def generate_directory_graph(directory): # Create a new directed graph graph = yapgvb.Digraph(directory) # Traverse the directory structure nodes = {} try: for dirpath, dirnames, filenames in os.walk(directory): print " ", dirpath parent_directory, dirname = os.path.split(dirpath) nfiles = len(filenames) # Create a new node for this directory nodes[dirpath] = graph.add_node( dirpath, label="%s: %s files" % (dirname, nfiles), shape='record', ) if parent_directory in nodes: # create an edge between the parent directory node # and the newly created node nodes[parent_directory] >> nodes[dirpath] except KeyboardInterrupt: print '----> Directory traversal cancelled!' return graph
def draw(self, path='adtree.png'): G = yapgvb.Digraph('ADTree') label = self._node_id_iter() viz_adnode = G.add_node(label.next(), label='root (%s)' % self.root.count, shape=yapgvb.shapes.circle, color=yapgvb.colors.blue, root=True) self._build_graph(G, self.root, viz_adnode, label) G.layout(yapgvb.engines.dot) G.render(path)
def create_graph(cfg, username): userAPI = UserAPI(cfg) campaignAPI = CampaignAPI(cfg) user = userAPI.show_by_username(username) nodes = {} edges = {} graph = yapgvb.Digraph(username) walk_user_campaigns(userAPI, campaignAPI, graph, nodes, edges, user) return graph
def generate_directory_graph(directory): # Create a new directed graph graph = yapgvb.Digraph(directory) # Traverse the directory structure nodes = {} try: for dirpath, dirnames, filenames in os.walk(directory): print " ", dirpath parent_directory, dirname = os.path.split(dirpath) nfiles = len(filenames) # Create a new node for this directory nodes[dirpath] = graph.add_node(dirpath, label = "%s" % (dirname), shape = 'record', ) # Create nodes for each file in this directory for filename in filenames: #print "filename:", filename bad = False for blackitem in BLACKLIST: if blackitem in filename: #print "Passing blacklisted item:", filename #print "because", blackitem, "is in ", filename bad = True break if bad: continue #print "creating node for ", filename nodes[dirpath + filename] = graph.add_node(dirpath + filename, label = "%s" % filename, shape = 'record', ) nodes[dirpath] >> nodes[dirpath + filename] if parent_directory in nodes: # create an edge between the parent directory node # and the newly created node nodes[parent_directory] >> nodes[dirpath] except KeyboardInterrupt: print '----> Directory traversal cancelled!' return graph
def graph(self, outfile): remaining = 60 try: import yapgvb g = yapgvb.Digraph('Analysis of ' + self.url) except: print 'Unable to import yapgvb, please install python library' if os.path.exists(outfile): os.remove(outfile) for url in self.rooturl: urlstr = url if self.rooturl[url].malicious > 5: color = yapgvb.colors.red urlstr += '\nmalicious' elif self.rooturl[url].malicious > 0: color = yapgvb.colors.orange urlstr += '\nsuspicious' else: color = 'white' if max(self.rooturl[url].malicious, self.rooturl[url].cumulative_malicious) > 0 or self.graphall: remaining -= 1 node = g.add_node(url) node.label = urlstr node.color = color node.shape = yapgvb.shapes.box for type, child in self.rooturl[url].children: if self.rooturl[child].hasParent and type == 'default': pass elif max(self.rooturl[url].malicious, self.rooturl[child].cumulative_malicious, self.rooturl[child].malicious) > 0 or self.graphall: cnode = g.add_node(child) cnode.shape = yapgvb.shapes.box cnode.label = child edge = g.add_edge(node, cnode) if not type == 'default': edge.label = type if remaining > 0: g.layout(yapgvb.engines.dot) g.render(outfile) else: print 'Not graphing "%s" because rooturl used (%d) more nodes than the maximum (60)' % (outfile, -remaining)
def dot_repr(self, all_instructions=False): graph = yapgvb.Digraph('cfg') graph.dpi = 600 nodes_dict = {} for cur_bb_id in self.bbs: lst = self.bbs[cur_bb_id].dot_repr(self, all_instructions) nodes_dict[lst[0]] = graph.add_node(lst[0], label=lst[1]) for cur_bb_id in self.bbs: nextNodeNum = 0 for next_bb_id in self.bbs[cur_bb_id].get_next_ids(): edge = nodes_dict["bb_" + str(cur_bb_id)] - nodes_dict["bb_" + str(next_bb_id)] edge.label = str(nextNodeNum) nextNodeNum += 1 return graph
def generate_random_graph(nnodes=20, nedges=80): import random graph = yapgvb.Digraph("my_graph") for i in xrange(nnodes): # Create a node named str(i) node = graph.add_node(str(i)) # Assign a random shape and color node.shape = random.choice(yapgvb.shapes.values()) node.color = random.choice(yapgvb.colors.values()) # Get all of the nodes as a list # (the graph.nodes attribute is an iterator) nodes = list(graph.nodes) for i in xrange(nedges): head = random.choice(nodes) tail = random.choice(nodes) edge = tail >> head edge.color = random.choice(yapgvb.colors.values()) return graph
def dump_back_reference_graph(obj, maxdepth): obj = obj() if obj is None: print "Weakref was freed." return curframe = inspect.currentframe() todo = deque([(obj, 0)]) strings = {} objects = {} depths = {} edges = [] skipped = set() def element_string(e): if type(e) == list: return "list" if type(e) == type(curframe): return "frame: %s:%i" % (os.path.basename( e.f_code.co_filename), e.f_lineno) if type(e) == dict: return "\n".join([ "%10s : %20s" % (str(k)[0:10], str(v)[0:10]) for k, v in e.iteritems() ][0:10]) #if type(e) == tuple: # return "tuple" return str(e)[0:40] def list_str_bounded(l, join_str, max_indices, max_elem): l = [str(e)[0:max_elem] for e in l] if len(l) > max_indices: l = l[0:max_indices] l.append('...') return join_str.join(l) def edge_string(e1, e2): if type(e1) == list: return list_str_bounded([i for i in range(len(e1)) if e1[i] == e2], ", ", 10, 10) if type(e1) == dict: keys = [str(k)[0:20] for (k, v) in e1.iteritems() if e2 == v] return list_str_bounded( [k for (k, v) in e1.iteritems() if e2 == v], "\n", 10, 20) return list_str_bounded( [a for a in dir(e1) if e1.__getattribute__(a) == e2], "\n", 10, 20) def dont_trace(e): if type(e) == type(inspect): return True return False while todo: e, d = todo.popleft() ide = id(e) if ide in strings or d > maxdepth: continue strings[ide] = element_string(e) depths[ide] = d objects[ide] = e if dont_trace(e): skipped.add(ide) continue d += 1 refs = gc.get_referrers(e) refs.remove(curframe) for r in list(refs): if r in todo or r == objects: refs.remove(r) todo.extend((r, d) for r in refs) edges.extend((id(r), ide) for r in refs) del refs print "Found %i nodes and %i edges" % (len(strings), len(edges)) #for s in strings.values(): # print s graph = yapgvb.Digraph('Referrers') nodes = {} colors = ["red", "orange", "yellow", "green", "blue", "purple", "black"] ncol = len(colors) for (ids, s) in strings.items(): nodes[ids] = graph.add_node(str(ids), label=s, color=colors[depths[ids] % ncol]) if ids in skipped: nodes[ids].shape = 'box' if depths[ids] == maxdepth: nodes[ids].shape = 'parallelogram' for (id1, id2) in edges: if id1 in nodes and id2 in nodes: edge = nodes[id1] >> nodes[id2] s = edge_string(objects[id1], objects[id2]) if s: edge.label = s graph.root = str(id(obj)) #graph.layout(yapgvb.engines.twopi) graph.layout(yapgvb.engines.dot) graph.render('gcgraph.ps') del objects
for item in items: clusterName = str(current + 1) nodes[clusterName] = graph.add_node(clusterName, label='group %s' % clusterName) generate_pham_graph(graph, item, parent=clusterName, phage=phage, current=clusterName) return graph if __name__ == '__main__': nodes = {} clusters = eval(open('graphviz_input.txt').read()) graph = yapgvb.Digraph() # Did the user specify a filename on the command line? output_file = sys.argv[1] if output_file is None: output_file = 'output.png' if len(sys.argv) > 2: phage = sys.argv[2] else: phage = None print 'phage:', phage print "Generating pham structure graph... Ctrl-C to terminate" for n, item in enumerate(clusters): graph = generate_pham_graph(graph, item, phage=phage, current=n)
import yapgvb import subprocess g = yapgvb.Digraph("tree") n = [g.add_node(str(i)) for i in xrange(4)] e = [i >> j for i, j in zip(n[1:], n[:-1])] e[0].label = 'cat' # for j in xrange(3): # g.add_edge(str(i+1), str(i)) g.layout(yapgvb.engines.dot) file = 'tree.png' g.render('tree.png') subprocess.Popen(['display', file])
def __init__(self, title='Django Model ERD'): self._graph = yapgvb.Digraph(title)
def plot(self, filename='computational_graph.png', method='dot', orientation='TB'): """ accepted filenames, e.g.: filename = 'myfolder/mypic.png' 'mypic.svg' etc. accepted methods method = 'dot' method = 'circo' method = 'fdp' method = 'twopi' method = 'neato' accepted orientations: orientation = 'TB' orientation = 'LR' orientation = 'BT' orientation = 'RL' """ try: import yapgvb except: raise PlotError('you will need yapgvb to plot graphs') import os supported_extensions = list(yapgvb.formats) extension = os.path.splitext(filename)[1][1:] if extension not in supported_extensions: raise PlotError( 'Unsupported output graphics file extension.\n' 'Supported extensions: ' + str(supported_extensions)) supported_methods = list(yapgvb.engines) if method not in supported_methods: raise PlotError( 'Unsupported graph layout method.\n' 'Supported layout methods: ' + str(supported_methods)) supported_orientations = ['TB', 'LR', 'BT', 'RL'] if orientation not in supported_orientations: raise PlotError( 'Unsupported graph layout orientation.\n' 'Supported layout orientations: ' + str(supported_orientations)) # setting the style for the nodes g = yapgvb.Digraph('someplot') g.rankdir = orientation # add nodes for f in self.functionList: if f.func == Function.Id: g.add_node('%d'%f.ID, label = '%d %s'%(f.ID,f.func.__name__), shape = yapgvb.shapes.doublecircle, color = yapgvb.colors.blue, fontsize = 10) else: g.add_node('%d'%f.ID, label = '%d %s'%(f.ID,f.func.__name__), shape = yapgvb.shapes.box, color = yapgvb.colors.blue, fontsize = 10) # add edges nodes = list(g.nodes) for f in self.functionList: for a in numpy.ravel(f.args): if isinstance(a, Function): nodes[a.ID] >> nodes[f.ID] # independent nodes for f in self.independentFunctionList: nodes[f.ID].shape = yapgvb.shapes.octagon # dependent nodes for f in self.dependentFunctionList: nodes[f.ID].shape = yapgvb.shapes.octagon g.layout(method) g.render(filename, format=extension)
#!/usr/bin/env python # # This file is a part of the Yapgvb software package, and is # licensed under the New BSD License. # A `LICENSE' file should have been included with this source. # # Copyright (c) 2009 Lonnie Princehouse # # A silly example to generate the logo for the yapgvb homepage import yapgvb if __name__ == '__main__': g = yapgvb.Digraph('yapgvb_logo') yapgvb_node = g.add_node("YAPGVB", label='YAPGVB', shape=yapgvb.shapes.doublecircle, color=yapgvb.colors.blue, fontsize=48) last_word = None for word in "Yet Another Python Graphviz Binding".split(): word_node = g.add_node(word, label=word, fontsize=24, shape=yapgvb.shapes.circle)
def moerdergraph(round, filename, alledges=False, nodefontsize=8.0, edgefontsize=8.0): # G is the main Graph object G = graph.Digraph("Moerder") # a dict for indexing all nodes nodes = {} # we need to keep some of the nodes in mind prev_node = first_node = node = None # make a copy of the participant list so we don't jumble up the original list participants = round.participants[:] if not alledges: # if not admin/gameover view: sort nodes prior to adding them to the graph participants.sort(key=lambda p: p.player.name + p.player.info) # for each participant, add a node to the graph bearing his name for participant in participants: name = participant.player.name if len(participant.player.info) > 0: name += "\\n" + participant.player.info node = G.add_node(participant.player.public_id) node.label = name.encode('utf-8') node.fontsize = nodefontsize node.margin = 0.03 if not prev_node: first_node = node # put all the nodes into a dict so we could find them fast by the player's id (needed later) nodes[participant.player.public_id] = node prev_node = node node.fontname = 'arial' # kicked participants are gray if participant.killed() and participant.killedby.killer is None: node.color = 'gray' node.fontcolor = 'gray' # dead participants are red if participant.killed() and not participant.killedby.killer is None: node.color = 'red' node.fontcolor = 'red' for participant in round.participants: if alledges or participant.killed(): # add black edges for the initial kill assignment edge = G.add_edge( nodes[participant.getInitialKiller().player.public_id], nodes[participant.player.public_id]) edge.color = 'black' edge.weight = 1.0 if participant.killed(): # add red edges for the kill if not participant.killedby.killer is None: # normal case edge = G.add_edge( nodes[participant.killedby.killer.player.public_id], nodes[participant.player.public_id]) else: # special case of a game master kill node = G.add_node('vorzeitig ausgestiegen') node.fontsize = nodefontsize node.fontname = 'arial' node.color = 'gray' node.fontcolor = 'gray' edge = G.add_edge(node, nodes[participant.player.public_id]) edge.color = 'red' edge.fontcolor = 'red' edge.weight = 1.0 # set edge label to kill description label = utils.dateformat(participant.killedby.date) + ":\\n" maxlinelen = max( 24, math.trunc( math.ceil(math.sqrt(6 * len(participant.killedby.reason))))) label += "\\n".join( textwrap.wrap(participant.killedby.reason, maxlinelen)) edge.label = label.encode('utf-8') edge.fontsize = edgefontsize edge.fontname = 'arial' # do the layout math and save to file G.layout(graph.engines.dot) G.render(filename)
def renderGraphMain(argv, stdout, env): # default arguments server = "http://localhost" server_port = rospy.DEFAULT_TEST_PORT #check arguments for a help flag optlist, args = getopt.getopt(argv[1:], "h?p:s:", ["help", "port=", "server=", "test"]) for o, a in optlist: if o in ("-h", "-?", "--help"): usage(stdout, argv[0]) return elif o in ("--test"): server_port = rospy.DEFAULT_TEST_PORT elif o in ("-p", "--port"): server_port = a elif o in ("-s", "--server"): server = a serverUri = '%s:%s/' % (server, server_port) print "Looking for server at %s" % serverUri os.environ[rospy.ROS_MASTER_URI] = serverUri os.environ[rospy.ROS_NODE] = NAME os.environ[rospy.ROS_PORT] = str(0) # any master = rospy.getMaster() out_FlowImageString = OutflowpyImageString(".imageOut") require( master.addMachine('default', rospy.getRosRoot(), 'localhost', 22, '', '')) require( master.addNode('', 'imageViewer', 'pyImageViewer', 'imageViewer', 'default', 0)) rospy.ready() require( master.connectFlow(out_FlowImageString.locator, "imageViewer:imageIn", 1)) while not rospy.isShutdown(): status_code, statusMessage, [nodes, flows] = master.getGraph() # print 'nodes' + str(nodes) # print 'flows ' + str(flows) print '--------------------------------------------' print 'This is the graph:' print 'refreshing every ' + str(sleep_time) + ' seconds' print '--------------------------------------------' for anode in nodes: status_code, statusMessage, [machine, address, port] = master.getNodeAddress(anode) print 'NODE: ' + str(anode) + ' on ' + str(machine) + ' at ' + str( address) + ' on port: ' + str(port) for aflow in flows: aflow_split = str(aflow[1]).split('.') destination = aflow_split[0] aflow_split_source = str(aflow[0]).split('.') source = aflow_split_source[0] if destination == anode: print '\tINFLOW: ' + str(aflow_split[1]) + ' from: ' + str( aflow[0]) if source == anode: print '\tOUTFLOW: ' + str( aflow_split_source[1]) + ' to: ' + str(aflow[1]) output_file = 'ROSGraph.jpeg' pid = os.fork( ) # This is a hack to get around an underlying memory leak in # the agraph library. if pid == 0: #print "starting yapgvb process" try: print '--------------------------------------------' ygraph = yapgvb.Digraph('ROSGraph') gnodes = {} for anode in nodes: gnodes[anode] = ygraph.add_node(label=anode) #print "added allnodes" #print flows for aflow in flows: aflow_split = str(aflow[1]).split(':') destination = aflow_split[0] aflow_split_source = str(aflow[0]).split(':') source = aflow_split_source[0] gnodes[source] >> gnodes[destination] #print "done setting up graph for rendering" ygraph.layout(yapgvb.engines.dot) ygraph.render(output_file) finally: mpid = os.getpid() os.kill(mpid, 9) else: os.wait() # Wrap up the image and send it out over a flow imToSend = Image.open(output_file) future_packet = pyImageString() future_packet.imageString = imToSend.tostring() future_packet.imageFormat = "RGB" future_packet.width, future_packet.height = imToSend.size out_FlowImageString.publish(future_packet) # don't loop too fast time.sleep(sleep_time)
def main(filename): try: file = open(filename, 'r') except Exception as e: print "Errors occurred opening input file %s" % filename print e exit(1) graph = yapgvb.Digraph() node_from = None node_to = None tmp = tempfile.NamedTemporaryFile() # set file pointer on PROCEDURE DIVISION line for line in file: if PROC.match(line): break # now writes to temp file, deleting comments and debug statement for line in file: try: if line[6] in ('*', 'D'): continue except IndexError: continue tmp.write(line) # look for labels and build graph # every label is a node, every perform is an edge tmp.seek(0) for line in tmp: mtch = LABEL.match(line) if mtch and mtch.group(1): #if mtch.group(1)[0:1] in ("Z-"): # continue node_from = graph.find_node(mtch.group(1)) mtch = PERFORM.match(line) if mtch and mtch.group(1) and mtch.group(1) != "VARYING": #if mtch.group(1)[0:1] in ("Z-"): # continue node_to = graph.find_node(mtch.group(1)) graph.add_edge(node_from, node_to) print "Graph edges: ", len([n for n in graph.edges]) print "Graph nodes: ", len([n for n in graph.nodes]) graph.layout(engine='dot') print "rendering graph..." try: fileoname = filename + ".jpg" fileout = open(fileoname, 'w') except Exception as e: print "Errors occurred opening output file %s" % fileoname print e exit(1) graph.render(outstream=fileout,format='jpg') print "Done!" tmp.close() file.close()
def _PlotAndDisplay(imageViewerApp_, graph_, timeStamp_): global _firstPlot if _which(imageViewerApp_) == None: print 'Image rendering application:', '"' + imageViewerApp_ + '"', 'does not exist on your machine.' print 'Change application name from your master script.' exit(1) (graphId, (source, destination), (primaryClockSources, secondaryClockSources), path) = graph_ if len(path) == 0: return None if source == 'F980' or source == 'F981': source = '1' if destination == 'F980' or destination == 'F981': destination = '1' # node that the clockSource will be provided for clockNode = source if source == '1': clockNode = destination pClckSource = '' sClckSource = '' if clockNode in primaryClockSources.keys(): pClckSource = primaryClockSources[clockNode] if clockNode in secondaryClockSources.keys(): sClckSource = secondaryClockSources[clockNode] # ploting starts here graphviz_graph = yapgvb.Digraph() colors = "#000000" colord = "#000000" for (s, d) in path: if s == source: colors = yapgvb.colors.blue else: colors = "#000000" if d == destination: colord = yapgvb.colors.blue else: colord = "#000000" source_label = s if s == pClckSource: source_label = s + '\nPCS' elif s == sClckSource: source_label = s + '\nSCS' dest_label = d if d == pClckSource: dest_label = d + '\nPCS' elif d == sClckSource: dest_label = d + '\nSCS' source_node = graphviz_graph.add_node(s, label=source_label, shape=yapgvb.shapes.circle, color=colors, fontsize=10) dest_node = graphviz_graph.add_node(d, label=dest_label, shape=yapgvb.shapes.circle, color=colord, fontsize=10) source_node >> dest_node graphviz_graph.add_node("GraphId", label='Graph ID: ' + graphId + ', time stamp:\n' + timeStamp_, shape=yapgvb.shapes.rectangle, color=yapgvb.colors.violet, fontsize=10) #graphviz_graph.label = 'Graph ID: ' + graphId + ', time stamp:\n' + timeStamp_ graphviz_graph.layout(yapgvb.engines.circo) # get a temp file tmpFile = tempfile.NamedTemporaryFile(prefix='graphviz', suffix='.png', delete='False') tmpFile.close() # render plot graphviz_graph.render(tmpFile.name) # avoid crashes when rendering multiple plots if _firstPlot == True: _firstPlot = False else: time.sleep(2) # show image os.system(imageViewerApp_ + ' ' + tmpFile.name + ' &') return None
def moerdergraphall(game, filename, alledges=False, nodefontsize=8.0, edgefontsize=8.0, rounds=None): if rounds is None: rounds = game.rounds.values() elif type(rounds) is not list: rounds = [rounds] # G is the main Graph object G = graph.Digraph("Moerder") G.model = 'subset' G.overlap = 'compress' G.splines = True G.normalize = True G.packmode = 'graph' G.rankdir = 'LR' # a dict for indexing all nodes nodes = {} # we need to keep some of the nodes in mind prev_node = first_node = node = None # make a copy of the participant list so we don't jumble up the original list participants = sorted( rounds, key=lambda x: len(x.participants))[-1].participants[:] gmnode = G.add_node('Game Master') gmnode.label = 'Game Master' gmnode.fontsize = nodefontsize gmnode.fontname = 'arial' gmnode.color = 'gray' gmnode.fontcolor = 'gray' gmnode.style = 'rounded' hnode = inode = G.add_node('invisible') inode.style = 'invisible' inode.pos = (0.0, 0.0) if len(participants) > 120: sorrynode = G.add_node(u'Sorry, zu viele Nodes in diesem Graph...') sorrynode.label = u'Sorry, zu viele Nodes in diesem Graph...' sorrynode.style = 'rounded,filled' sorrynode.fontsize = nodefontsize sorrynode.style = 'rounded,filled' sorrynode.penwidth = 2 sorrynode.color = '#00003380' sorrynode.fillcolor = '#FFFFFF00' sorrynode.margin = 0.01 # do the layout math and save to file if graph.__dict__.has_key('_yapgvb_py'): # if yapgvb works in python-only mode rc = MyRenderingContext() G.layout(graph.engines.dot, rendering_context=rc) G.render(filename, rendering_context=rc) else: # if yapgvb has libboost support compiled in G.layout(graph.engines.dot) G.render(filename) return massmurderers = game.getMassMurderer() massmurdererlist = [ player.public_id for player in massmurderers['killers'] ] if len(massmurderers) > 0 else [] if not alledges: # if not admin/gameover view: sort nodes prior to adding them to the graph participants.sort(key=lambda p: p.player.name + p.player.info) nodecount = len(participants) nodesperline = math.trunc(math.sqrt(nodecount)) # for each participant, add a node to the graph bearing his name nodenumber = 0 for participant in participants: nodenumber += 1 name = participant.player.name if len(participant.player.info) > 0: name += "\\n" + participant.player.info name = utils.dotescape(name) node = G.add_node(participant.player.public_id) node.label = name.encode('utf-8') node.fontsize = nodefontsize node.style = 'rounded,filled' node.penwidth = 2 node.color = '#00003380' node.fillcolor = '#FFFFFF00' node.margin = 0.01 nodeweight = game.getDeathsCount(participant) + game.getKillsCount( participant) #node.group = str(nodeweight) node.pos = (nodenumber % nodesperline, nodenumber / nodesperline) if nodeweight == 0: iedge = G.add_edge(inode, node) iedge.style = 'invisible' iedge.arrowhead = 'none' iedge.weight = 0.1 node.pos = (0.0, 0.0) #iedge.constraint = False if not prev_node: first_node = node # put all the nodes into a dict so we could find them fast by the player's id (needed later) nodes[participant.player.public_id] = node prev_node = node node.fontname = 'arial' # kicked participants are gray if participant.killed() and participant.killedby.killer is None: #node.color = '#FF6666FF' #node.fontcolor = '#33333388' #node.fillcolor = '#66666622' node.style += ',dashed' # mass murderers are black if participant.player.public_id in massmurdererlist: node.color = 'black' node.fillcolor = 'black' node.fontcolor = 'white' # dead participants are red if (game.getDeathsCount(participant) >= len(game.rounds)): node.color = '#FF0000FF' node.penwidth = 2 #node.fontcolor = '#FFFFFFFF' #node.fillcolor = '#FF0000FF' colorgenerator = colorgen(0.86) for round in game.rounds.values(): edgecolor = next(colorgenerator) if round not in rounds: continue for participant in round.participants: if alledges or participant.killed(): edge = G.add_edge( nodes[participant.getInitialKiller().player.public_id], nodes[participant.player.public_id]) edge.color = edgecolor edge.style = 'dashed' edge.penwidth = 2 edge.weight = 6.0 #edge.constraint = False if participant.killed(): if not participant.killedby.killer is None: # normal case edge = G.add_edge( nodes[participant.killedby.killer.player.public_id], nodes[participant.player.public_id]) else: # special case of a game master kill edge = G.add_edge(gmnode, nodes[participant.player.public_id]) edge.color = edgecolor edge.fontcolor = 'red' edge.style = 'solid' edge.penwidth = 4 edge.weight = 10.0 # set edge label to kill description label = utils.dateformat(participant.killedby.date) + ":\\n" maxlinelen = max( 24, math.trunc( math.ceil( math.sqrt(6 * len(participant.killedby.reason))))) label += "\\n".join( textwrap.wrap(participant.killedby.reason, maxlinelen)).replace('"', "'") edge.label = ''.join( [c for c in label.encode('utf-8') if ord(c) < 2048]) edge.fontsize = edgefontsize edge.fontname = 'arial' # do the layout math and save to file if graph.__dict__.has_key('_yapgvb_py'): # if yapgvb works in python-only mode rc = MyRenderingContext() G.layout(graph.engines.dot, rendering_context=rc) G.render(filename, rendering_context=rc) else: # if yapgvb has libboost support compiled in G.layout(graph.engines.dot) G.render(filename)