def dotprint(expr, styles=default_styles, atom=(lambda x: (not isinstance(x, Basic))), maxdepth=None, repeat=True, labelfunc=str, **kwargs):
 graphstyle.update(kwargs)
 nodes = []
 edges = []
 def traverse(e, depth, pos=()):
  nodes.append(dotnode(e, styles, labelfunc=labelfunc, pos=pos, repeat=repeat))
  if (maxdepth and (depth >= maxdepth)):
   return
  edges.extend(dotedges(e, atom=atom, pos=pos, repeat=repeat))
  [traverse(arg, (depth + 1), (pos + (i,))) for (i, arg) in enumerate(e.args) if (not atom(arg))]
 traverse(expr, 0)
 return (template % {'graphstyle': attrprint(graphstyle, delimiter='\n'), 'nodes': '\n'.join(nodes), 'edges': '\n'.join(edges)})

def dotprint ( expr , styles = default_styles , atom = ( lambda x : ( not isinstance ( x , Basic ) ) ) , maxdepth = None , repeat = True , labelfunc = str , ** kwargs ) : graphstyle . update ( kwargs ) nodes = [ ] edges = [ ] def traverse ( e , depth , pos = ( ) ) : nodes . append ( dotnode ( e , styles , labelfunc = labelfunc , pos = pos , repeat = repeat ) ) if ( maxdepth and ( depth >= maxdepth ) ) : return edges . extend ( dotedges ( e , atom = atom , pos = pos , repeat = repeat ) ) [ traverse ( arg , ( depth + 1 ) , ( pos + ( i , ) ) ) for ( i , arg ) in enumerate ( e . args ) if ( not atom ( arg ) ) ] traverse ( expr , 0 ) return ( template % { 'graphstyle' : attrprint ( graphstyle , delimiter = '\n' ) , 'nodes' : '\n' . join ( nodes ) , 'edges' : '\n' . join ( edges ) } )
dot description of a sympy expression tree options are styles: styles for different classes .