Ask Your Question

# Revision history [back]

One way to do this would be to modify the original tree function to parse the list; another would be to build the graph directly. The second one is slightly trickier because the names of graph vertices must be unique, so you have to ensure this with some kind of global counter. Here's one version I made by writing a class to contain both the counter, the graph, and the recursive tree builder:

class ExpressionGraph():
def __init__(self,expr):
self.G = Graph()
self.i = 0
print self.i
print "(init)"
self.expr = expr
self.graph_expr(self.expr)
def graph_expr(self,expr):
if expr.operator() is None:
name = "[{0}] {1}".format(self.i,expr)
self.i += 1
print self.i
print "(leaf) "+str(expr)
self.G.add_vertex(name)
return name
else:
name = "[{0}] {1}".format(self.i,expr.operator().__name__)
self.i += 1
print self.i
print "(node) "+str(expr)
new_nodes = []
for opnd in expr.operands():
new_nodes += [self.graph_expr(opnd)]
self.G.add_vertex(name)
self.G.add_edges([(name,node) for node in new_nodes])
return name


Note that I've included some print statements so you can see how it's working:

f = x^2 + 3*x + 5
E1 = ExpressionGraph(f)


prints out

0
(init)
1
(node) x^2 + 3*x + 5
2
(node) x^2
3
(leaf) x
4
(leaf) 2
5
(node) 3*x
6
(leaf) x
7
(leaf) 3
8
(leaf) 5


and E.G.show() plots the tree:

One way to do this would be to modify the original tree function to parse the list; another would be to build the graph directly. The second one is slightly trickier because the names of graph vertices must be unique, so you have to ensure this with some kind of global counter. Here's one version I made by writing a class to contain both the counter, the graph, and the recursive tree builder:

class ExpressionGraph():
def __init__(self,expr):
self.G = Graph()
self.i = 0
self.expr = expr
self.root = None
self.graph_expr(self.expr)
def plot(self,*args,**kwds):
#print "root is {0}".format(self.root)
return self.G.plot(*args,layout='tree',tree_root=self.root,**kwds)
def graph_expr(self,expr):
try:
operator = expr.operator()
except AttributeError: # e.g. if expr is an integer
operator = None

if operator is None:
name = "[{0}] {1}".format(self.i,expr)
print self.i
print "(init)"
self.expr = expr
self.graph_expr(self.expr)
def graph_expr(self,expr):
if expr.operator() is None:
name = "[{0}] {1}".format(self.i,expr)
"(leaf) {0}".format(expr)
self.i += 1
self.G.add_vertex(name)
return name
else:
name = "[{0}] {1}".format(self.i,expr.operator().__name__)
print self.i
print "(leaf) "+str(expr)
self.G.add_vertex(name)
return "(node) {0}; {1}".format(expr,expr.operator().__name__)
if self.i == 0:
self.root = name
else:
name = "[{0}] {1}".format(self.i,expr.operator().__name__)
print "  ** root is '{0}' **".format(self.root)
self.i += 1
print self.i
print "(node) "+str(expr)
new_nodes = []
for opnd in expr.operands():
new_nodes += [self.graph_expr(opnd)]
self.G.add_vertex(name)
self.G.add_edges([(name,node) for node in new_nodes])
return name


Note that I've included some print statements so you can see how it's working:

f = x^2 + 3*x + 5
E1 2*(x+2^x)
E = ExpressionGraph(f)


prints out

0
(init)
(node) 2*2^x + 2*x; add
** root is '[0] add' **
1
(node) x^2 + 3*x + 5
2*2^x; mul
2
(node) x^2
2^x; pow
3
(leaf) x
2
4
(leaf) x
5
(leaf) 2
5
6
(node) 3*x
6
2*x; mul
7
(leaf) x
7
(leaf) 3
8
(leaf) 5
2


and E.G.show()E.plot() plots the tree:tree, with additional arguments passed to the underlying graph. For example:

E.plot(vertex_size=2000,vertex_colors='#ffccff')