343
321
didx, cmd = doText(c, s[idx+1:])
344
322
cmdlist.append(cmd)
350
328
return cmdlist,stat
354
def getGraphList(gg, l = []):
332
def get_graphlist(gg, l = []):
355
333
"""Traverse a graph with subgraphs and return them as a list"""
362
for g in gg.subgraph_list:
339
if gg.get_subgraphs():
340
for g in gg.get_subgraphs():
364
342
if outer: return l
366
class EndOfGraphElement:
344
class EndOfGraphElement(object):
367
345
def __init__(self):
370
def getAllGraphElements(graph, l=[]):
348
def get_all_graph_elements(graph, l=[]):
371
349
"""Return all nodes and edges, including elements in subgraphs"""
377
for element in graph.sorted_graph_elements:
378
if isinstance(element, pydot.Node):
380
elif isinstance(element,pydot.Edge):
382
elif isinstance(element, pydot.Graph):
384
getAllGraphElements(element,l)
355
for element in graph.allitems:
356
if isinstance(element, dotparsing.DotSubGraph):
358
get_all_graph_elements(element,l)
386
log.warning('Unknown graph element')
391
365
l.append(EndOfGraphElement())
368
class DotConvBase(object):
395
369
"""Dot2TeX converter base"""
396
370
def __init__(self, options = {}):
398
373
self.template = options.get('template','')
399
374
self.textencoding = options.get('encoding',DEFAULT_TEXTENCODING)
400
375
self.templatevars = {}
402
377
if options.get('templatefile',''):
403
self.loadTemplate(options['templatefile'])
378
self.load_template(options['templatefile'])
379
if options.get('template',''):
380
self.template = options['template']
405
382
self.options = options
406
383
if options.get('texpreproc',False) or options.get('autosize',False):
409
386
self.dopreproc = False
411
def loadTemplate(self, templatefile):
388
def load_template(self, templatefile):
413
390
self.template = open(templatefile).read()
417
def convertFile(self, filename):
394
def convert_file(self, filename):
418
395
"""Load dot file and convert"""
427
def drawEllipse(self, drawop, style = None):
430
def drawBezier(self, drawop, style = None):
433
def drawPolygon(self, drawop, style = None):
436
def drawPolyLine(self, drawop, style = None):
439
def drawText(self, drawop, style = None):
442
def outputNodeComment(self, node):
404
def draw_ellipse(self, drawop, style = None):
407
def draw_bezier(self, drawop, style = None):
410
def draw_polygon(self, drawop, style = None):
413
def draw_polyline(self, drawop, style = None):
416
def draw_text(self, drawop, style = None):
419
def output_node_comment(self, node):
443
420
return " %% Node: %s\n" % node.name
445
def outputEdgeComment(self, edge):
422
def output_edge_comment(self, edge):
446
423
src = edge.get_source()
447
424
dst = edge.get_destination()
448
425
if self.directedgraph:
452
429
return " %% Edge: %s %s %s\n" % (src, edge, dst)
454
def setColor(self, node):
457
def setStyle(self, node):
460
def drawEdge(self, edge):
463
def startNode(self, node):
465
def endNode(self,node):
467
def startGraph(self, graph):
469
def endGraph(self,graph):
478
def filterStyles(self, style):
431
def set_color(self, node):
434
def set_style(self, node):
437
def draw_edge(self, edge):
440
def start_node(self, node):
442
def end_node(self,node):
444
def start_graph(self, graph):
446
def end_graph(self,graph):
449
def start_edge(self):
455
def filter_styles(self, style):
481
def convertColor(self, drawopcolor,pgf=False):
458
def convert_color(self, drawopcolor,pgf=False):
482
459
"""Convert color to a format usable by LaTeX and XColor"""
483
460
# Graphviz uses the following color formats:
484
461
# "#%2x%2x%2x" Red-Green-Blue (RGB)
485
462
# "#%2x%2x%2x%2x" Red-Green-Blue-Alpha (RGBA)
486
463
# H[, ]+S[, ]+V Hue-Saturation-Value (HSV) 0.0 <= H,S,V <= 1.0
487
464
# string color name
489
466
# Is the format RBG(A)?
490
467
if drawopcolor.startswith('#'):
491
468
t = list(chunks(drawopcolor[1:],2))
594
571
self.options.get('valignmode','center')=='center':
595
572
# do this for single line only
596
573
# Todo: Make this optional
597
pos = getattr(drawobj,'lp',None) or \
598
getattr(drawobj,'pos',None)
574
pos = drawobj.attr.get('lp',None) or \
575
drawobj.attr.get('pos',None)
600
577
coord = pos.split(',')
601
578
if len(coord)==2:
602
579
drawop[1] = coord[0]
603
580
drawop[2] = coord[1]
605
lblstyle = getattr(drawobj,'lblstyle',None)
606
exstyle = getattr(drawobj,'exstyle','')
582
lblstyle = drawobj.attr.get('lblstyle',None)
583
exstyle = drawobj.attr.get('exstyle','')
609
586
lblstyle += ',' +exstyle
611
588
lblstyle = exstyle
612
s += self.drawText(drawop,lblstyle)
589
s += self.draw_text(drawop,lblstyle)
617
594
for node in self.nodes:
618
595
self.currentnode = node
619
dstring = getattr(node,'_draw_',"")
620
lstring = getattr(node,'_ldraw_',"")
596
dstring = node.attr.get('_draw_',"")
597
lstring = node.attr.get('_ldraw_',"")
623
600
drawstring = dstring+" "+lstring
625
602
if not drawstring.strip(): continue
626
603
# detect node type
604
shape = node.attr.get('shape','')
629
606
shape = 'ellipse' # default
630
607
# extract size information
631
x,y = node.pos.split(',')
608
x,y = node.attr.get('pos','').split(',')
633
610
# width and height are in inches. Convert to bp units
634
w = float(node.width)*in2bp
635
h = float(node.height)*in2bp
637
s += self.outputNodeComment(node)
638
s += self.startNode(node)
639
#drawoperations = parseDrawString(drawstring)
640
s += self.doDrawString(drawstring, node)
641
s += self.endNode(node)
611
w = float(node.attr['width'])*in2bp
612
h = float(node.attr['height'])*in2bp
614
s += self.output_node_comment(node)
615
s += self.start_node(node)
616
#drawoperations = parse_drawstring(drawstring)
617
s += self.do_drawstring(drawstring, node)
618
s += self.end_node(node)
644
def getEdgePoints(self, edge):
645
points = edge.pos.split(' ')
649
if points[i].startswith('s'):
650
p = points[0].split(',')
651
tmp = "%s,%s" % (p[1],p[2])
652
if points[1].startswith('e'):
659
if points[0].startswith('e'):
660
p = points[0].split(',')
662
points.append("%s,%s" % (p[1],p[2]))
666
if i>1: arrowstyle = '<->'
667
return arrowstyle, points
621
def get_edge_points(self, edge):
623
# <edge> :: <spline> (';' <spline>)*
624
# <spline> :: <endp>? <startp>? <point> <triple>+
625
# <point> :: <x> ',' <y>
626
# <triple> :: <point> <point> <point>
627
# <endp> :: "e" "," <x> "," <y>
628
## spline ( ';' spline )*
629
##where spline = (endp)? (startp)? point (triple)+
630
##and triple = point point point
631
##and endp = "e,%d,%d"
632
##and startp = "s,%d,%d"
633
##If a spline has points p1 p2 p3 ... pn, (n = 1 (mod 3)), the points correspond to the control points of a B-spline from p1 to pn. If startp is given, it touches one node of the edge, and the arrowhead goes from p1 to startp. If startp is not given, p1 touches a node. Similarly for pn and endp.
634
pos = edge.attr.get('pos')
635
segments = pos.split(';')
639
points = pos.split(' ')
643
if points[i].startswith('s'):
644
p = points[0].split(',')
645
tmp = "%s,%s" % (p[1],p[2])
646
if points[1].startswith('e'):
653
if points[0].startswith('e'):
654
p = points[0].split(',')
656
points.append("%s,%s" % (p[1],p[2]))
660
if i>1: arrowstyle = '<->'
661
segret.append((arrowstyle,points))
671
s += self.setColor(('cC',"black"))
667
s += self.set_color(('cC',"black"))
672
668
for edge in self.edges:
673
dstring = getattr(edge,'_draw_',"")
674
lstring = getattr(edge,'_ldraw_',"")
675
hstring = getattr(edge,'_hdraw_',"")
676
tstring = getattr(edge,'_tdraw_',"")
677
tlstring = getattr(edge,'_tldraw_',"")
678
hlstring = getattr(edge,'_hldraw_',"")
669
dstring = edge.attr.get('_draw_',"")
670
lstring = edge.attr.get('_ldraw_',"")
671
hstring = edge.attr.get('_hdraw_',"")
672
tstring = edge.attr.get('_tdraw_',"")
673
tlstring = edge.attr.get('_tldraw_',"")
674
hlstring = edge.attr.get('_hldraw_',"")
680
676
# Note that the order of the draw strings should be the same
681
677
# as in the xdot output.
682
678
drawstring = dstring + " " + hstring + " " + tstring \
683
679
+ " " + lstring + " " + tlstring + " " + hlstring
684
drawop,stat = parseDrawString(drawstring);
680
drawop,stat = parse_drawstring(drawstring);
685
681
if not drawstring.strip():
687
s += self.outputEdgeComment(edge)
683
s += self.output_edge_comment(edge)
688
684
if self.options.get('duplicate', False):
689
s += self.startEdge()
690
s += self.doDrawOp(drawop, edge,stat)
685
s += self.start_edge()
686
s += self.do_draw_op(drawop, edge,stat)
693
s += self.drawEdge(edge)
694
s += self.doDrawString(lstring+" "+tlstring+" "+hlstring, edge)
689
s += self.draw_edge(edge)
690
s += self.do_drawstring(lstring+" "+tlstring+" "+hlstring, edge)
698
dstring = getattr(self.graph,'_draw_',"")
699
lstring = getattr(self.graph,'_ldraw_',"")
694
dstring = self.graph.attr.get('_draw_',"")
695
lstring = self.graph.attr.get('_ldraw_',"")
701
697
# Avoid filling background of graphs with white
702
698
if dstring.startswith('c 5 -white C 5 -white') \
703
and not getattr(self.graph,'style'):
699
and not self.graph.attr.get('style'):
705
701
if getattr(self.graph,'_draw_',None):
707
703
dstring = "c 5 -black " + dstring #self.graph._draw_
709
705
drawstring = dstring+" "+lstring
710
if drawstring.strip():
711
s = self.startGraph(self.graph)
712
g = self.doDrawString(drawstring, self.graph)
713
e = self.endGraph(self.graph)
706
if drawstring.strip():
707
s = self.start_graph(self.graph)
708
g = self.do_drawstring(drawstring, self.graph)
709
e = self.end_graph(self.graph)
715
711
self.body += s +g + e
717
def setOptions(self):
713
def set_options(self):
718
714
# process options
719
715
# Warning! If graph attribute is true and command line option is false,
720
716
# the graph attribute will be used. Command line option should have
752
749
# need to convert to xdot format
753
750
# Warning. Pydot will not include custom attributes
754
751
log.debug('Trying to create xdotdata')
756
tmpdata = createXdot(dotdata,self.options.get('prog','dot'))
753
tmpdata = create_xdot(dotdata,self.options.get('prog','dot'))
757
754
log.debug('xdotdata:\n'+tmpdata)
758
755
if tmpdata == None or not tmpdata.strip():
759
756
log.error('Failed to create xdotdata. Is Graphviz installed?')
761
maingraph = parseDotData(tmpdata)
758
maingraph = parse_dot_data(tmpdata)
759
log.debug('dotparsing graph:\n'+str(maingraph))
766
764
self.maingraph = maingraph
767
765
self.pencolor = ""
768
766
self.fillcolor = ""
769
767
self.linewidth = 1
770
768
# Detect graph type
771
if maingraph.graph_type == 'digraph':
772
self.directedgraph = True
774
self.directedgraph = False
769
self.directedgraph = maingraph.directed
776
772
log.error(helpmsg)
779
776
if self.dopreproc:
780
return self.doPreviewPreproc()
777
return self.do_preview_preproc()
782
779
# Romove annoying square
783
780
# Todo: Remove squares from subgraphs. See pgram.dot
784
dstring = getattr(self.maingraph,'_draw_',"")
781
dstring = self.maingraph.attr.get('_draw_',"")
786
self.maingraph._draw_ = ""
788
setDotAttr(self.maingraph)
783
self.maingraph.attr['_draw_'] = ""
785
#setDotAttr(self.maingraph)
791
788
# A graph can consists of nested graph. Extract all graphs
792
graphlist = getGraphList(self.maingraph, [])
794
self.body += self.startFig()
789
graphlist = get_graphlist(self.maingraph, [])
791
self.body += self.start_fig()
796
793
# To get correct drawing order we need to iterate over the graphs
797
794
# multiple times. First we draw the graph graphics, then nodes and
800
797
# todo: support the outputorder attribute
801
798
for graph in graphlist:
802
799
self.graph = graph
805
if not self.options.get('flattengraph',False):
806
for graph in graphlist:
808
self.nodes = cleanDotNodes(graph)
809
self.edges = graph.edge_list
810
if not self.options.get('switchdraworder',False):
819
for graph in graphlist:
821
nodelist.extend(cleanDotNodes(graph))
822
edgelist.extend(graph.edge_list)
823
self.nodes = nodelist
824
self.edges = edgelist
802
## if not self.options.get('flattengraph',False):
803
## for graph in graphlist:
804
## self.graph = graph
805
## self.nodes = clean_dot_nodes(graph)
806
## self.edges = graph.edge_list
807
## if not self.options.get('switchdraworder',False):
808
## self.do_edges() # tmp
817
## for graph in graphlist:
818
## self.graph = graph
819
## nodelist.extend(clean_dot_nodes(graph))
820
## edgelist.extend(graph.edge_list)
821
self.nodes = maingraph.allnodes
822
self.edges = maingraph.alledges
825
823
if not self.options.get('switchdraworder',False):
824
self.do_edges() # tmp
832
self.body += self.endFig()
830
self.body += self.end_fig()
833
831
return self.output()
835
def cleanTemplate(self, template):
833
def clean_template(self, template):
836
834
"""Remove preprocsection or outputsection"""
837
835
if not self.dopreproc and self.options.get('codeonly',False):
838
836
r = re.compile('<<startcodeonlysection>>(.*?)<<endcodeonlysection>>',
897
895
vars['<<gvcols>>'] = ""
898
896
self.templatevars = vars
900
898
def output(self):
901
self.initTemplateVars()
902
template = self.cleanTemplate(self.template)
903
code = replaceTags(template ,self.templatevars.keys(),
899
self.init_template_vars()
900
template = self.clean_template(self.template)
901
code = replace_tags(template ,self.templatevars.keys(),
904
902
self.templatevars)
905
903
#code = self.template.replace('<<figcode>>', self.body)
908
def getLabel(self, drawobj):
906
def get_label(self, drawobj):
910
908
texmode = self.options.get('texmode','verbatim')
911
909
if getattr(drawobj,'texmode', ''):
912
910
texmode = drawobj.texmode
913
911
text = getattr(drawobj,'label',None)
915
913
#log.warning('text %s %s',text,drawobj.to_string())
917
915
if text == None or text.strip() == '\N':
919
if not isinstance(drawobj, pydot.Edge):
917
if not isinstance(drawobj, dotparsing.DotEdge):
920
918
text = getattr(drawobj,'name',None) or \
921
919
getattr(drawobj,'graph_name','')
920
text = text.replace("\\\\","\\")
924
923
elif text.strip() == '\N':
927
926
text = text.replace("\\\\","\\")
929
928
if getattr(drawobj,'texlbl', ''):
930
929
# the texlbl overrides everything
931
930
text = drawobj.texlbl
932
931
elif texmode == 'verbatim':
934
text = escapeTeXChars(text)
933
text = escape_texchars(text)
936
935
elif texmode == 'math':
938
937
text = "$%s$" % text
943
def getLabeld(self, drawobj):
942
def get_labeld(self, drawobj):
945
944
texmode = self.options.get('texmode','verbatim')
946
945
if drawobj.get('texmode', ''):
999
997
# Todo: Add support for head and tail labels!
1000
998
# Todo: Support rect nodes if possible.
1001
def doPreviewPreproc(self):
1002
setDotAttr(self.maingraph)
1003
self.initTemplateVars()
1004
template = self.cleanTemplate(self.template)
1005
template = replaceTags(template ,self.templatevars.keys(),
999
def do_preview_preproc(self):
1000
#setDotAttr(self.maingraph)
1001
self.init_template_vars()
1002
template = self.clean_template(self.template)
1003
template = replace_tags(template ,self.templatevars.keys(),
1006
1004
self.templatevars)
1007
1005
pp = TeXDimProc(template, self.options)
1008
1006
processednodes = {}
1009
1007
processededges = {}
1010
1008
processedgraphs = {}
1014
1012
usedgraphs = {}
1015
1013
# iterate over every element in the graph
1017
for element in getAllGraphElements(self.maingraph,[]):
1018
if isinstance(element, pydot.Node):
1019
# is it a node statement?
1021
if node.name.startswith('"'):
1024
# node defined in a edge statement (edge_stmt)
1026
name = node.name.replace('"','')
1030
if name=='node' or name=='edge' or name=='graph': continue
1032
label = self.getLabel(node)
1033
tmpnode = processednodes.get(name,None)
1036
# has the node been defined before?
1039
## # is it a new label?
1040
## if node.label or node.texlbl:
1041
## #if tmpnode['texlbl'] <> label and node_stmt:
1042
## tmpnode['texlbl'] = label
1044
tmpnode = dict(texlbl=None, width=None, height=None,
1045
margin=None, style=None, fixedsize=None,
1046
shape=None, texmode=None,label=None,
1048
processednodes[name]= tmpnode
1050
tmpnode['width'] = node.width
1052
tmpnode['height'] = node.height
1054
tmpnode['margin'] = node.margin
1056
tmpnode['style'] = node.style
1058
tmpnode['texmode'] = node.texmode
1059
if node.label or node.label=='':
1060
tmpnode['label'] = node.label
1062
tmpnode['texlbl'] = node.texlbl
1064
tmpnode['lblstyle'] = node.lblstyle
1066
tmpnode['shape'] = node.shape
1068
tmpnode['fixedsize'] = node.fixedsize.lower()
1069
#log.debug('nodeinfo %s %s',name, node.fixedsize)
1071
tmpnode['shape'] = node.shape
1072
elif isinstance(element, pydot.Edge):
1073
if not element.label: continue
1074
# Ensure that the edge name is unique.
1075
name = element.src + element.dst +str(counter)
1076
label = self.getLabel(element)
1077
element.texlbl = label
1078
processededges[name]=element
1079
elif isinstance(element, pydot.Graph):
1080
if not getattr(element,'label',None) and \
1081
not getattr(element,'texlbl',None): continue
1082
name = element.graph_name
1083
label = self.getLabel(element)
1084
element.texlbl = label
1085
processedgraphs[name]=element
1091
for name, item in processednodes.items():
1092
if item['fixedsize'] == 'true' or item['style'] == 'invis':
1094
if item['shape'] == 'record':
1016
## elif isinstance(element, dotparsing.DotSubGraph):
1017
## if not getattr(element,'label',None) and \
1018
## not getattr(element,'texlbl',None): continue
1019
## name = element.graph_name
1020
## label = self.get_label(element)
1021
## element.texlbl = label
1022
## processedgraphs[name]=element
1028
for node in self.maingraph.allnodes:
1030
if node.attr.get('fixedsize','') == 'true' \
1031
or node.attr.get('style','') in ['invis','invisible']:
1033
if node.attr.get('shape','') == 'record':
1095
1034
log.warning('Record nodes not supported in preprocessing mode: %s',name)
1098
texlbl = self.getLabeld(item)
1036
texlbl = self.get_label(node)
1100
item['texlbl'] = texlbl
1101
code = self.getNodePreprocCode(item)
1102
pp.addSnippet(name,code)
1103
#log.warning(item['texlbl'])
1104
usednodes[name] = item
1105
for name, item in processededges.items():
1106
code = self.getEdgePreprocCode(item)
1107
pp.addSnippet(name,code)
1108
usededges[name] = item
1109
for name, item in processedgraphs.items():
1110
code = self.getGraphPreprocCode(item)
1111
pp.addSnippet(name,code)
1112
usedgraphs[name] = item
1039
node.attr['texlbl'] = texlbl
1040
code = self.get_node_preproc_code(node)
1041
pp.add_snippet(name,code)
1044
usednodes[name] = node
1045
for edge in dotparsing.flatten(self.maingraph.alledges):
1046
if not edge.attr.get('label'): continue
1047
# Ensure that the edge name is unique.
1048
name = edge.src.name + edge.dst.name +str(counter)
1049
label = self.get_label(edge)
1050
edge.attr['texlbl'] = label
1051
code = self.get_edge_preproc_code(edge)
1052
pp.add_snippet(name,code)
1053
usededges[name] = edge
1056
for graph in self.maingraph.allgraphs:
1057
if not graph.attr.get('label',None) and \
1058
not graph.attr.get('texlbl',None): continue
1059
# Make sure that the name is unique
1060
name = graph.name + str(counter)
1063
label = self.get_label(graph)
1064
graph.attr['texlbl'] = label
1065
code = self.get_graph_preproc_code(graph)
1066
pp.add_snippet(name,code)
1067
usedgraphs[name] = graph
1115
1069
ok = pp.process()
1118
1072
errormsg = """\
1119
1073
Failed to preprocess the graph.
1171
node.height = height
1174
node.fixedsize='true'
1175
self.maingraph.add_node(node)
1124
node.attr['width'] = width
1125
node.attr['height'] = height
1126
node.attr['label'] = " "
1128
node.attr['fixedsize']='true'
1129
self.maingraph.allitems.append(node)
1176
1131
for name,item in usededges.items():
1179
1134
hp,dp,wt = pp.texdims[name]
1180
xmargin, ymargin = self.getMargins(edge)
1135
xmargin, ymargin = self.get_margins(edge)
1181
1136
labelcode = '<<<table border="0" cellborder="0" cellpadding="0">'\
1182
1137
'<tr><td fixedsize="true" width="%s" height="%s">a</td>'\
1183
1138
'</tr></table>>>'
1184
edge.label=labelcode % ((wt + 2*xmargin)*72, (hp+dp+2*ymargin)*72)
1139
edge.attr['label']=labelcode % ((wt + 2*xmargin)*72, (hp+dp+2*ymargin)*72)
1140
#self.maingraph.allitems.append(edge)
1185
1141
for name,item in usedgraphs.items():
1187
1143
hp,dp,wt = pp.texdims[name]
1188
xmargin, ymargin = self.getMargins(graph)
1144
xmargin, ymargin = self.get_margins(graph)
1189
1145
labelcode = '<<<table border="0" cellborder="0" cellpadding="0">'\
1190
1146
'<tr><td fixedsize="true" width="%s" height="%s">a</td>'\
1191
1147
'</tr></table>>>'
1192
graph.label=labelcode % ((wt + 2*xmargin)*72, (hp+dp+2*ymargin)*72)
1194
self.maingraph.d2toutputformat = self.options.get('format',
1148
graph.attr['label']=labelcode % ((wt + 2*xmargin)*72, (hp+dp+2*ymargin)*72)
1151
self.maingraph.attr['d2toutputformat'] = self.options.get('format',
1195
1152
DEFAULT_OUTPUT_FORMAT)
1196
graphcode = self.maingraph.to_string()
1197
graphcode = graphcode.replace('"<<<','<<')
1198
graphcode = graphcode.replace('>>>"','>>')
1153
graphcode = str(self.maingraph)
1154
graphcode = graphcode.replace('<<<','<<')
1155
graphcode = graphcode.replace('>>>','>>')
1199
1156
return graphcode
1204
1161
PSTRICKS_TEMPLATE = r"""\documentclass{article}
1386
1343
self.fillcolor = color
1387
1344
s = " \psset{fillcolor=%s}\n" % color
1388
1345
else: return ""
1347
if self.color <> color:
1349
self.pencolor = self.fillcolor = color;
1350
s = " \psset{linecolor=%s}\n" % (color);
1352
log.warning('Unhandled color: %s',drawop)
1391
def setStyle(self, drawop):
1355
def set_style(self, drawop):
1392
1356
c, style = drawop
1393
1357
psstyle = self.styles.get(style,"")
1395
1359
return " \psset{%s}\n" % psstyle
1399
def filterStyles(self, style):
1363
def filter_styles(self, style):
1401
1365
for item in style.split(','):
1402
1366
keyval = item.strip()
1403
1367
if keyval.find('setlinewidth') < 0:
1404
1368
fstyles.append(keyval)
1405
1369
return ', '.join(fstyles)
1407
def startNode(self, node):
1371
def start_node(self, node):
1408
1372
self.pencolor = "";
1409
1373
self.fillcolor = ""
1410
1374
self.color = ""
1413
def endNode(self,node):
1377
def end_node(self,node):
1416
def startEdge(self):
1380
def start_edge(self):
1417
1381
self.pencolor = "";
1418
1382
self.fillcolor = ""
1424
def startGraph(self, graph):
1388
def start_graph(self, graph):
1425
1389
self.pencolor = "";
1426
1390
self.fillcolor = ""
1427
1391
self.color = ""
1430
def endGraph(self,node):
1394
def end_graph(self,node):
1434
def drawEllipseNode(self, x,y,w,h,node):
1435
s = " %% Node: %s\n" % node.name
1436
s += " \psellipse(%sbp,%sbp)(%sbp,%sbp)\n" % (x,y, \
1437
w/2+self.linewidth,h/2+self.linewidth)
1443
s += " \\rput(%sbp,%sbp){$%s$}\n" % (x,y,label)
1449
def drawEdge(self, edge):
1398
## def draw_ellipseNode(self, x,y,w,h,node):
1399
## s = " %% Node: %s\n" % node.name
1400
## s += " \psellipse(%sbp,%sbp)(%sbp,%sbp)\n" % (x,y, \
1401
## w/2+self.linewidth,h/2+self.linewidth)
1404
## label = node.label
1406
## label = node.name
1407
## s += " \\rput(%sbp,%sbp){$%s$}\n" % (x,y,label)
1413
def draw_edge(self, edge):
1451
if edge.style == 'invis':
1415
if edge.attr.get('style','') in ['invis','invisible']:
1453
arrowstyle, points = self.getEdgePoints(edge)
1454
if arrowstyle == '--': arrowstyle=''
1455
color = getattr(edge,'color','')
1456
if self.color <> color:
1458
s += self.setColor(('c',color))
1460
# reset to default color
1461
s += self.setColor(('c','black'))
1463
for point in points:
1464
p = point.split(',')
1465
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
1417
edges = self.get_edge_points(edge)
1418
for arrowstyle, points in edges:
1419
if arrowstyle == '--': arrowstyle=''
1420
color = getattr(edge,'color','')
1421
if self.color <> color:
1423
s += self.set_color(('c',color))
1425
# reset to default color
1426
s += self.set_color(('c','black'))
1428
for point in points:
1429
p = point.split(',')
1430
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
1467
edgestyle = edge.style
1470
styles.append('arrows=%s' % arrowstyle)
1472
edgestyles = [self.styles.get(key.strip(),key.strip()) for key in edgestyle.split(',') if key]
1473
styles.extend(edgestyles)
1475
stylestr = ",".join(styles)
1478
if not self.options.get('straightedges',False):
1479
s += " \psbezier[%s]%s\n" % (stylestr,"".join(pp))
1481
s += " \psline[%s]%s%s\n" % (stylestr, pp[0], pp[-1])
1482
#s += " \psbezier[%s]{%s}%s\n" % (stylestr, arrowstyle,"".join(pp))
1484
## x,y = edge.lp.split(',')
1485
## #s += "\\rput(%s,%s){%s}\n" % (x,y,edge.label)
1432
edgestyle = edge.attr.get('style','')
1435
styles.append('arrows=%s' % arrowstyle)
1437
edgestyles = [self.styles.get(key.strip(),key.strip()) \
1438
for key in edgestyle.split(',') if key]
1439
styles.extend(edgestyles)
1441
stylestr = ",".join(styles)
1444
if not self.options.get('straightedges',False):
1445
s += " \psbezier[%s]%s\n" % (stylestr,"".join(pp))
1447
s += " \psline[%s]%s%s\n" % (stylestr, pp[0], pp[-1])
1448
#s += " \psbezier[%s]{%s}%s\n" % (stylestr, arrowstyle,"".join(pp))
1450
## x,y = edge.lp.split(',')
1451
## #s += "\\rput(%s,%s){%s}\n" % (x,y,edge.label)
1488
def initTemplateVars(self):
1489
DotConvBase.initTemplateVars(self)
1454
def init_template_vars(self):
1455
DotConvBase.init_template_vars(self)
1490
1456
# Put a ',' before <<graphstyle>>
1491
1457
graphstyle = self.templatevars.get('<<graphstyle>>','')
1798
1764
# as in the xdot output.
1799
1765
drawstring = dstring + " " + hstring + " " + tstring \
1800
1766
+ " " + lstring + " " + tlstring + " " + hlstring
1801
drawop,stat = parseDrawString(drawstring);
1767
drawop,stat = parse_drawstring(drawstring);
1802
1768
if not drawstring.strip():
1804
s += self.outputEdgeComment(edge)
1770
s += self.output_edge_comment(edge)
1805
1771
if self.options.get('duplicate', False):
1806
s += self.startEdge()
1807
s += self.doDrawOp(drawop, edge,stat)
1772
s += self.start_edge()
1773
s += self.do_draw_op(drawop, edge,stat)
1774
s += self.end_edge()
1810
1776
topath = getattr(edge,'topath',None)
1811
s += self.drawEdge(edge)
1777
s += self.draw_edge(edge)
1812
1778
if not self.options.get('tikzedgelabels',False) and not topath:
1813
s += self.doDrawString(lstring+" "+tlstring+" "+hlstring, edge)
1779
s += self.do_drawstring(lstring+" "+tlstring+" "+hlstring, edge)
1815
s += self.doDrawString(tlstring+" "+hlstring, edge)
1816
#s += self.drawEdge(edge)
1817
#s += self.doDrawString(lstring+" "+tlstring+" "+hlstring, edge)
1781
s += self.do_drawstring(tlstring+" "+hlstring, edge)
1782
#s += self.draw_edge(edge)
1783
#s += self.do_drawstring(lstring+" "+tlstring+" "+hlstring, edge)
1821
def drawEdge(self, edge):
1787
def draw_edge(self, edge):
1823
if edge.style == 'invis':
1789
if edge.attr.get('style','') in ['invis','invisible']:
1825
arrowstyle, points = self.getEdgePoints(edge)
1826
# PGF uses the fill style when drawing some arrowheads. We have to
1827
# ensure that the fill color is the same as the pen color.
1828
color = getattr(edge,'color','')
1830
if self.color <> color:
1832
s += self.setColor(('cC',color))
1834
# reset to default color
1835
s += self.setColor(('cC','black'))
1838
for point in points:
1839
p = point.split(',')
1840
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
1842
edgestyle = edge.style
1845
if arrowstyle <> '--':
1846
#styles.append(arrowstyle)
1847
styles = [arrowstyle]
1850
edgestyles = [self.styles.get(key.strip(),key.strip()) for key in edgestyle.split(',') if key]
1851
styles.extend(edgestyles)
1853
stylestr = ",".join(styles)
1854
topath = getattr(edge,'topath',None)
1856
pstrs = ["%s .. controls %s and %s " % p for p in nsplit(pp, 3)]
1858
if self.options.get('tikzedgelabels',False) or topath:
1859
edgelabel = self.getLabel(edge)
1860
#log.warning('label: %s', edgelabel)
1861
lblstyle = getattr(edge,'lblstyle','')
1863
lblstyle = '['+lblstyle+']'
1867
extra = " node%s {%s}" % (lblstyle,edgelabel)
1871
s += " \draw [%s] %s to[%s]%s %s;\n" % (stylestr, src,
1873
elif not self.options.get('straightedges',False):
1874
#s += " \draw [%s] %s .. %s;\n" % (stylestr, " .. ".join(pstrs), pp[-1])
1875
s += " \draw [%s] %s ..%s %s;\n" % (stylestr, " .. ".join(pstrs), extra,pp[-1])
1877
s += " \draw [%s] %s --%s %s;\n" % (stylestr, pp[0],extra, pp[-1])
1791
edges = self.get_edge_points(edge)
1792
for arrowstyle, points in edges:
1793
#arrowstyle, points = self.get_edge_points(edge)
1794
# PGF uses the fill style when drawing some arrowheads. We have to
1795
# ensure that the fill color is the same as the pen color.
1796
color = getattr(edge,'color','')
1798
if self.color <> color:
1800
s += self.set_color(('cC',color))
1802
# reset to default color
1803
s += self.set_color(('cC','black'))
1806
for point in points:
1807
p = point.split(',')
1808
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
1810
edgestyle = edge.attr.get('style','')
1813
if arrowstyle <> '--':
1814
#styles.append(arrowstyle)
1815
styles = [arrowstyle]
1818
edgestyles = [self.styles.get(key.strip(),key.strip()) for key in edgestyle.split(',') if key]
1819
styles.extend(edgestyles)
1821
stylestr = ",".join(styles)
1822
topath = getattr(edge,'topath',None)
1824
pstrs = ["%s .. controls %s and %s " % p for p in nsplit(pp, 3)]
1826
if self.options.get('tikzedgelabels',False) or topath:
1827
edgelabel = self.get_label(edge)
1828
#log.warning('label: %s', edgelabel)
1829
lblstyle = getattr(edge,'lblstyle','')
1831
lblstyle = '['+lblstyle+']'
1835
extra = " node%s {%s}" % (lblstyle,edgelabel)
1839
s += " \draw [%s] %s to[%s]%s %s;\n" % (stylestr, src,
1841
elif not self.options.get('straightedges',False):
1842
#s += " \draw [%s] %s .. %s;\n" % (stylestr, " .. ".join(pstrs), pp[-1])
1843
s += " \draw [%s] %s ..%s %s;\n" % (stylestr, " .. ".join(pstrs), extra,pp[-1])
1845
s += " \draw [%s] %s --%s %s;\n" % (stylestr, pp[0],extra, pp[-1])
1881
def initTemplateVars(self):
1882
DotConvBase.initTemplateVars(self)
1849
def init_template_vars(self):
1850
DotConvBase.init_template_vars(self)
1883
1851
if self.options.get('crop',False):
1884
1852
cropcode = "\usepackage[active,tightpage]{preview}\n" + \
1885
1853
"\PreviewEnvironment{tikzpicture}\n" + \
1890
1858
vars['<<cropcode>>'] = cropcode
1891
1859
self.templatevars.update(vars)
1893
def getNodePreprocCode(self,node):
1894
lblstyle = node.get('lblstyle','')
1895
text = node.get('texlbl','')
1897
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, text)
1899
return r"\tikz \node {" + text +"};"
1901
def getEdgePreprocCode(self,edge):
1902
lblstyle = getattr(edge,'lblstyle','')
1904
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, edge.texlbl)
1906
return r"\tikz \node " + "{"+edge.texlbl +"};"
1908
def getGraphPreprocCode(self,graph):
1909
lblstyle = getattr(graph,'lblstyle','')
1911
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, graph.texlbl)
1913
return r"\tikz \node " + graph.texlbl +"};"
1861
def get_node_preproc_code(self,node):
1862
lblstyle = node.attr.get('lblstyle','')
1863
text = node.attr.get('texlbl','')
1865
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, text)
1867
return r"\tikz \node {" + text +"};"
1869
def get_edge_preproc_code(self,edge):
1870
lblstyle = edge.attr.get('lblstyle','')
1871
text = edge.attr.get('texlbl','')
1873
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, text)
1875
return r"\tikz \node " + "{"+text +"};"
1877
def get_graph_preproc_code(self,graph):
1878
lblstyle = graph.attr.get('lblstyle','')
1879
text = graph.attr.get('texlbl','')
1881
return " \\tikz \\node[%s] {%s};\n" % (lblstyle, text)
1883
return r"\tikz \node {" + text +"};"
1920
1890
TIKZ_TEMPLATE = r"""\documentclass{article}
1921
1891
\usepackage[x11names, rgb]{xcolor}
2007
1981
or getattr(self.maingraph,'d2tnodeoptions','')
2008
1982
self.options['edgeoptions'] = self.options.get('edgeoptions','') \
2009
1983
or getattr(self.maingraph,'d2tedgeoptions','')
2011
def outputNodeComment(self, node):
1985
def output_node_comment(self, node):
2012
1986
# With the node syntax comments are unnecessary
2015
def getNodePreprocCode(self,node):
2016
lblstyle = node.get('lblstyle','')
2018
shape = node.get('shape','ellipse')
1989
def set_tikzcolor(self,color,colorname):
1990
res = self.convert_color(color, True)
1992
ccolor, opacity = res
1993
if not (opacity == '1'):
1994
log.warning('Opacity not supported yet: %s',res)
1998
if ccolor.startswith('{'):
2000
s += " \definecolor{%s}%s;\n" % (colorname,ccolor)
2008
def get_node_preproc_code(self,node):
2009
lblstyle = node.attr.get('lblstyle','')
2011
shape = node.attr.get('shape','ellipse')
2019
2012
shape = self.shapemap.get(shape, shape)
2020
2013
#s += "%% %s\n" % (shape)
2021
label = node.get('texlbl','')
2022
style = node.get('style'," ") or " ";
2014
label = node.attr.get('texlbl','')
2015
style = node.attr.get('style'," ") or " ";
2024
2017
if style.strip():
2025
2018
style += ','+lblstyle
2035
2028
(shape, style, label)
2040
2033
nodeoptions= self.options.get('nodeoptions',None)
2041
2034
if nodeoptions:
2042
2035
s += "\\begin{scope}[%s]\n" % nodeoptions
2043
2036
for node in self.nodes:
2044
2037
self.currentnode = node
2046
shape = getattr(node,'shape','ellipse')
2047
shape = self.shapemap.get(shape, shape)
2039
if node.attr.get('style') in ['invis','invisible']:
2043
shape = getattr(node,'shape','ellipse')
2044
shape = self.shapemap.get(shape, shape)
2048
2045
if shape == None:
2049
2046
shape='ellipse'
2051
2048
pos = getattr(node,'pos',None)
2054
2051
x,y = pos.split(',')
2055
label = self.getLabel(node)
2052
label = self.get_label(node)
2057
2054
pos = "%sbp,%sbp" % (x,y)
2058
style = node.style or "";
2061
style += ','+node.lblstyle
2063
style = node.lblstyle
2066
style += ','+node.exstyle
2068
style = node.exstyle
2055
style = node.attr.get('style') or "";
2056
if node.attr.get('lblstyle'):
2058
style += ','+node.attr['lblstyle']
2060
style = node.attr['lblstyle']
2061
if node.attr.get('exstyle'):
2063
style += ','+node.attr['exstyle']
2065
style = node.attr['exstyle']
2070
sn += self.outputNodeComment(node)
2071
sn += self.startNode(node)
2072
if self.options.get('styleonly'):
2067
sn += self.output_node_comment(node)
2068
sn += self.start_node(node)
2069
if shape=="coordinate":
2070
sn += " \\coordinate (%s) at (%s);\n" % (tikzify(node.name),pos)
2071
elif self.options.get('styleonly'):
2073
2072
sn += " \\node (%s) at (%s) [%s] {%s};\n" % \
2074
(node.name, pos, style, label)
2073
(tikzify(node.name), pos, style, label)
2076
color = getattr(node,'color','')
2075
color = node.attr.get('color','')
2077
2076
drawstr = 'draw'
2078
2077
if style.strip() == 'filled':
2078
fillcolor = node.attr.get('fillcolor') or \
2079
node.attr.get('color') or "gray"
2079
2080
drawstr='fill,draw'
2082
drawstr += ','+color
2083
code, color = self.set_tikzcolor(color,'strokecolor')
2085
code, fillcolor = self.set_tikzcolor(fillcolor,'fillcolor')
2087
drawstr = "draw=%s,fill=%s" % (color,fillcolor)
2089
code, fillcolor = self.set_tikzcolor(fillcolor,'fillcolor')
2091
drawstr = "draw,fill=%s" % fillcolor
2093
code, color = self.set_tikzcolor(color,'strokecolor')
2084
2095
drawstr += '='+color
2086
2097
if style.strip():
2087
2098
sn += " \\node (%s) at (%s) [%s,%s,%s] {%s};\n" % \
2088
(node.name, pos, drawstr, shape, style, label)
2099
(tikzify(node.name), pos, drawstr, shape, style, label)
2090
2101
sn += " \\node (%s) at (%s) [%s,%s] {%s};\n" % \
2091
(node.name, pos, drawstr, shape, label)
2092
sn += self.endNode(node)
2102
(tikzify(node.name), pos, drawstr, shape, label)
2103
sn += self.end_node(node)
2096
2107
if nodeoptions:
2097
2108
s += "\\end{scope}\n"
2102
2113
edgeoptions = self.options.get('edgeoptions',None)
2103
2114
if edgeoptions:
2110
2121
tlstring = getattr(edge,'_tldraw_',"")
2111
2122
hlstring = getattr(edge,'_hldraw_',"")
2112
2123
topath = getattr(edge,'topath',None)
2113
s += self.drawEdge(edge)
2124
s += self.draw_edge(edge)
2114
2125
if not self.options.get('tikzedgelabels',False) and not topath:
2115
s += self.doDrawString(lstring+" "+tlstring+" "+hlstring, edge)
2126
s += self.do_drawstring(lstring+" "+tlstring+" "+hlstring, edge)
2117
s += self.doDrawString(tlstring+" "+hlstring, edge)
2128
s += self.do_drawstring(tlstring+" "+hlstring, edge)
2119
2130
if edgeoptions:
2120
2131
s += "\\end{scope}\n"
2123
def drawEdge(self, edge):
2134
def draw_edge(self, edge):
2125
if edge.style == 'invis':
2136
if edge.attr.get('style','') in ['invis','invisible']:
2127
arrowstyle, points = self.getEdgePoints(edge)
2128
# PGF uses the fill style when drawing some arrowheads. We have to
2129
# ensure that the fill color is the same as the pen color.
2130
color = getattr(edge,'color','')
2132
for point in points:
2133
p = point.split(',')
2134
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
2136
edgestyle = edge.style
2140
if arrowstyle <> '--':
2141
#styles.append(arrowstyle)
2142
styles = [arrowstyle]
2145
edgestyles = [self.styles.get(key.strip(),key.strip()) for key in edgestyle.split(',') if key]
2146
styles.extend(edgestyles)
2148
stylestr = ",".join(styles)
2150
stylestr = color+','+stylestr
2151
src = edge.get_source()
2152
dst = edge.get_destination()
2153
topath = getattr(edge,'topath',None)
2155
pstrs = ["%s .. controls %s and %s " % p for p in nsplit(pp, 3)]
2156
pstrs[0] = "(%s) ..controls %s and %s " % (src, pp[1], pp[2])
2158
if self.options.get('tikzedgelabels',False) or topath:
2159
edgelabel = self.getLabel(edge)
2160
#log.warning('label: %s', edgelabel)
2161
lblstyle = getattr(edge,'lblstyle','')
2162
exstyle = getattr(edge,'exstyle','')
2138
edges = self.get_edge_points(edge)
2140
log.warning('The tikz output format does not support edge'\
2141
'concentrators yet. Expect ugly output or try the pgf or '\
2142
'pstricks output formats.')
2143
for arrowstyle, points in edges:
2144
# PGF uses the fill style when drawing some arrowheads. We have to
2145
# ensure that the fill color is the same as the pen color.
2146
color = edge.attr.get('color','')
2148
for point in points:
2149
p = point.split(',')
2150
pp.append("(%sbp,%sbp)" % (p[0],p[1]))
2152
edgestyle = edge.attr.get('style')
2156
if arrowstyle <> '--':
2157
#styles.append(arrowstyle)
2158
styles = [arrowstyle]
2161
edgestyles = [self.styles.get(key.strip(),key.strip()) \
2162
for key in edgestyle.split(',') if key]
2163
styles.extend(edgestyles)
2165
stylestr = ",".join(styles)
2167
code,color = self.set_tikzcolor(color,'strokecolor')
2169
stylestr = color+','+stylestr
2170
src = tikzify(edge.get_source())
2173
src_anchor = self.compassmap.get(edge.src_port.split(':')[-1],'')
2175
src = "%s.%s" % (src,src_anchor)
2176
dst = tikzify(edge.get_destination())
2178
dst_anchor = self.compassmap.get(edge.dst_port.split(':')[-1],'')
2180
dst = "%s.%s" % (dst,dst_anchor)
2181
topath = edge.attr.get('topath',None)
2183
pstrs = ["%s .. controls %s and %s " % p for p in nsplit(pp, 3)]
2184
pstrs[0] = "(%s) ..controls %s and %s " % (src, pp[1], pp[2])
2186
if self.options.get('tikzedgelabels',False) or topath:
2187
edgelabel = self.get_label(edge)
2188
#log.warning('label: %s', edgelabel)
2189
lblstyle = getattr(edge,'lblstyle','')
2190
exstyle = getattr(edge,'exstyle','')
2193
lblstyle += ',' +exstyle
2165
lblstyle += ',' +exstyle
2197
lblstyle = '['+lblstyle+']'
2169
lblstyle = '['+lblstyle+']'
2201
extra = " node%s {%s}" % (lblstyle,edgelabel)
2204
s += " \draw [%s] (%s) to[%s]%s (%s);\n" % (stylestr, src,
2206
elif not self.options.get('straightedges',False):
2207
s += " \draw [%s] %s ..%s (%s);\n" % (stylestr,
2208
" .. ".join(pstrs), extra,dst)
2173
extra = " node%s {%s}" % (lblstyle,edgelabel)
2176
s += " \draw [%s] (%s) to[%s]%s (%s);\n" % (stylestr, src,
2178
elif not self.options.get('straightedges',False):
2179
s += " \draw [%s] %s ..%s (%s);\n" % (stylestr,
2180
" .. ".join(pstrs), extra,dst)
2182
s += " \draw [%s] (%s) --%s (%s);\n" % (stylestr, src, extra,dst)
2210
s += " \draw [%s] (%s) --%s (%s);\n" % (stylestr, src, extra,dst)
2186
def startNode(self, node):
2189
def endNode(self,node):
2214
def start_node(self, node):
2217
def end_node(self,node):
2193
2221
^\!\s Preview:\s Snippet\s
2194
2222
(?P<number>\d*)\s ended.
2286
2314
#for i in range(len(self.snippets_id)):
2287
2315
# self.texdims[self.snippets_id[i]] = self.texdimlist[i]
2288
2316
self.texdims = dict(zip(self.snippets_id,self.texdimlist))
2291
def cleanDotNodes(graph):
2292
"""Remove unnecessary data from node list"""
2293
nodes = graph.get_node_list()
2294
tmp = [node for node in nodes if node.name.startswith('"')]
2296
node.name = node.name.replace('"','')
2297
# There are some strange issues with what nodes are returned
2298
# across different operating systems and versions of pydot, pyparsing,
2299
# and Graphviz. This is just a quick fix. Need to investigate this further
2306
# todo: Should also support graph attributes
2307
def setDotAttr(graph):
2308
"""Distribute default attributes to nodes and edges"""
2309
elements = getAllGraphElements(graph,[])
2314
for element in elements:
2315
if isinstance(element,pydot.Node):
2317
nodeattrs = node.__dict__
2318
# is it an attribute statement? (attr_stmt)
2319
if node.name == 'node':
2320
# The node attributes are stored in node.__dict__. Extract all
2321
# items that are not None or functions
2322
defattrs.update([a for a in nodeattrs.items()
2323
if (a[1] or a[1]=='') and not callable(a[1])])
2324
elif node.name == 'edge':
2325
defedgeattrs.update([a for a in nodeattrs.items()
2326
if a[1] and not callable(a[1])])
2328
elif node.name == 'graph':
2331
name = node.name.replace('"','')
2332
if definednodes.get(name,False):
2336
definednodes[name] = True
2337
for key,value in defattrs.items():
2338
if value=='\N':continue
2339
if not node.__dict__.get(key):
2340
node.__dict__[key]=value
2341
elif isinstance(element,pydot.Edge):
2343
for key,value in defedgeattrs.items():
2344
if not edge.__dict__.get(key):
2345
edge.__dict__[key]=value
2346
elif isinstance(element,pydot.Graph):
2347
# push current set of attributes on the stack
2348
stack.append((defattrs,defedgeattrs))
2349
defattrs = defattrs.copy()
2350
defedgeattrs = defedgeattrs.copy()
2351
elif isinstance(element,EndOfGraphElement):
2352
defattrs,defedgeattrs = stack.pop()
2355
def convertDot(data, backend='pstricks', options = {}):
2356
"""Convert xdot data to a backend compatible format
2360
backend - pstricks, pgf, eepic
2363
graph = pydot.graph_from_dot_data(data)
2364
nodes = cleanDotNodes(graph)
2365
edges = graph.edge_list
2367
if graph.graph_type == 'digraph':
2368
directedgraph = True
2370
directedgraph = False
2371
# process edges and nodes
2376
def debug(filename = 'd:/pycode/algs/t.dot'):
2377
dotdata = open(filename).read()
2378
r = convertDot(dotdata)
2382
def processCmdLine():
2383
"""Set up and parse command line options"""
2319
def create_options_parser():
2320
"""Create and and return an options parser"""
2384
2321
usage = "Usage: %prog [options] <files>"
2385
2322
parser = OptionParser(usage)
2386
2323
parser.add_option("-f", "--format",
2490
2460
log.info("System information:\n"
2491
2461
" Python: %s \n"
2492
2462
" Platform: %s\n"
2494
2463
" Pyparsing: %s",
2495
2464
sys.version_info, platform.platform(),
2496
pydot.__version__,pydot.dot_parser.pyparsing_version)
2465
dotparsing.pyparsing_version)
2497
2466
log.info('dot2tex called with: %s' % sys.argv)
2498
2467
log.info('Program started in %s' % os.getcwd())
2500
if options.printversion:
2505
log.info('Data read from standard input')
2506
dotdata = sys.stdin.readlines()
2507
elif len(args) == 1:
2509
dotdata = open(args[0], 'rU').readlines()
2511
log.error("Could not open input file %s" % args[0])
2513
log.info('Data read from %s' % args[0])
2468
if not run_as_module:
2469
if options.printversion:
2471
print_version_info()
2474
log.info('Data read from standard input')
2475
dotdata = sys.stdin.readlines()
2476
elif len(args) == 1:
2477
dotdata = load_dot_file(args[0])
2479
# Make sure dotdata is compatitle with the readlines data
2480
dotdata = dotdata.splitlines(True)
2482
# look for a line containing an \input
2483
m = re.search(r"^\s*\\input\{(?P<filename>.+?)\}\s*$",
2484
"".join(dotdata),re.MULTILINE)
2486
filename = m.group(1)
2487
log.info('Found \\input{%s}',filename)
2488
dotdata = load_dot_file(filename)
2515
2492
# I'm not quite sure why this is necessary, but some files
2516
2493
# produces data with line endings that confuses pydot/pyparser.