Package: abstract
AbstractAbstract is a Python library for creating and drawing graphs
and taking advantage of graph properties.InstallationpipinstallabstractGraphIntroductionIn computer science, a graph is an abstract data type that
is meant to implement the undirected graph and directed graph
concepts from mathematics; specifically, the field of graph theory.[1]A graph data structure consists of a finite (and possibly mutable)
set of vertices or nodes or points, together with a set of
unordered pairs of these vertices for an undirected graph or
a set of ordered pairs for a directed graph. These pairs are known
as edges, arcs, or lines for an undirected graph and as arrows,
directed edges, directed arcs, or directed lines for a directed graph.
The vertices may be part of the graph structure, or may be external
entities represented by integer indices or references.[1]UsageTheGraphclass allows you to create nodes and edges and
visualize the resulting graph. Edges can have direction which
indicates parent-child relationship.To construct a new graph, useGraph().fromabstractimportGraphgraph=Graph(direction='LR')# default direction is 'LR', other options are: 'TB', 'BT', 'RL'add_node(...)Theadd_nodemethod creates a node in the graph
and returns aNodeobject.It takes the following arguments:name: name of the new node (should be unique); snake case is recommendedlabel(optional): it can be any string, if it is missing the name will be displayedvalue(optional): can be any objectstyle(optional): it should be aNodeStyleobject and is only used for renderingif_node_exists(optional): what to do if a node with this name exists
and can be 'warn', 'error', or 'ignore'; default is 'warn'Let's use theRock, Paper, Scissors, Lizard, Spockgame to show howGraphworks. The following list shows the order in which
an object in the game beats the object to its right of it in the list and
gets beaten by the object left of it. Please note that there are only five
objects and they are repeated to illustrate all possible pairs.node_list=['scissors','paper','rock','lizard','Spock','scissors','lizard','paper','Spock','rock','scissors']Now let's createnodeswith the same names:# create a set to avoid duplicatesfornodeinset(node_list):node=graph.add_node(name=node)graph.display(direction='TB')# left-right direction is too tallNote: by default, Graph uses colour theme from thecolourationlibrary for roots and uses
the directionality of edges to determine the colour of other nodes.
In the above example, without any edges, all nodes are roots.connect(...)(add an edge)Theconnectmethod creates anedgefrom astartnode to anendnode.
Thestartandendarguments can be either names of nodes or theNodeobjects.foriinrange(len(node_list)-1):edge=graph.connect(start=node_list[i],end=node_list[i+1])graph.display(direction='LR')# top-bottom direction is too tallNote: nodes that form a loop are coloured differently
(red circles with yellow colour inside)get_nodeTo retrieve a node from the graph you can use theget_nodemethod
which returns aNodeobject.rock=graph.get_node('rock')display(...)Thedisplaymethod visualizes the graph and if apathis provided it saves it
to an image file that can be apdforpng;
you can also provide the resolution with thedpiargument.
The file format is infered from
thepathargument.# save as a png file and view the filegraph.draw(path='my_graph.png',view=True)Graph(obj=...)You can create a graph from any object that has a__graph__()method.
Examples of such objects are:Graphclass from this libraryPensieveclass from thepensievelibraryPageclass frominternet.wikipediasubmodulefrompensieveimportPensievefromabstractimportGraphpensieve=Pensieve()pensieve['two']=2pensieve['three']=3pensieve['four']=lambdatwo:two*twopensieve['five']=5pensieve['six']=lambdatwo,three:two*threepensieve['seven']=7pensieve['eight']=lambdatwo,four:two*fourpensieve['nine']=lambdathree:three*threepensieve['ten']=lambdatwo,five:two*fivegraph=Graph(obj=pensieve,direction='TB')# or Graph(pensieve)graph.display()random(...)Therandommethod creates a random Graph.g1=Graph.random(num_nodes=8,connection_probability=0.4,seed=6)g1Adding Two Graphs:+You can easily add two graphs using the+operator.
The result will have the union of nodes and edges in both graphs.g2=Graph.random(num_nodes=7,start_index=3,connection_probability=0.4,seed=41)g2g3=g1+g2g3Finding LoopsThenode'sis_in_loopmethod helps you find nodes that form a loop;i.e., nodes that have at least one descendant which is also an ancestor.graph_with_loop=Graph()forletterin'abcdef':graph_with_loop.add_node(letter)forstart,endin[('a','b'),('b','c'),('c','a'),('c','d'),('d','e'),('e','f'),('f','e')]:graph_with_loop.connect(start,end)graph_with_loopfornodeingraph_with_loop.nodes:ifnode.is_in_loop_with(other='a')andnode.name!='a':print(node.name,'is in the same loop as a')elifnode.is_in_loop():print(node.name,'is in a loop')else:print(node.name,'is not in a loop')output:a is in a loop
b is in the same loop as a
c is in the same loop as a
d is not in a loop
e is in a loop
f is in a loopFuture FeaturesCreate a graph from:list of dictionariesdataframeCreate a new graph by filtering a graph