PhyNetPy is a network first library, as there is no separate tree class that is required to be void of reticulations or hybridizations. Every network or tree is represented the same way, as a directed acyclic graph (the DAG class).


To create a network is very easy and straightforward:

                        from PhyNetPy.Graph import DAG

                        #Can initialize as an empty graph
                        tree = DAG()

                        #To make it a network, simply add in individual nodes
                        #one at a time, or pass in an array of nodes
                        tree.addNodes(individualNodeObj)
                        tree.addNodes(arrayOfNodeObjs)

                        #same applies to adding edges
                        tree.addEdges(individualEdge)
                        tree.addEdges(arrayOfEdges) #Where an edge can just be [NodeObj, NodeObj2]

                        #Now you have a complete network. To grab the newick representation...
                        newickStr = tree.newickString() 

                        #You can now visualize your graph with IcyTree
                        
                        #You can also initialize trees with node and edge lists 
                        tree2 = DAG(edgeList) #add nodes later
                        tree3 = DAG(nodes = nodeList) #add edges later
                        tree4 = DAG(edgeList, nodeList) #add both now


                        #To see a description of all the nodes in your graph:
                        tree.printGraph()

                

A Node object has the following initialization parameters, all of which are defaults:

  1. branchLen = None
  2. parNode = [ ]
  3. attr = { }
  4. isReticulation = False
  5. name = None
                        from PhyNetPy.Node import Node

                        #Can initialize as an empty Node
                        new_node = Node()

                        #To set the branch length
                        new_node.setBranchLength(num)
                        
                        #To get the branch length
                        node_len = new_node.branchLen()

                        #To add a parent (must be a Node or UltrametricNode obj)
                        new_node.addParent(par_node)

                        #or to set the parent
                        new_node.setParent(par_node)

                        #To set the name of a Node
                        new_node.setName("Homo Sapiens")

                        #To get the name of the Node
                        node_name = new_node.getName()

                        #To set a custom attribute
                        new_node.setAttribute(attribute, value) #i.e "t" : 5.4
                
                        #To look up an attribute
                        attr_val = new_node.attrLookup(attribute) #i.e "t" returns 5.4

                        #To visualize the values contained in a Node obj 
                        new_node.asString()

                        #A more typical way to create a Node
                        new_node2 = Node(parNode = [par_node], attr = {"t":5.4}, name = "species2")