def make_dot(name, url, label, nodes, edges): dot = Digraph(name=name, comment=url) dot.graph_attr.update({ 'label': label, 'overlap': 'scalexy' }) subgraphs = {} for node in nodes: if node.sensor not in subgraphs: url = url_for('sensor', id=node.sensor, _external=True) name = "cluster_sensor_{}".format(node.sensor) label = "Sensor {type}: {sname} ({sensor})".format_map( node._asdict()) subgraphs[node.sensor] = Digraph(name=name, comment=url) subgraphs[node.sensor].graph_attr.update({'label': label}) label = '{name}\\n({id})'.format_map(node._asdict()) subgraphs[node.sensor].node(str(node.id), label=label, color='black') for sensor in subgraphs: dot.subgraph(subgraphs[sensor]) for edge in edges: label = '{tname}\\n({id})'.format_map(edge._asdict()) dot.edge(str(edge.source), str(edge.target), label=label) dot.engine = 'dot' return dot
def to_graphviz(workflow, LR): """Convert dictionary to a dot graph.""" g = Digraph(name="dataflow") if LR: g.graph_attr["rankdir"] = "LR" else: g.graph_attr["rankdir"] = "TB" seen = set() cache = {} for nbname, v in workflow.items(): g.node(nbname, shape="box3d") for fname in v["input"]: if fname not in seen: seen.add(fname) g.node(fname, shape="octagon", style="filled", fillcolor=data_colour(fname)) g.edge(fname, nbname) for fname in v["output"]: if fname not in seen: seen.add(fname) g.node(fname, shape="octagon", style="filled", fillcolor=data_colour(fname)) g.edge(nbname, fname) g.node("Generated by dataflow.py from https://github.com/chengsoonong/nbtidy", shape="none") return g
def get_formatted_fields(self, type_name: str, schema: dict, group: Digraph) -> list: resulting_fields = [] for field in self.get_fields(schema, schema_name=type_name): name = field['name'] if 'reference' in field: if field['type'] == 'list': head_label = '*' if field['attr']['Required'] else '1..*' else: head_label = '1' if field['attr']['Required'] else '0..1' group.edge(type_name, field['reference'], headlabel=head_label, taillabel='*', label=field['name']) else: field['name'] = '*' + name if field['attr']['Unique'] else name resulting_field = '+ {}'.format(field['name']) if len(field['attr']['Allowed'] or []) > 0: enum_name = '{}Enum'.format(name) group.node(enum_name, '{{{}Enum\lEnum|{}}}'.format(name, '\l'.join(map(str, field['attr']['Allowed'])))) resulting_field += ': {}'.format(enum_name) else: resulting_field += ': {}'.format(field['type']) resulting_field += ' [0..1]' if not field['attr']['Required'] else '' resulting_field += ' (write-only)' if field['attr']['Write only'] else '' resulting_field += ' (read-only)' if field['attr']['Read only'] else '' resulting_fields.append((resulting_field, field['attr']['Sink'])) resulting_fields.sort(key=Doc.get_sink, reverse=True) return [resulting_field[0] for resulting_field in resulting_fields]
def draw( self, vec, contentMatrix, fig_coment,K = 0, filter_lonelyRoot = False, filter_noRequest = True): self.find_lonely(vec) # dot = Digraph(comment=fig_coment, engine='dot') # dot = Digraph(comment=fig_coment, engine='neato') dot = Digraph(comment=fig_coment, engine='fdp') # dot = Digraph(comment=fig_coment, engine='twopi') dot.format = 'svg' # dot.body.extend(['rankdir=LR']) # set vertical layout if K >0: time_consuming = self.most_timeConsuming(contentMatrix['wait_interval'],K) else: time_consuming = [] # dot.body.append('center=ture') # dot.node_attr.update(color='lightblue2', style='filled',width='0.04',height='0.04') for i in range(0,len(vec)): if (filter_lonelyRoot and (i in self.lonely)) or vec[i]<0: continue if i in time_consuming: if contentMatrix['wait_interval'][i] != -1: dot.node(str(i+1),"("+str(i+1)+")\n"+contentMatrix['mimeType'][i].split(';')[0].split('/')[-1]+':'+str(contentMatrix['wait_interval'][i]),color='tomato2', style='filled') elif not filter_noRequest: dot.node(str(i+1),"("+str(i+1)+")\n"+"no request", style='filled') else: if contentMatrix['wait_interval'][i] != -1: dot.node(str(i+1),"("+str(i+1)+")\n"+contentMatrix['mimeType'][i].split(';')[0].split('/')[-1]+':'+str(contentMatrix['wait_interval'][i]),color='lightblue2', style='filled') elif not filter_noRequest: dot.node(str(i+1),"("+str(i+1)+")\n"+"no request", style='filled') if vec[i] != 0 and ((not filter_noRequest) or contentMatrix['wait_interval'][i] != -1): dot.edge(str(vec[i]), str(i+1))#,constraint='false') dot.render(fig_coment+'_treeplot.dot', view=True) return dot
def tree_to_graph(self,tree=None,n="",comment="Huffman Coding",formatin="png",graph=None): """Based on the Huffman Coding it creates a graph with graphviz library :param comment: graph comment :param formatin: graph format :param n: temporal huffman coding path to leaf """ if not tree: tree=self.tree if not graph: graph = Digraph(comment=comment, format=formatin) left = n+"0" right = n+"1" # Each node has the symbol frecuency graph.node(n,str(tree[0])+", \'"\ # Symbol value if it is a leaf +(str(tree[1]))+"\'; \n"\ # Symbol code if it is a leaf +n if not isinstance(tree[1],list) else str(tree[0])) # In case we are not in a leaf if (isinstance(tree[1],list)): self.tree_to_graph(tree[1][0],left,graph=graph) self.tree_to_graph(tree[1][1],right,graph=graph) try: graph.edge(n,left,label='0') graph.edge(n,right,label='1') except Exception as e: print n, "error" raise return graph
def diagram(self): from graphviz import Digraph from queue import Queue diagram=Digraph(comment='The Trie') i=0 diagram.attr('node', shape='circle') diagram.node(str(i), self.root.getValue()) q=Queue() q.put((self.root, i)) while not q.empty(): node, parent_index=q.get() for child in node.getChildren(): i+=1 if child.getEnding(): diagram.attr('node', shape='doublecircle') diagram.node(str(i), child.getValue()) diagram.attr('node', shape='circle') else: diagram.node(str(i), child.getValue()) diagram.edge(str(parent_index), str(i)) q.put((child, i)) o=open('trie_dot.gv', 'w') o.write(diagram.source) o.close() diagram.render('trie_dot.gv', view=True) 'trie_dot.gv.pdf'
def render_tree(tokens, edges): """ Renders a (parse) tree using graphiz Args: tokens: an array of tokens (strings) edges: an array of (head_token_id, dep_token_id, label) triples. The ids are integers starting from 0 for the first token Returns: the Digraph object representing the tree. Can be rendered in notebook. """ dot = Digraph(comment='The Round Table') # Removed this to avoid having tokens appearing without edges # for token_id, token in enumerate(tokens): # dot.node(str(token_id), token) for edge in edges: head, dep, label = edge dot.edge(str(head), str(dep), label) dot.node(str(head), tokens[head]) dot.node(str(dep), tokens[dep]) return dot
def create_tree(queryset): """ Given a queryset of BuildingSnapshots, construct a graphviz dot graph of the tree structure. This can be useful for visually inspecting the tree. """ seen_nodes = set() dot = Digraph(comment="Building Snapshot Visualization") for bs in queryset: if bs.canonical_building_id is None: continue bs_id, bs_name = bs_node_id(bs), bs_node_name(bs) c_id, c_name = c_node_id(bs), c_node_name(bs) dot.node(c_id, c_name) dot.node(bs_id, bs_name) dot.edge(c_id, bs_id) seen_nodes.add(bs_id) seen_nodes.add((c_id, bs_id)) if bs.canonical_building.canonical_snapshot_id is not None: s_id, s_name = s_node_id(bs.canonical_building), s_node_name(bs.canonical_building) dot.node(s_id, s_name) dot.edge(s_id, c_id) create_bs_tree(bs, dot, seen_nodes) return dot
def generate_graph(self, rule_links, out_file): graph_label = 'Rule based visualizer' graph_attr = { 'rankdir': 'TD', 'labelloc': 't', 'fontsize': '15', 'label': graph_label } node_attr = {} dot = Digraph(comment='Rule based links visualization', node_attr=node_attr, graph_attr=graph_attr, format='png') nodes = set() for _, rule_link in rule_links: print(rule_link._source_action_ref) if rule_link._source_action_ref not in nodes: nodes.add(rule_link._source_action_ref) dot.node(rule_link._source_action_ref, rule_link._source_action_ref) if rule_link._dest_action_ref not in nodes: nodes.add(rule_link._dest_action_ref) dot.node(rule_link._dest_action_ref, rule_link._dest_action_ref) dot.edge(rule_link._source_action_ref, rule_link._dest_action_ref, constraint='true', label=rule_link._rule_ref) output_path = os.path.join(os.getcwd(), out_file) dot.format = 'png' dot.render(output_path)
def handle(self, *args, **options): """ Main command handler. """ dot = Digraph(name='Job Graph', comment='Job Graph', format='svg', engine='twopi') def status_to_color(status): return {Job.NEW: 'lightgray', Job.QUEUED: 'yellow', Job.RUNNING: 'lightblue', Job.COMPLETE: 'lightgreen', Job.ERROR: 'red'}[status] for job in Job.objects.all(): jobinfo = "%s Created: %s" % (str(job.table), job.created) dot.node('J-%d' % job.id, style='filled', color=status_to_color(job.status), tooltip=jobinfo) if job.parent: dot.edge('J-%d' % job.parent.id, 'J-%d' % job.id) if job.master: dot.edge('J-%d' % job.id, 'J-%d' % job.master.id, style='dashed') outfile = options['outfile'] if outfile.endswith('.svg'): outfile = outfile[:-4] dot.render(outfile) print "Rendered to %s.svg" % outfile
def display_variant_graph_as_SVG(graph,svg_output): # create new Digraph dot = Digraph(format="svg", graph_attr={'rankdir': 'LR'}) # add nodes counter = 0 mapping = {} for n in graph.graph.nodes(): counter += 1 mapping[n] = str(counter) # dot.node(str(n), nodedata["label"]) readings = ["<TR><TD ALIGN='LEFT'><B>" + n.label + "</B></TD><TD ALIGN='LEFT'><B>Sigla</B></TD></TR>"] reverseDict = defaultdict(list) for key,value in n.tokens.items(): reverseDict["".join(item.token_data["t"] for item in value)].append(key) for key,value in sorted(reverseDict.items()): reading = ("<TR><TD ALIGN='LEFT'><FONT FACE='Bukyvede'>{}</FONT></TD><TD ALIGN='LEFT'>{}</TD></TR>").format(key,', '.join(value)) readings.append(reading) dot.node(mapping[n], '<<TABLE CELLSPACING="0">' + "".join(readings) + '</TABLE>>',{'shape': 'box'}) # add edges for u,v,edgedata in graph.graph.edges_iter(data=True): dot.edge(str(mapping[u]), str(mapping[v]), edgedata["label"]) # render the dot graph to SVG # Note: this creates a file if svg_output: svg = dot.render(svg_output,'svg_output') else: svg = dot.render() # display using the IPython SVG module return display(SVG(svg))
def build_graph(args): stream = open(os.path.dirname(__file__)+"/diagram.yml", "r") conf_diagram = yaml.safe_load(stream) dia = Digraph('webdevops', filename=args.filename, format=args.format, directory=args.path) dia = apply_styles(dia,conf_diagram['diagram']['styles']) dia.body.append(r'label = "\n\nWebdevops Images\n at :%s"' % get_current_date() ) # Create subgraph for group, group_attr in conf_diagram['diagram']['groups'].items(): SUBGRAPH[group] = Digraph("cluster_"+group); SUBGRAPH[group].body.append(r'label = "%s"' % group_attr['name'] ) SUBGRAPH[group] = apply_styles(SUBGRAPH[group],group_attr['styles'] ) for image, base in CONTAINERS.items(): graph_image = get_graph(conf_diagram, dia, image) graph_base = get_graph(conf_diagram, dia, base) if "webdevops" in base: if graph_image == graph_base: graph_image.edge(base, image) else: graph_image.node(image) EDGES[image] = base if args.all : attach_tag(graph_image, image) else: graph_image.node(image) for name, subgraph in SUBGRAPH.items(): dia.subgraph(subgraph) for image, base in EDGES.items(): dia.edge(base, image) return dia
def build_visualization(): print('Building schema documentation...') # Load directory tree info bin_dir = os.path.dirname(os.path.realpath(__file__)) root_dir = os.path.join(os.path.abspath( os.path.join(bin_dir, os.pardir, os.pardir))) # Create graph dot = Digraph( comment="High level graph representation of GDC data model", format='pdf') dot.graph_attr['rankdir'] = 'RL' dot.node_attr['fillcolor'] = 'lightblue' dot.node_attr['style'] = 'filled' # Add nodes for node in m.Node.get_subclasses(): label = node.get_label() print label dot.node(label, label) # Add edges for edge in m.Edge.get_subclasses(): if edge.__dst_class__ == 'Case' and edge.label == 'relates_to': # Skip case cache edges continue src = m.Node.get_subclass_named(edge.__src_class__) dst = m.Node.get_subclass_named(edge.__dst_class__) dot.edge(src.get_label(), dst.get_label(), edge.get_label()) gv_path = os.path.join(root_dir, 'docs', 'viz', 'gdc_data_model.gv') dot.render(gv_path) print('graphviz output to {}'.format(gv_path))
def visualize_users(quora_data): dot = Digraph(comment='Users subgraph', engine='sfdp') seen_users = set() for document in quora_data: username = _get_username(document) # Checking if user was already added to the graph if username not in seen_users: # Adding user to graph as node dot.node(username, label=username) seen_users.add(username) for document in quora_data: username = _get_username(document) # Traversing over following users and adding edge for following in document[username]['following']: following_sanitized = _sanitize_username(following) if following_sanitized in seen_users: dot.edge(username, following_sanitized) # Traversing over user's followers for follower in document[username]['followers']: follower_sanitized = _sanitize_username(follower) if follower_sanitized in seen_users: dot.edge(follower_sanitized, username) dot = _apply_styles(dot, styles) # print dot.source dot.render(os.path.join('images', 'users.gv'), view=True)
def digraph(self, yangfile=None): """ Create a graph object """ if yangfile is None: return None modulename = yangfile.split('.yang')[0] if '@' in modulename: modulename = modulename.split('@')[0] module = self.modules.get(modulename, None) graph = Digraph(comment=modulename, format='jpeg') graph.node(modulename) for imp in module.imports: graph.node(imp) graph.edge(imp, modulename) for dep in module.depends: graph.node(dep) graph.edge(modulename, dep) return self._apply_style(graph)
def render_graph(graph): dot = Digraph('directed_graph') for node in graph: dot.node(node.name) for dependency in node.requires: dot.edge(node.name, dependency.name) dot.render()
def draw_path_hybrid(fcg_path, exe_path): "draw execution path on static function call graph" dot = Digraph(".") time_stamp = str(time.time()) "filter out duplication" edges_pool = [] #nodes_pool = [] "draw execution path" for i in exe_path: path = exe_path[i] for node in path: dot.node(node, num2text[node], color="red") edges = nodes2edges(path) for edge in edges: edge_sign = edge["src"]+edge["dst"] if edge_sign not in edges_pool: dot.edge(edge["src"], edge["dst"], color="red") edges_pool.append(edge_sign) "draw static function call graph" for i in fcg_path: path = fcg_path[i] for node in path: dot.node(node, num2text[node]) edges = nodes2edges(path) for edge in edges: edge_sign = edge["src"]+edge["dst"] if edge_sign not in edges_pool: dot.edge(edge["src"], edge["dst"]) edges_pool.append(edge_sign) dot.render('cfg/'+time_stamp+'.gv', view=True)
def apps_and_browser(): G = Digraph(name='Apps and Browser', node_attr={'shape': 'plaintext'}) G.node('webview_framework', label="""< <TABLE> <TR> <TD ROWSPAN="0" COLSPAN="3"> <TABLE> <TR> <TD>Default Browser</TD> </TR> <TR> <TD ROWSPAN="2" PORT="webview">Android Framework<BR/>WebView API</TD> </TR> </TABLE> </TD> <TD ROWSPAN="1" COLSPAN="3"> <TABLE BGCOLOR="grey"> <TR> <TD>Android 4.0</TD> </TR> <TR> <TD>Android 4.1~4.3</TD> </TR> <TR> <TD>Android 4.4+</TD> </TR> </TABLE> </TD> </TR> </TABLE>>""", shape="box") G.node('Apps', label="""< <TABLE> <TR> <TD>Apps</TD> </TR> </TABLE>>""", shape="box") G.edge("Apps", "webview_framework:webview", color="blue") return G
def build_graph(self): """ Returns ------- graphiz.Digraph It contains nodes and links corresponding to self.steps """ g = Digraph('test', format='svg',graph_attr={'bgcolor':'lightgrey'}) #Create nodes for step in self.steps: str_shape = 'octagon' if step.type == StagerRep.CONSUMER: str_shape = 'doubleoctagon' if step.type == StagerRep.PRODUCER: str_shape = 'Mdiamond' name = step.name.split('$$processus')[0] name = self.format_name(step.name.split('$$processus')[0]) if step.running > 0: g.node(name,color='lightblue', style='filled',shape=str_shape,area='0.5') else: g.node(name,shape=str_shape,color='blue',area='0.5') #Create edges for step in self.steps: step_name = self.format_name(step.name.split('$$processus')[0]) for next_step_name in step.next_steps: next_step = self.get_step_by_name(next_step_name.split('$$processus')[0]) if next_step: next_step_name_formated = self.format_name(next_step.name.split('$$processus')[0]) g.edge(step_name, next_step_name_formated) g.edge_attr.update(arrowhead='empty', arrowsize='1',color='purple') return g
def pcdebug_mobilewebsite(): G = Digraph(name='website on pc debuging', node_attr={'shape': 'plaintext'}) G.node('pc_chrome_remote', label="""< <TABLE> <TR> <TD> Remote Debug Tools </TD> </TR> <TR> <TD> Chrome </TD> </TR> <TR> <TD> PC </TD> </TR> </TABLE>>""", shape="box") G.node('mobile_web', label="""< <TABLE> <TR> <TD> Mobile Browser </TD> <TD BGCOLOR="grey"> <TABLE ROWSPAN="1" BGCOLOR="grey"> <TR> <TD> JavaScript </TD> </TR> <TR> <TD> CSS </TD> </TR> <TR> <TD> HTML </TD> </TR> </TABLE> </TD> </TR> </TABLE>>""", shape="box") G.edge("mobile_web", "pc_chrome_remote", label="webdriver", color="blue") return G
def hand_mobiledebug_mobileapp(): G = Digraph(name='website on mobile hand debuging', node_attr={'shape': 'plaintext'}) G.node('mobile_app', label="""< <TABLE> <TR> <TD> <TABLE> <TR> <TD> Webview </TD> <TD> <TABLE ROWSPAN="1" BGCOLOR="grey"> <TR> <TD> JavaScript </TD> </TR> <TR> <TD> CSS </TD> </TR> <TR> <TD> HTML </TD> </TR> </TABLE> </TD> </TR> </TABLE> </TD> <TD COLSPAN="3">Native</TD> </TR> <TR> <TD COLSPAN="6">Apps</TD> </TR> </TABLE>>""", shape="box") G.node('automatic_real_devices', label="""< <TABLE> <TR> <TD> Android SDK </TD></TR> <TR> <TD> Hand </TD></TR> </TABLE>>""", shape="box") G.edge("automatic_real_devices", "mobile_app", color="blue") return G
def generate_dot(nicknames, relations, name, format, program, directed=False): """Create dot graph representations.""" # Create graph. dot_attrs = { 'name': name, 'format': format, 'engine': program, } if directed: dot = Digraph(**dot_attrs) else: dot = Graph(**dot_attrs) # Create nodes. for nickname in nicknames: dot.node(nickname, label=nickname) # Create edges. max_count = float(max(rel[2] for rel in relations)) max_width = 4 for nickname1, nickname2, count in sorted(relations, key=lambda x: x[0]): width = (count / max_count * max_width) + 1 dot.edge(nickname1, nickname2, style='setlinewidth(%d)' % width) return dot
def render(self, filename, comment, render="content"): dot = Digraph(comment=comment,edge_attr={'len': '6', 'weight':'0.00001'}) dot.engine = 'dot' # add nodes to dot graph for node_key in self.nodes.keys(): node_content = "nil" # either use id or content to mark graph nodes if render == "id": node_content = str(self.nodes[node_key].id) elif render == "content": if len(self.nodes[node_key].content) > 0: node_content = ', '.join(str(x) for x in self.nodes[node_key].content) else: node_content = str(self.nodes[node_key].id) + ":" if len(self.nodes[node_key].content) > 0: node_content += ', '.join(str(x) for x in self.nodes[node_key].content) + ":" else: node_content += "nil:" if len(self.nodes[node_key].meta) > 0: node_content += self.nodes[node_key].meta else: node_content += "nil" dot.node(str(self.nodes[node_key].id), node_content) #add edges to dot graph for edge_key in self.edges.keys(): for dest_node in self.edges[edge_key]: dot.edge(str(edge_key), str(dest_node)) if not os.path.exists("graph"): os.makedirs("graph") dot.render("graph/" + filename + ".gv")
def proc(file_path): fp = open(file_path, 'r') cont = fp.read() fp.close() cont_dict = json.loads(cont) calls = cont_dict["calls"] calls_filter = [] for i in calls: if i["category"] == "system": pass else: calls_filter.append(i["api"]) dot = Digraph(comment="cuckoolog") last = None j = 0 edges = set() for i in calls_filter: if last == None: last = i else: if last+i in edges: pass else: edges.add(last+i) dot.edge(last,i,label=str(j)) j += 1 last = i dot.render("cfg/"+file_path+'.gv', view=False)
def draw_graph(debt_graph: Graph, graph_name: str, open_file: bool = True) -> None: """ Draw the graph in a pdf file or print it to the console (if graphviz isn't installed) :param open_file: :param graph_name: :param debt_graph: """ print('%s: ' % graph_name, debt_graph) try: from graphviz import backend, Digraph viz = Digraph(graph_name) #, engine='circo') # Use this engine if the graph is hard to read viz.node_attr.update(color='orangered', shape='box', style='rounded', penwidth='2') viz.edge_attr.update(color='grey') for participant in debt_graph: if debt_graph.get_node_edges(participant): for debt in debt_graph.get_node_edges(participant): if debt[1] >= MIN_DISPLAY_VALUE: viz.edge(participant, debt[0], xlabel='{:.2f}'.format(debt[1])) print('Render saved as %s.gv.pdf' % graph_name) viz.view() if open_file else viz.render() except ImportError: print('(Please install graphviz for a much cleaner visualization of the graph)') except backend.ExecutableNotFound: print('(The python wrapper for graphviz is installed but not the package itself)')
def drawDeBruijn(kMere, k): deBruijn = Digraph(comment='de Bruijn graph for given reads', format='png') deBruijn.graph_attr['rankdir'] = 'UD' # generate k-1 mere kMinus1 = [] for mer in kMere: if mer[:-1] not in kMinus1: kMinus1.append(mer[:-1]) if mer[1:] not in kMinus1: kMinus1.append(mer[1:]) # insert nodes for mer in kMinus1: deBruijn.node(mer, mer) # insert edges for mer1 in kMinus1: for mer2 in kMinus1: if mer1 == mer2: continue for kMer in kMere: if ((mer1 == kMer[:-1]) and (mer2 == kMer[1:])): deBruijn.edge(mer1,mer2) # print graph deBruijn.render(filename="deBruijnGraph_"+str(k)+"mere")
def GraphToDigraph(G): DG = Digraph(comment = 'PO') for v in G.vertices(): DG.node(str(v),G.vertex_label(v)) for e in G.edges(): DG.edge(str(e[0]),str(e[1])) DG.render('graph.gv',view=True)
def parse_build_file(build_file_path, render_format): root = ElementTree.parse(build_file_path) target_deps = {} for t in root.iter('target'): if 'depends' in t.attrib: deps = [d.strip() for d in t.attrib['depends'].split(',')] else: deps = [] name = t.attrib['name'] target_deps[name] = deps if render_format: dot = Digraph(build_file_path, format=render_format) for t in target_deps: print print_target(t, target_deps) if render_format: dot.node(t, t) for d in target_deps[t]: dot.edge(t, d) if render_format: dot.render(filename=os.path.splitext(build_file_path)[0], directory=os.path.dirname(build_file_path))
def dumpgraph(request,descl, comment,rankdir="RL", student=None,ALL=True): dot = Digraph(comment=comment) dot.format='svg' dot.graph_attr['rankdir'] = rankdir if student != None: student = get_object_or_404(Student,student_id=student) s=set() for l in descl: s.add(l.ascendant) s.add(l.descendant) for x in s: if student != None and student.knowsConcept(x.name) : cc = student.conceptlevel(x.name) l= ['red','green','orange','yellow'] cc=l[min(cc,len(l)-1)] dot.node(x.name,URL=x.makeUrl(),color=cc,style="filled",shape="box") else: if ALL : dot.node(x.name,URL=x.makeUrl(),color="red",style="filled",shape="box") for l in descl: if ALL: dot.edge(l.descendant.name,l.ascendant.name) else: if student != None and student.knowsConcept(l.descendant.name) and student.knowsConcept(l.ascendant.name): dot.edge(l.descendant.name,l.ascendant.name) dot.render('concept/templates/concept/graph')
def cli(url, include): token = zign.api.get_existing_token('test') access_token = token['access_token'] r = requests.get(url + '/accounts', headers={'Authorization': 'Bearer {}'.format(access_token)}) accounts = r.json() def get_label(account_region): parts = account_region.split('/') name = accounts.get(parts[0], {}).get('name', parts[0]) return name r = requests.get(url + '/account-connections', params={'include': include}, headers={'Authorization': 'Bearer {}'.format(access_token)}, timeout=180) data = r.json() max_score = 0 for dest, sources in data.items(): for row in sources: if row['score'] > max_score: max_score = row['score'] graph = Digraph(comment='Account Graph', engine='circo', format='svg') for dest, sources in data.items(): graph.node(dest, label=get_label(dest), style='filled') for row in sources: source = row['source'] graph.node(source, label=get_label(source), style='filled') graph.edge(source, dest, weight=str(int(row['score'])), penwidth=str(max(0.5, 5 * row['score']/max_score))) graph.render('account-graph')
class Layout(object): """implementation of rudimentary maze layout using GraphViz""" def __init__(self, grid, **kwargs): """constructor The layout uses a digraph object as arcs are directed. An arrowless arc is used to represent two-way passages. The rendering engine should be set here, for example: foo = Layout(grid, engine='fdp') The default layout engine is 'dot'. The rendering engine can be changed, for example: foo = Layout(grid) foo.dot.engine('fdp') """ self.grid = grid if 'comment' not in kwargs: kwargs['comment'] = 'GraphViz Layout' if 'filename' not in kwargs: kwargs['filename'] = 'demos/maze.gv' self.filename = kwargs['filename'] if 'format' not in kwargs: kwargs['format'] = 'png' self.rendername = self.filename + '.' + kwargs['format'] if 'name' not in kwargs: kwargs['name'] = grid.name self.dot = Digraph(**kwargs) def draw_cell(self, cell): """draw a cell""" kwargs = cell.kwargs['graphviz'] if 'graphviz' in cell.kwargs \ else {} self.dot.node(cell.name, **kwargs) def draw_passage(self, cell, nbr, **kwargs): """draw a passage""" self.dot.edge(cell.name, nbr.name, **kwargs) def set_attribute(self, name, **kwargs): """set attributes""" if kwargs: self.dot.attr(name, **kwargs) def draw(self, cellargs={}, passageargs={}): """draw the maze""" visited = {} self.set_attribute('node', **cellargs) self.set_attribute('edge', **passageargs) # define the cells for cell in self.grid.each(): self.draw_cell(cell) # define the arcs and edges for cell in self.grid.each(): for nbr in cell.arcs: if cell in nbr.arcs: # two-way passage if nbr not in visited: self.draw_passage(cell, nbr, arrowhead='none') else: self.draw_passage(cell, nbr) visited[cell] = 1 def set_square_cells(self): """configuration for a rectangular maze The preferred rending engines for 'pos' are 'fdp' and 'neato'. """ for cell in self.grid.each(): if 'graphviz' not in cell.kwargs: cell.kwargs['graphviz'] = {} cell.kwargs['graphviz']['pos'] = '%f,%f!' % cell.position cell.kwargs['graphviz']['label'] = '' cell.kwargs['graphviz']['shape'] = 'box' def set_cell(self, cell, **kwargs): """configuration for a particular cell""" if 'graphviz' not in cell.kwargs: cell.kwargs['graphviz'] = {} for name in kwargs: if kwargs[name] is None: del cell.kwargs['graphviz'][name] else: cell.kwargs['graphviz'][name] = kwargs[name] def render(self): """render the output""" self.dot.render() print('saved to %s' % self.filename) print('rendered to %s' % self.rendername)
print('\n## Synopsis') # ## Collecting Crashes from Multiple Fuzzers if __name__ == "__main__": print('\n## Collecting Crashes from Multiple Fuzzers') if __name__ == "__main__": from graphviz import Digraph if __name__ == "__main__": g = Digraph() server = 'Crash Server' g.node('Crash Database', shape='cylinder') for i in range(1, 7): g.edge('Fuzzer ' + repr(i), server) g.edge(server, 'Crash Database') g # ## Running a Crash Server if __name__ == "__main__": print('\n## Running a Crash Server') # ### Setting up the Server if __name__ == "__main__": print('\n### Setting up the Server') import os import shutil
def grafo_DOT(name, outfichero, GOs, color): """ Funcion que dibuja el grafo con los nodos de una muestra """ # Cabecera g = Digraph(str(name), filename=outfichero) g.attr(rankdir='BT') g.attr('node', fontname='Arial', fontsize='12', shape='box', \ style='rounded,filled', color="/%s/9" % (color)) # Definimos rangos de frecuencias para colorear rango1 = 5 rango2 = 7 rango3 = 10 rango4 = 15 rango5 = 20 rango6 = 30 rango7 = 50 rango8 = 70 rango9 = 100 # Definimos los nodos for nodo in name.nodes(data=True): if nodo[1]["frec"] <= rango1: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' \ + str(round(nodo[1]["frec"], 2)), fillcolor="/%s/1" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/1" % (color)) elif nodo[1]["frec"] <= rango2: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/2" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/2" % (color)) elif nodo[1]["frec"] <= rango3: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ tr(round(nodo[1]["frec"], 2)), fillcolor="/%s/3" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/3" % (color)) elif nodo[1]["frec"] <= rango4: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/4" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/4" % (color)) elif nodo[1]["frec"] <= rango5: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/5" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/5" % (color)) elif nodo[1]["frec"] <= rango6: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/6" % (color), shape="diamond") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/6" % (color)) elif nodo[1]["frec"] <= rango7: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/7" % (color), shape="diamond", fontcolor="white") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/7" % (color), fontcolor="white") elif nodo[1]["frec"] <= rango8: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/8" % (color), shape="diamond", fontcolor="white") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/8" % (color), fontcolor="white") elif nodo[1]["frec"] <= rango9: if nodo[0] in GOs: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="/%s/9" % (color), shape="diamond", fontcolor="white") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ tr(round(nodo[1]["frec"], 2)), fillcolor="/%s/9" % (color), fontcolor="white") else: g.node(nodo[0].replace(":", "_"), label= nodo[0] + '\n' + id_to_name[nodo[0]].replace(" ", "\ ") + '\n' + \ str(round(nodo[1]["frec"], 2)), fillcolor="red") # Definimos los ejes for edge in name.edges(keys=True): g.edge(edge[0].replace(":", "_"), edge[1].replace(":", "_"), label=edge[2]) # Representamos el grafo y guardamos el fichero en formato DOT (si hay "/n" en el label no nos sirve el fichero) g.render()
class MarkovChain: def __init__(self, states=None, obs=None, obs_p=None): '''Discrete Markov Chain. Parameters ---------- states : array_like or numpy ndarray State names list. obs : array_like or numpy ndarray Observed transition frequency matrix. obs_p : array_like or numpy ndarray Observed transition probability matrix. ''' self.states = np.array(states) self.observed_matrix = np.array(obs) self.observed_p_matrix = np.array(obs_p) def _transition_matrix(self, seq=None, states=None): '''Calculate a transition frequency matrix. Parameters ---------- seq : str or array_like A string or an array-like object exposing the array interface and containing strings or ints. states : numpy ndarray Array containing a list of states. Returns ------- matrix : numpy ndarray Transition frequency matrix. ''' seql = self.seq if seq is None else np.array(list(seq)) if states is None: states = self.states matrix = np.zeros((len(states), len(states))) for x, y in product(range(len(states)), repeat=2): xid = np.argwhere(seql == states[x]).flatten() yid = xid + 1 yid = yid[yid < len(seql)] s = np.count_nonzero(seql[yid] == states[y]) matrix[x, y] = s return matrix def n_order_matrix(self, mat=None, order=2): '''Create Nth order transition probability matrix. Parameters ---------- mat : numpy ndarray Observed transition probability matrix. order : int, optional Order of transition probability matrix to return. Default is 2. Returns ------- x : numpy ndarray Nth order transition probability matrix. ''' return nl.matrix_power( self.observed_p_matrix if mat is None else mat, order ) def prob_to_freq_matrix(self, mat=None, row_totals=None): '''Calculate a transition frequency matrix given a transition probability matrix and row totals. This method is meant to be used to calculate a frequency matrix for a Nth order transition probability matrix. Parameters ---------- mat : numpy ndarray Transition probability matrix. row_totals : numpy ndarray Row totals of transition frequency matrix. Returns ------- x : numpy ndarray Transition frequency matrix. ''' _mat = self.observed_p_matrix if mat is None else mat _rt = self._obs_row_totals if row_totals is None else row_totals return _mat * _rt def from_data(self, seq): '''Infer a Markov chain from data. States, frequency and probability matrices are automatically calculated and assigned to as class attributes. Parameters ---------- seq : numpy ndarray, array_like, str Sequence of events. A string or an array-like object exposing the array interface and containing strings or ints. Returns ------- MarkovChain : object Trained MarkovChain class instance. ''' # states list self.seq = np.array(list(seq)) self.states = np.unique(list(seq)) # observed transition frequency matrix self.observed_matrix = self._transition_matrix(seq, self.states) self._obs_row_totals = np.sum(self.observed_matrix, axis=1) # observed transition probability matrix self.observed_p_matrix = np.nan_to_num( self.observed_matrix / self._obs_row_totals[:, None] ) # filling in a row containing zeros with uniform p values uniform_p = 1 / len(self.states) zero_row = np.argwhere(self.observed_p_matrix.sum(1) == 0).ravel() self.observed_p_matrix[zero_row, :] = uniform_p # expected transition frequency matrix self.expected_matrix = ss.contingency.expected_freq( self.observed_matrix) return self def chisquare(self, obs=None, exp=None, **kwargs): '''Wrapper function for carrying out a chi-squared test using `scipy.stats.chisquare` method. Parameters ---------- obs : numpy ndarray Observed transition frequency matrix. exp : numpy ndarray Expected transition frequency matrix. kwargs : optional Keyword arguments passed to `scipy.stats.chisquare` method. Returns ------- chisq : float or numpy ndarray Chi-squared test statistic. p : float or numpy ndarray P value of the test. ''' _obs = self.observed_matrix if obs is None else obs _exp = self.expected_matrix if exp is None else exp return ss.chisquare(f_obs=_obs, f_exp=_exp, **kwargs) def graph_make(self, *args, **kwargs): '''Make a directed graph of a Markov chain using `graphviz`. Parameters ---------- args : optional Passed to the underlying `graphviz.Digraph` method. kwargs : optional Passed to the underlying `graphviz.Digraph` method. Returns ------- graph : graphviz.dot.Digraph Digraph object with its own methods. Note ---- `graphviz.dot.Digraph.render` method should be used to output a file. ''' self.graph = Digraph(*args, **kwargs) ids = range(len(self.states)) edges = product(ids, ids) for edge in edges: v1 = edge[0] v2 = edge[1] s1 = self.states[v1] s2 = self.states[v2] p = str(np.round(self.observed_p_matrix[v1, v2], 2)) self.graph.edge(s1, s2, label=p, weight=p) return self.graph def simulate( self, n, tf=None, states=None, start=None, ret='both', seed=None ): '''Markov chain simulation based on `scipy.stats.multinomial`. Parameters ---------- n : int Number of states to simulate. tf : numpy ndarray Transition frequency matrix. If None, `self.observed_matrix` attribute is used. states : array_like List of state names. If None, `self.states` attribute is used. start : {None, 'random', str, or int}, optional Event to begin with. If `int`, choosed a state by index. If `str`, choosed by a state name. If 'random', take a random state. If `None`, start with an event with maximum probability. ret : {'indices', 'states', 'both'} Return state indices if 'indices' is passed. If 'states' is passed, return state names. Return both if 'both' is passed. seed : {None, array_like of int} Random states used to draw random variates. Passed to `scipy.stats.multinomial` method. Returns ------- x : numpy ndarray Sequence of state indices. y : numpy ndarray, optional Sequence of state names. Returned if `return` arg is set to 'states' or 'both'. ''' # matrices init if tf is None: tf = self.observed_matrix fp = self.observed_p_matrix else: fp = tf / tf.sum(axis=1)[:, None] # states init if states is None: states = self.states if not isinstance(states, np.ndarray): states = np.array(states) # choose a state to begin with # `_start` is always an index of state if start is None: row_totals = tf.sum(axis=1) _start = np.argmax(row_totals / tf.sum()) elif isinstance(start, int): _start = start if start < len(states) else len(states)-1 elif isinstance(start, str): _start = np.argwhere(states == start) elif start == 'random': _start = np.random.randint(0, len(states)) # simulated sequence init seq = np.zeros(n, dtype=np.int) seq[0] = _start # random seeds r_states = np.random.randint(0, n, n) if seed is None else seed # simulation procedure for i in range(1, n): _ps = fp[seq[i-1]] _sample = np.argmax( ss.multinomial.rvs(1, _ps, 1, random_state=r_states[i]) ) seq[i] = _sample if ret == 'indices': return seq elif ret == 'states': return states[seq] else: return seq, states[seq]
system_time = datetime.now().strftime("%Y-%m-%d %H-%M-%S") if __name__ == "__main__": for eng in ("dot", "neato", "twopi", "circo", "fdp", "sfdp"): dot = Digraph(comment=system_time + '_' + eng) f = open(file, "r") graph = [] used = [] for index, line in enumerate(f): data = line.split() if len(data) == 0: continue if data[1] < data[0]: data[0], data[1] = data[1], data[0] if (data[0], data[1]) not in used: data = (data[0], data[1], data[2]) used.append((data[0], data[1])) graph.append(data) f.close() for data in graph: dot.edge(data[0], data[1], weight=data[2], label=data[2], color="black", arrowhead="none", arrowtail="none") src = Source(dot.source) filename = system_time + '_' + eng + '.gv' src.render(filename) render(eng, 'svg', filename)
def get_cluster_graph(self, engine="fdp", graph_attr=None, node_attr=None, edge_attr=None): """ Generate directory graph in the DOT language. Directories are shown as clusters .. warning:: This function scans the entire directory tree starting from top so the resulting graph can be really big. Args: engine: Layout command used. ['dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage'] graph_attr: Mapping of (attribute, value) pairs for the graph. node_attr: Mapping of (attribute, value) pairs set for all nodes. edge_attr: Mapping of (attribute, value) pairs set for all edges. Returns: graphviz.Digraph <https://graphviz.readthedocs.io/en/stable/api.html#digraph> """ # https://www.graphviz.org/doc/info/ from graphviz import Digraph g = Digraph( "directory", #filename="flow_%s.gv" % os.path.basename(self.relworkdir), engine=engine) # if engine == "automatic" else engine) # Set graph attributes. #g.attr(label="%s@%s" % (self.__class__.__name__, self.relworkdir)) g.attr(label=self.top) #g.attr(fontcolor="white", bgcolor='purple:pink') #g.attr(rankdir="LR", pagedir="BL") #g.attr(constraint="false", pack="true", packMode="clust") g.node_attr.update(color='lightblue2', style='filled') #g.node_attr.update(ranksep='equally') # Add input attributes. if graph_attr is not None: fg.graph_attr.update(**graph_attr) if node_attr is not None: fg.node_attr.update(**node_attr) if edge_attr is not None: fg.edge_attr.update(**edge_attr) def node_kwargs(path): return dict( #shape="circle", #shape="none", #shape="plaintext", #shape="point", shape="record", #color=node.color_hex, fontsize="8.0", label=os.path.basename(path), ) edge_kwargs = dict(arrowType="vee", style="solid", minlen="1") cluster_kwargs = dict(rankdir="LR", pagedir="BL", style="rounded", bgcolor="azure2") # TODO: Write other method without clusters if not walk. exclude_top_node = False for root, dirs, files in os.walk(self.top): if exclude_top_node and root == self.top: continue cluster_name = "cluster_%s" % root #print("root", root, cluster_name, "dirs", dirs, "files", files, sep="\n") with g.subgraph(name=cluster_name) as d: d.attr(**cluster_kwargs) d.attr(rank="source" if (files or dirs) else "sink") d.attr(label=os.path.basename(root)) for f in files: filepath = os.path.join(root, f) d.node(filepath, **node_kwargs(filepath)) if os.path.islink(filepath): # Follow the link and use the relpath wrt link as label. realp = os.path.realpath(filepath) realp = os.path.relpath(realp, filepath) #realp = os.path.relpath(realp, self.top) #print(filepath, realp) #g.node(realp, **node_kwargs(realp)) g.edge(filepath, realp, **edge_kwargs) for dirname in dirs: dirpath = os.path.join(root, dirname) #head, basename = os.path.split(dirpath) new_cluster_name = "cluster_%s" % dirpath #rank = "source" if os.listdir(dirpath) else "sink" #g.node(dirpath, rank=rank, **node_kwargs(dirpath)) #g.edge(dirpath, new_cluster_name, **edge_kwargs) #d.edge(cluster_name, new_cluster_name, minlen="2", **edge_kwargs) d.edge(cluster_name, new_cluster_name, **edge_kwargs) return g
define_nodes(c,nodes,col,shortlabel) else: # No grouping define_nodes(dot, nodes, col,shortlabel) # One edge for each unique command sender,receiver listing all commands in label dot.attr('edge',fontcolor=cmdcol) dot.attr('edge',color=cmdcol) for pair,cmds in cmd_pairs.items(): sender,receiver = pair.split(',') if commandlabels: cmd_str = '\n'.join(sorted(cmds)) else: cmd_str = None dot.edge(sender,receiver,label=cmd_str) # One edge showing all commands nobody sends to each component, # using dummy nodes as the source if missingcommands: dot.attr('edge',fontcolor=nocmdcol) dot.attr('edge',color=nocmdcol) for p,cmds in cmd_no_sender.items(): if commandlabels: cmd_str = '\n'.join(cmds) else: cmd_str = None dot.edge(p+suffix_nocmd,p,label=cmd_str) # One edge for each unique event publisher,receiver listing all items as the label dot.attr('edge',fontcolor=evcol)
class Diagram: __directions = ("TB", "BT", "LR", "RL") __outformats = ("png", "jpg", "svg", "pdf") # fmt: off _default_graph_attrs = { "pad": "2.0", "splines": "ortho", "nodesep": "0.60", "ranksep": "0.75", "fontname": "Sans-Serif", "fontsize": "15", "fontcolor": "#2D3436", } _default_node_attrs = { "shape": "box", "style": "rounded", "fixedsize": "true", "width": "1.4", "height": "1.4", "labelloc": "b", # imagepos attribute is not backward compatible # "imagepos": "tc", "imagescale": "true", "fontname": "Sans-Serif", "fontsize": "13", "fontcolor": "#2D3436", } _default_edge_attrs = { "color": "#7B8894", } # fmt: on # TODO: Label position option # TODO: Save directory option (filename + directory?) def __init__( self, name: str = "", filename: str = "", direction: str = "LR", outformat: str = "png", show: bool = True, graph_attr: dict = {}, node_attr: dict = {}, edge_attr: dict = {}, ): """Diagram represents a global diagrams context. :param name: Diagram name. It will be used for output filename if the filename isn't given. :param filename: The output filename, without the extension (.png). If not given, it will be generated from the name. :param direction: Data flow direction. Default is 'left to right'. :param outformat: Output file format. Default is 'png'. :param show: Open generated image after save if true, just only save otherwise. :param graph_attr: Provide graph_attr dot config attributes. :param node_attr: Provide node_attr dot config attributes. :param edge_attr: Provide edge_attr dot config attributes. """ self.name = name if not filename: filename = "_".join(self.name.split()).lower() self.filename = filename self.dot = Digraph(self.name, filename=self.filename) # Set attributes. for k, v in self._default_graph_attrs.items(): self.dot.graph_attr[k] = v self.dot.graph_attr["label"] = self.name for k, v in self._default_node_attrs.items(): self.dot.node_attr[k] = v for k, v in self._default_edge_attrs.items(): self.dot.edge_attr[k] = v if not self._validate_direction(direction): raise ValueError(f'"{direction}" is not a valid direction') self.dot.graph_attr["rankdir"] = direction if not self._validate_outformat(outformat): raise ValueError(f'"{outformat}" is not a valid output format') self.outformat = outformat # Merge passed in attributes self.dot.graph_attr.update(graph_attr) self.dot.node_attr.update(node_attr) self.dot.edge_attr.update(edge_attr) self.show = show def __str__(self) -> str: return str(self.dot) def __enter__(self): setdiagram(self) return self def __exit__(self, exc_type, exc_value, traceback): self.render() # Remove the graphviz file leaving only the image. os.remove(self.filename) setdiagram(None) def _repr_png_(self): return self.dot.pipe(format="png") def _validate_direction(self, direction: str) -> bool: direction = direction.upper() for v in self.__directions: if v == direction: return True return False def _validate_outformat(self, outformat: str) -> bool: outformat = outformat.lower() for v in self.__outformats: if v == outformat: return True return False def node(self, hashid: str, label: str, **attrs) -> None: """Create a new node.""" self.dot.node(hashid, label=label, **attrs) def connect(self, node: "Node", node2: "Node", edge: "Edge") -> None: """Connect the two Nodes.""" self.dot.edge(node.hashid, node2.hashid, **edge.attrs) def subgraph(self, dot: Digraph) -> None: """Create a subgraph for clustering""" self.dot.subgraph(dot) def render(self) -> None: self.dot.render(format=self.outformat, view=self.show)
# -*- coding: utf-8 -*- """ Created on Fri Sep 29 15:27:38 2017 @author: User """ from graphviz import Digraph dot = Digraph(comment='Проезд ПВП МСК-> РнД') dot.node('A', 'ПВП1') dot.node('B', 'ПВП2') dot.node('C', 'ПВП3') dot.node('D', 'ПВП4') dot.edges(['AB', 'BC', 'CD']) dot.edge('A', 'C', color='Red', label='135 КМ') dot.edge('A', 'D', color='Red') dot.attr(color='Green') print(dot.source) dot.render('C:\\py_tests\\round-table.gv.pdf', view=True) #dot.render('C:\\py_tests\\round-table.gv', view=True) # doctest: +SKIP 'C:\\py_tests\\round-table.gv.pdf'
def inputToRawTable(): #Creating a class for a diagram dot = Digraph() print( 'Are you going to enter a table for DFA or NFA? Please type DFA or NFA.' ) typeOfFA = input() if (typeOfFA != 'DFA' and typeOfFA != 'NFA'): print('Incorrect input. Exiting program.') exit() table = [] print( 'Please enter the alphabet symbols in your alphabet separated by white spaces.' ) alphabetInput = input() alphabetInput = alphabetInput.split() #Creating an array of alphabet symbols alphabetArray = [] numOfAlphSymb = len(alphabetInput) for i in range(numOfAlphSymb): alphabetArray.append(alphabetInput[i]) #Creating the first row of the table consisting of one white space and all the alphabet symbols. firstRow = [] firstRow.append(' ') for i in range(numOfAlphSymb): firstRow.append(alphabetInput[i]) table.append(firstRow) #Prompting the user to enter all the states print( 'Please enter the states separated by white spaces. They are your table row names.' ) statesInput = input() statesInput = statesInput.split() numOfInputStates = len(statesInput) #Prompting the user to enter the start state print('Please enter the start state out of the list you entered.') startState = input() #Prompting the user to enter the accepting state / states print( 'Please enter the accepting state or states out of the list you entered.' ) print( 'If there are several accepting states, separate them by white spaces.' ) acceptingStates = input() #For each state, creating a node in the diagram and a row in the table updatedStatesInput = [] for i in range(numOfInputStates): if ((startState == statesInput[i]) and (startState in acceptingStates)): dot.node('Fake', 'q', style='invisible') dot.edge('Fake', startState, style='bold') dot.node(startState, startState, root='true', shape='doublecircle') updatedStatesInput.append('->*' + statesInput[i]) elif (startState == statesInput[i]): dot.node('Fake', 'q', style='invisible') dot.edge('Fake', startState, style='bold') dot.node(startState, startState, root='true') updatedStatesInput.append('->' + statesInput[i]) elif (statesInput[i] in acceptingStates): dot.node(statesInput[i], statesInput[i], shape='doublecircle') updatedStatesInput.append('*' + statesInput[i]) else: dot.node(statesInput[i], statesInput[i]) updatedStatesInput.append(statesInput[i]) #Prompting the user to fill out the table. #The user is asked to fill out one cell at a time. # In parallel, the edges of the graph and their labels are created on the diagram. for i in range(numOfInputStates): print('Entering input for row ' + str(updatedStatesInput[i]) + '.') localList = [] localList.append(updatedStatesInput[i]) for j in range(numOfAlphSymb): print('Please enter an input for alphabetical symbol ' + str(alphabetArray[j]) + '.') print( 'If there are several states for one cell, separate them by commas.' ) print('If there are no states in the cell, indicate it by 0') localInput = input() if (typeOfFA == 'DFA'): localList.append(localInput) else: localList.append('{' + localInput + '}') if (',' in localInput): state_list = [] state_list = localInput.split(',') for k in range(len(state_list)): dot.edge(str(statesInput[i]), state_list[k], label=str(alphabetArray[j])) elif (localInput != '0'): dot.edge(str(statesInput[i]), localInput, label=str(alphabetArray[j])) table.append(localList) #Showing the entered information to the user in a tabular form. #The user is prompted to answer "Yes" if the table is correct. t = Texttable() t.add_rows(table) print(t.draw()) print( 'Here is the table constructed based on your input. Is it correct? Type Yes or No.' ) answer = input() if (answer == 'Yes'): print("The diagram has been output as a PDF file.") else: print('Table incorrect. Exiting program.') exit() #Outputting the FA diagram using the render() method return dot.render('FA_diagram.gv', view=True) # doctest: +SKIP
from datetime import datetime import sys file = sys.argv[1] system_time = datetime.now().strftime("%Y-%m-%d %H-%M-%S") if __name__ == "__main__": for eng in ("dot", "neato", "twopi", "circo", "fdp", "sfdp"): dot = Digraph(comment=system_time + '_' + eng) f = open(file, "r") graph = [] used = [] for index, line in enumerate(f): data = line.split() if data[1] < data[0]: data[0], data[1] = data[1], data[0] if (data[0], data[1]) not in used: data = (data[0], data[1], data[2]) used.append((data[0], data[1])) graph.append(data) f.close() for data in graph: dot.edge(data[0], data[1], weight=data[2], arrowhead="none", arrowtail="none") src = Source(dot.source) filename = system_time + '_' + eng + '.gv' src.render(filename) render(eng, 'svg', filename)
def plot_graph( mdp, graph_size='10,10', s_node_size='1,5', a_node_size='0,5', rankdir='LR', ): """ Function for pretty drawing MDP graph with graphviz library. Requirements: graphviz : https://www.graphviz.org/ for ubuntu users: sudo apt-get install graphviz python library for graphviz for pip users: pip install graphviz :param mdp: :param graph_size: size of graph plot :param s_node_size: size of state nodes :param a_node_size: size of action nodes :param rankdir: order for drawing :return: dot object """ s_node_attrs = { 'shape': 'doublecircle', 'color': '#85ff75', 'style': 'filled', 'width': str(s_node_size), 'height': str(s_node_size), 'fontname': 'Arial', 'fontsize': '24' } a_node_attrs = { 'shape': 'circle', 'color': 'lightpink', 'style': 'filled', 'width': str(a_node_size), 'height': str(a_node_size), 'fontname': 'Arial', 'fontsize': '20' } s_a_edge_attrs = {'style': 'bold', 'color': 'red', 'ratio': 'auto'} a_s_edge_attrs = { 'style': 'dashed', 'color': 'blue', 'ratio': 'auto', 'fontname': 'Arial', 'fontsize': '16' } graph = Digraph(name='MDP') graph.attr(rankdir=rankdir, size=graph_size) for state_node in mdp._transition_probs: graph.node(state_node, **s_node_attrs) for posible_action in mdp.get_possible_actions(state_node): action_node = state_node + "-" + posible_action graph.node(action_node, label=str(posible_action), **a_node_attrs) graph.edge(state_node, state_node + "-" + posible_action, **s_a_edge_attrs) for posible_next_state in mdp.get_next_states( state_node, posible_action): probability = mdp.get_transition_prob(state_node, posible_action, posible_next_state) reward = mdp.get_reward(state_node, posible_action, posible_next_state) if reward != 0: label_a_s_edge = 'p = ' + str(probability) + \ ' ' + 'reward =' + str(reward) else: label_a_s_edge = 'p = ' + str(probability) graph.edge(action_node, posible_next_state, label=label_a_s_edge, **a_s_edge_attrs) return graph
def graphviz_visualization(activities_count, dfg, image_format="png", measure="frequency", max_no_of_edges_in_diagram=170, start_activities=None, end_activities=None): """ Do GraphViz visualization of a DFG graph Parameters ----------- activities_count Count of attributes in the log (may include attributes that are not in the DFG graph) dfg DFG graph image_format GraphViz should be represented in this format measure Describes which measure is assigned to edges in direcly follows graph (frequency/performance) max_no_of_edges_in_diagram Maximum number of edges in the diagram allowed for visualization Returns ----------- viz Digraph object """ if start_activities is None: start_activities = [] if end_activities is None: end_activities = [] filename = tempfile.NamedTemporaryFile(suffix='.gv') viz = Digraph("", filename=filename.name, engine='dot', graph_attr={'bgcolor': 'transparent'}) # first, remove edges in diagram that exceeds the maximum number of edges in the diagram dfg_key_value_list = [] for edge in dfg: dfg_key_value_list.append([edge, dfg[edge]]) # more fine grained sorting to avoid that edges that are below the threshold are # undeterministically removed dfg_key_value_list = sorted(dfg_key_value_list, key=lambda x: (x[1], x[0][0], x[0][1]), reverse=True) dfg_key_value_list = dfg_key_value_list[ 0:min(len(dfg_key_value_list), max_no_of_edges_in_diagram)] dfg_allowed_keys = [x[0] for x in dfg_key_value_list] dfg_keys = list(dfg.keys()) for edge in dfg_keys: if edge not in dfg_allowed_keys: del dfg[edge] # calculate edges penwidth penwidth = assign_penwidth_edges(dfg) activities_in_dfg = set() activities_count_int = copy(activities_count) for edge in dfg: activities_in_dfg.add(edge[0]) activities_in_dfg.add(edge[1]) # assign attributes color activities_color = get_activities_color(activities_count_int) # represent nodes viz.attr('node', shape='box') if len(activities_in_dfg) == 0: activities_to_include = sorted(list(set(activities_count_int))) else: # take unique elements as a list not as a set (in this way, nodes are added in the same order to the graph) activities_to_include = sorted(list(set(activities_in_dfg))) activities_map = {} for act in activities_to_include: if "frequency" in measure and act in activities_count_int: viz.node(str(hash(act)), act + " (" + str(activities_count_int[act]) + ")", style='filled', fillcolor=activities_color[act]) activities_map[act] = str(hash(act)) else: viz.node(str(hash(act)), act) activities_map[act] = str(hash(act)) # make edges addition always in the same order dfg_edges = sorted(list(dfg.keys())) # represent edges for edge in dfg_edges: if "frequency" in measure: label = str(dfg[edge]) else: label = human_readable_stat(dfg[edge]) viz.edge(str(hash(edge[0])), str(hash(edge[1])), label=label, penwidth=str(penwidth[edge])) start_activities_to_include = [ act for act in start_activities if act in activities_map ] end_activities_to_include = [ act for act in end_activities if act in activities_map ] if start_activities_to_include: viz.node("@@startnode", "@@S", style='filled', shape='circle', fillcolor="#32CD32", fontcolor="#32CD32") for act in start_activities_to_include: viz.edge("@@startnode", activities_map[act]) if end_activities_to_include: viz.node("@@endnode", "@@E", style='filled', shape='circle', fillcolor="#FFA500", fontcolor="#FFA500") for act in end_activities_to_include: viz.edge(activities_map[act], "@@endnode") viz.attr(overlap='false') viz.attr(fontsize='11') viz.format = image_format return viz
def to_graph(cache, arcs=[]): graph = Digraph(comment='Control Flow Graph') colors = {0: 'blue', 1: 'red'} kind = {0: 'T', 1: 'F'} cov_lines = set(i for i, j in arcs) for nid, cnode in cache.items(): lineno = cnode.lineno() shape, peripheries = 'oval', '1' if isinstance(cnode.ast_node, ast.AnnAssign): if cnode.ast_node.target.id in {'_if', '_for', '_while'}: shape = 'diamond' elif cnode.ast_node.target.id in {'enter', 'exit'}: shape, peripheries = 'oval', '2' else: shape = 'rectangle' graph.node(cnode.i(), "%d: %s" % (lineno, unhack(cnode.source())), shape=shape, peripheries=peripheries) for pn in cnode.parents: plineno = pn.lineno() if hasattr(pn, 'calllink') and pn.calllink > 0 and not hasattr( cnode, 'calleelink'): graph.edge(pn.i(), cnode.i(), style='dotted', weight=100) continue if arcs: if (plineno, lineno) in arcs: graph.edge(pn.i(), cnode.i(), color='green') elif plineno == lineno and lineno in cov_lines: graph.edge(pn.i(), cnode.i(), color='green') # child is exit and parent is covered elif hasattr(cnode, 'fn_exit_node') and plineno in cov_lines: graph.edge(pn.i(), cnode.i(), color='green') # parent is exit and one of its parents is covered. elif hasattr(pn, 'fn_exit_node') and len( set(n.lineno() for n in pn.parents) | cov_lines) > 0: graph.edge(pn.i(), cnode.i(), color='green') # child is a callee (has calleelink) and one of the parents is covered. elif plineno in cov_lines and hasattr(cnode, 'calleelink'): graph.edge(pn.i(), cnode.i(), color='green') else: graph.edge(pn.i(), cnode.i(), color='red') else: order = {c.i():i for i,c in enumerate(pn.children)} if len(order) < 2: graph.edge(pn.i(), cnode.i()) else: o = order[cnode.i()] graph.edge(pn.i(), cnode.i(), color=colors[o], label=kind[o]) return graph
def draw_graph(self, env_name, g_ind, epi_ind=None): ######## change to single graph setting numP, numA = self.numP[0], self.numA[0] ANDmat, ORmat = self.ANDmat[0].numpy(), self.ORmat[0].numpy() ind_to_id = self.ind_to_id[0].tolist() rewards = self.rmag[0].tolist() num_level = len(numA) ######## from graphviz import Digraph root = os.path.join(__PATH__, 'config', env_name) if epi_ind is None: filename = './render/temp/subtask_graph_GT_{}'.format(g_ind) else: filename = './render/temp/subtask_graph_index{}_epi{}'.format( g_ind, epi_ind) g = Digraph(comment='subtask graph', format='png', filename=filename) g.attr(nodesep="0.1", ranksep="0.2") g.node_attr.update(fontsize="14", fontname='Arial') # 1. add Or nodes in the first layer for ind in range(numP[0]): sub_id = ind_to_id[ind] label = '\n{:+1.2f}'.format(rewards[ind]) g.node('OR' + str(ind), label, shape='rect', height="0.1", width="0.1", image=root + '/subtask{:02d}.png'.format(sub_id)) abias, obias = 0, numP[0] for lind in range(num_level): Na, No = numA[lind], numP[lind + 1] Amat = ANDmat[abias:abias + Na] Omat = ORmat[obias:obias + No] # Add AND nodes for i in range(Na): Aind = i + abias g.node('AND' + str(Aind), "", shape='ellipse', style='filled', width="0.3", height="0.2", margin="0") # Edge OR->AND left, right = Amat.nonzero() for i in range(len(left)): Aind = abias + left[i] Oind = right[i] if Amat[left[i]][right[i]] < 0: g.edge('OR' + str(Oind), 'AND' + str(Aind), style="dashed", arrowsize="0.7") else: g.edge('OR' + str(Oind), 'AND' + str(Aind), arrowsize="0.7") # Add OR nodes for i in range(No): ind = i + obias sub_id = ind_to_id[ind] label = '\n{:+1.2f}'.format(rewards[ind]) g.node('OR' + str(ind), label, shape='rect', height="0", width="0", image=root + '/subtask{:02d}.png'.format(sub_id)) # Edge AND->OR left, right = Omat.nonzero() for i in range(len(left)): Oind = obias + left[i] Aind = right[i] g.edge('AND' + str(Aind), 'OR' + str(Oind), arrowsize="0.7", arrowhead="odiamond") abias += Na obias += No g.render()
def sgGenerate(): # Get dynamic object info (pose and vel) periodically extractor.update_dynamic_obj_info() # Update vision sensor info extractor.update_all_robots_vision_sensors_fov() robot_list = extractor.robot_obj_list # Get objects that are in the sensor FOV for robot_num in range(1): obj_list = extractor.get_objects_from_vision_sensor(robot_list[robot_num].vision_sensor) #NOT ROBUST HERE if (obj_list != None): # Remove the robot itself from the list obj_list = [i for i in obj_list if i.name!=robot_list[robot_num].name] # Print detected objects of the vision sensor print(robot_list[robot_num].name, robot_list[robot_num].vision_sensor.name, obj_list) ############################################# # generate scene graph ############################################# dot = Digraph(comment='warehouse', format='svg') dot.node_attr['shape']='record' robot_velocity = get_velocity(robot_list[robot_num]) i = robot_list[robot_num] # print(i.bbox_min[0], i.bbox_min[1], i.bbox_max[0], i.bbox_max[1]) # robot_label = '{%s|%s|velocity: %.2f|orientation: %.2f}'%(robot[robot_num].name, robot[robot_num].vision_sensor.name, robot_velocity, robot[robot_num].ori[2]*180/pi) robot_label = '{%s|%s|velocity: %.2f}'%(robot_list[robot_num].name, robot_list[robot_num].vision_sensor.name, robot_velocity) #robot_label = '{%s|type: 0|%s|velocity: %.2f}'%(robot_list[robot_num].name, robot_list[robot_num].vision_sensor.name, robot_velocity) #Label for itself? # robot_label = '{%s|%s}'%(robot[robot_num].name, robot[robot_num].vision_sensor.name) dot.node('robot', label=robot_label) dot.node('warehouse', label='warehouse') dot.node('floor', label='{floor|size: 25*25}') dot.edge('warehouse','floor') for obj in obj_list: obj_direction = get_direction(robot_list[robot_num], obj) obj_distance = get_distance_bbox(robot_list[robot_num], obj) obj_velocity = get_velocity(obj) obj_type = get_type(obj) obj_orientation = get_orientation(robot_list[robot_num], obj) # print(obj.name, '%.3f' %obj_velocity) # node_label = '{%s|direction: %s|distance: %.2f}'%(obj.name, obj_direction, obj_distance) # if obj.name == 'Bill#3': # node_label = '{%s|velocity: 0.2|distance: %.2f}'%(obj.name, obj_distance) # else: # node_label = '{%s|Static|distance: %.2f}'%(obj.name, obj_distance) node_label = '{%s|type: %s|distance: %.2f|orientation: %.2f|direction: %.2f|velocity: %.2f}'%( obj.name, obj_type, obj_distance, obj_orientation, obj_direction, obj_velocity) # node_label = '{%s|velocity: %.2f|distance: %.2f}'%( obj.name, obj_velocity, obj_distance) # node_label = '{%s|distance: %.2f}'%(obj.name, obj_distance) dot.node(obj.name, label=node_label) if re.match(r'wall*', obj.name): dot.edge('warehouse', obj.name, label='on') elif re.match(r'product*', obj.name): for obj_support in obj_list: # if get_support_bbox(obj, obj_support): if get_overlap_bbox(obj, obj_support): dot.edge(obj_support.name, obj.name, label='on') break else: dot.edge('floor', obj.name, label='on') break else: dot.edge('floor', obj.name, label='on') #output scene graph as .svg file in #sg_name = 'sg_robot/robot%d' %robot_num #dot.render(sg_name, view=True) #output scene graph as string #print dot.source sg_message=SceneGraph() sg_message.header = std_msgs.msg.Header() sg_message.header.stamp = rospy.Time.now() sg_message.sg_data=dot.source pub.publish(sg_message)
def plot_graphic_file_flow_sd(n_sd=1, n_sub=3, savefig="png"): """ Plot a model showing what files are created at each stage of a BEAST production run with source density binning. Parameters ---------- n_sd : int (default=1) number of source density bins to show n_sub : int (default=3) number of source density sub-bins to show savefig : str (default='png') set to the file extension of desired file to save image of model """ # initialize graph # (note: can't do dictionary for nodes like plot_graphic_model.py, because # we need to exert more control over which things are lined up) graph = Digraph(node_attr={"shape": "box"}) # first layer with graph.subgraph() as sg: sg.attr(rank="same") sg.node("sed", "SEDgrid") sg.node("phot", "phot") sg.node("fake", "phot_fake") # additional layers sg1 = Digraph(node_attr={"shape": "box"}) sg2 = Digraph(node_attr={"shape": "box"}) sg3 = Digraph(node_attr={"shape": "box"}) sg4 = Digraph(node_attr={"shape": "box"}) sg5 = Digraph(node_attr={"shape": "box"}) sg6 = Digraph(node_attr={"shape": "box"}) _ = [x.attr(rank="same") for x in [sg1, sg2, sg3, sg4, sg5, sg6]] # items in last layer sg6.node("stats", "stats_all") sg6.node("pdf1d", "pdf1d_all") sg6.node("pdf2d", "pdf2d_all") sg6.node("lnp", "lnp_all") # initialize dict of edges edges = defaultdict(list) # initialize dict of invisible edges # these are used to force the order: # https://stackoverflow.com/questions/44274518/how-can-i-control-within-level-node-order-in-graphvizs-dot/44274606 edges_invis = defaultdict(list) # iterate through source density bins for s in range(n_sd): curr_sd = f"SD{s}-{s+1}" # files for this source density bin sg1.node(f"phot{s}", f"phot_{curr_sd}") sg1.node(f"fake{s}", f"phot_fake_{curr_sd}") sg2.node(f"obs{s}", f"obsmodel_{curr_sd}") # make edges edges["phot"].append(f"phot{s}") edges["fake"].append(f"fake{s}") edges[f"fake{s}"].append(f"obs{s}") # files for combo of source density and sub-bin for b in range(n_sub): curr_sub = f"sub{b}" # -- nodes -- sg3.node(f"phot{s}s{b}", f"phot_{curr_sd}_{curr_sub}") sg3.node(f"sed{s}s{b}", f"SEDgrid_{curr_sd}_{curr_sub}_trim") sg3.node(f"obs{s}s{b}", f"obsmodel_{curr_sd}_{curr_sub}_trim") sg4.node(f"lnps_{s}s{b}", f"likelihoods for\n{curr_sd}_{curr_sub}") sg5.node(f"stat{s}s{b}", f"stats_{curr_sd}_{curr_sub}") sg5.node(f"pdf1d{s}s{b}", f"pdf1d_{curr_sd}_{curr_sub}") sg5.node(f"pdf2d{s}s{b}", f"pdf2d_{curr_sd}_{curr_sub}") sg5.node(f"lnp{s}s{b}", f"lnp_{curr_sd}_{curr_sub}") # -- edges -- # phot to sub-phot edges[f"phot{s}"].append(f"phot{s}s{b}") # SED to trimmed SED edges["sed"].append(f"sed{s}s{b}") # obsmodel to trimmed obsmodel edges[f"obs{s}"].append(f"obs{s}s{b}") # photometry + trimmed SED + trimmed obsmodel to likelihoods edges[f"phot{s}s{b}"].append(f"lnps_{s}s{b}") edges[f"sed{s}s{b}"].append(f"lnps_{s}s{b}") edges[f"obs{s}s{b}"].append(f"lnps_{s}s{b}") # likelihoods to output files edges[f"lnps_{s}s{b}"] += [ f"stat{s}s{b}", f"pdf1d{s}s{b}", f"pdf2d{s}s{b}", f"lnp{s}s{b}", ] # output files to combined files edges[f"stat{s}s{b}"].append("stats_all") edges[f"pdf1d{s}s{b}"].append("pdf1d_all") edges[f"pdf2d{s}s{b}"].append("pdf2d_all") edges[f"lnp{s}s{b}"].append("lnp_all") # -- invisible edges -- # photometry + trimmed SED + trimmed obsmodel # -> nope, tends to make things more messy # edges_invis[f"phot{s}s{b}"].append(f"sed{s}s{b}") # edges_invis[f"sed{s}s{b}"].append(f"obs{s}s{b}") # output files edges_invis[f"stat{s}s{b}"].append(f"pdf1d{s}s{b}") edges_invis[f"pdf1d{s}s{b}"].append(f"pdf2d{s}s{b}") edges_invis[f"pdf2d{s}s{b}"].append(f"lnp{s}s{b}") # add the edges for ckey in edges.keys(): for cval in edges[ckey]: if "phot" in ckey: graph.edge(ckey, cval, color="#FDB62D") elif "fake" in ckey or "obs" in ckey: graph.edge(ckey, cval, color="#D7576B") elif "sed" in ckey: graph.edge(ckey, cval, color="#4A02A0") else: graph.edge(ckey, cval) # add invisible edges (to force ordering) for ckey in edges_invis.keys(): for cval in edges_invis[ckey]: graph.edge(ckey, cval, style="invis") # append subgraphs graph.subgraph(sg1) graph.subgraph(sg2) graph.subgraph(sg3) graph.subgraph(sg4) graph.subgraph(sg5) # make the graph flow horizontally graph.graph_attr["rankdir"] = "LR" # save it graph.render("beast-graphic-file-flow-sourceden", format=savefig)
#!/usr/bin/env python # cluster_edge.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 20 from graphviz import Digraph g = Digraph('G', filename='cluster_edge.gv') g.attr(compound='true') with g.subgraph(name='cluster0') as c: c.edges(['ab', 'ac', 'bd', 'cd']) with g.subgraph(name='cluster1') as c: c.edges(['eg', 'ef']) g.edge('b', 'f', lhead='cluster1') g.edge('d', 'e') g.edge('c', 'g', ltail='cluster0', lhead='cluster1') g.edge('c', 'e', ltail='cluster0') g.edge('d', 'h') g.view()
def plot_network(symbol, title="plot", shape=None, node_attrs={}): """convert symbol to dot object for visualization Parameters ---------- title: str title of the dot graph symbol: Symbol symbol to be visualized shape: dict dict of shapes, str->shape (tuple), given input shapes node_attrs: dict dict of node's attributes for example: node_attrs={"shape":"oval","fixedsize":"fasle"} means to plot the network in "oval" Returns ------ dot: Diagraph dot object of symbol """ # todo add shape support try: from graphviz import Digraph except: raise ImportError("Draw network requires graphviz library") if not isinstance(symbol, Symbol): raise TypeError("symbol must be Symbol") draw_shape = False if shape != None: draw_shape = True interals = symbol.get_internals() _, out_shapes, _ = interals.infer_shape(**shape) if out_shapes == None: raise ValueError("Input shape is incompete") shape_dict = dict(zip(interals.list_outputs(), out_shapes)) conf = json.loads(symbol.tojson()) nodes = conf["nodes"] heads = set([x[0] for x in conf["heads"]]) # TODO(xxx): check careful # default attributes of node node_attr = { "shape": "box", "fixedsize": "true", "width": "1.3", "height": "0.8034", "style": "filled" } # merge the dcit provided by user and the default one node_attr.update(node_attrs) dot = Digraph(name=title) # color map cm = ("#8dd3c7", "#fb8072", "#ffffb3", "#bebada", "#80b1d3", "#fdb462", "#b3de69", "#fccde5") # make nodes for i in range(len(nodes)): node = nodes[i] op = node["op"] name = node["name"] # input data attr = copy.deepcopy(node_attr) label = op if op == "null": if i in heads: label = node["name"] attr["fillcolor"] = cm[0] else: continue elif op == "Convolution": label = r"Convolution\n%sx%s/%s, %s" % ( _str2tuple(node["param"]["kernel"])[0], _str2tuple(node["param"]["kernel"])[1], _str2tuple( node["param"]["stride"])[0], node["param"]["num_filter"]) attr["fillcolor"] = cm[1] elif op == "FullyConnected": label = r"FullyConnected\n%s" % node["param"]["num_hidden"] attr["fillcolor"] = cm[1] elif op == "BatchNorm": attr["fillcolor"] = cm[3] elif op == "Activation" or op == "LeakyReLU": label = r"%s\n%s" % (op, node["param"]["act_type"]) attr["fillcolor"] = cm[2] elif op == "Pooling": label = r"Pooling\n%s, %sx%s/%s" % ( node["param"]["pool_type"], _str2tuple( node["param"]["kernel"])[0], _str2tuple(node["param"]["kernel"])[1], _str2tuple(node["param"]["stride"])[0]) attr["fillcolor"] = cm[4] elif op == "Concat" or op == "Flatten" or op == "Reshape": attr["fillcolor"] = cm[5] elif op == "Softmax": attr["fillcolor"] = cm[6] else: attr["fillcolor"] = cm[7] dot.node(name=name, label=label, **attr) # add edges for i in range(len(nodes)): node = nodes[i] op = node["op"] name = node["name"] if op == "null": continue else: inputs = node["inputs"] for item in inputs: input_node = nodes[item[0]] input_name = input_node["name"] if input_node["op"] != "null" or item[0] in heads: attr = {"dir": "back", 'arrowtail': 'open'} # add shapes if draw_shape: if input_node["op"] != "null": key = input_name + "_output" shape = shape_dict[key][1:] label = "x".join([str(x) for x in shape]) attr["label"] = label else: key = input_name shape = shape_dict[key][1:] label = "x".join([str(x) for x in shape]) attr["label"] = label dot.edge(tail_name=name, head_name=input_name, **attr) return dot
break if not dup: loops3.append(result) else: loops3.append(result) graphs = [] ascii_val = 65 for loop in loops: dot = Digraph(comment='Loop') for ele in loop: dot.node(chr(ascii_val), str(ele)) ascii_val += 1 for x in range(65, ascii_val): if x != ascii_val - 1: dot.edge(chr(x), chr(x + 1), constraint='false') else: dot.edge(chr(x), chr(65), constraint='false') graphs.append(dot) ascii_val = 65 num_graphs = 1 for graph in graphs: graph.format = 'png' graph.render('test-output/loopx2mod100_%d.gv' % num_graphs, view=True) num_graphs += 1 graphs = [] ascii_val = 65 for loop in loops1: dot = Digraph(comment='Loop')
from graphviz import Graph from graphviz import Digraph from knock41 import sentences from knock42 import words dg = Digraph(format='png') if __name__ == "__main__": for i, chunk in enumerate(sentences[2]): dg.node(words[i]) for i, chunk in enumerate(sentences[2]): if chunk.dst != -1: dg.edge(words[i], words[chunk.dst]) dg.render('./dgraph', view=True)
def drawDiagram(modelXbrl, diagramFile, diagramNetwork=None, viewDiagram=False): if diagramNetwork not in diagramNetworks: modelXbrl.error("objectmaker:diagramNetwork", "Diagram network %(diagramNetwork)s not recognized, please specify one of %(recognizedDiagramNetworks)s", modelXbrl=modelXbrl, diagramNetwork=diagramNetwork, recognizedDiagramNetworks=", ".join(diagramNetworks)) return try: from graphviz import Digraph, backend except ImportError: modelXbrl.error("objectmaker:missingLibrary", "Missing library, please install graphviz for python importing", modelXbrl=modelXbrl) return isUML = diagramNetwork == "uml" isBaseSpec = diagramNetwork in ("pre", "cal", "def") graphName = os.path.splitext(modelXbrl.modelDocument.basename)[0] mdl = Digraph(comment=graphName) mdl.attr("graph") mdl.node('node_title', graphName, shape="none", fontname="Bitstream Vera Sans") mdl.attr('node', shape="record") mdl.attr('node', fontname="Bitstream Vera Sans") mdl.attr('node', fontsize="8") if isUML: arcroleName = "http://xbrl.us/arcrole/Property" propertiesRelationshipSet = modelXbrl.relationshipSet(arcroleName) if not propertiesRelationshipSet: modelXbrl.modelManager.addToLog(_("no relationships for {0}").format(arcroleName)) return False def node(mdl, id, modelObject): if modelObject is not None: mdl.attr("node", style="") # white classes if isUML: _properties = "".join("+{} {}\l".format(rel.toModelObject.qname.localName, rel.toModelObject.niceType) for rel in propertiesRelationshipSet.fromModelObject(modelObject) if rel.toModelObject is not None) mdl.node(id, "{{{}|{}}}".format(modelObject.qname.localName, _properties)) elif isBaseSpec and isinstance(modelObject, ModelConcept): concept = modelObject if concept.isHypercubeItem: _properties = "Hypercube" elif concept.isExplicitDimension: _properties = "Dimension, Explicit" elif concept.isExplicitDimension: _properties = "Dimension, Typed ({} {})".format(typedDomainElement.qname, typedDomainElement.niceType) elif concept.isEnumeration: _properties = "Enumeration ({})".format(concept.enumDomain.qname) else: _properties = "{}{}".format("Abstract " if modelObject.isAbstract else "", modelObject.niceType) mdl.node(id, "{{{}|{}}}".format(modelObject.qname.localName, _properties)) elif isinstance(modelObject, ModelDocument.ModelDocument): mdl.node(id, "{{{}|{}}}".format(modelObject.basename, modelObject.gettype())) elif isinstance(modelObject, str): # linkrole definition mdl.node(id, "{{{}}}".format(modelObject)) else: mdl.node(id, "{{{}}}".format(modelObject.qname.localName)) nodes = set() edges = set() arcroles = diagramNetworks[diagramNetwork] lang = None # from parameter for override # sort URIs by definition linkroleUris = set() if isBaseSpec: for arcrole in arcroles: graphRelationshipSet = modelXbrl.relationshipSet(arcrole) for linkroleUri in graphRelationshipSet.linkRoleUris: modelRoleTypes = modelXbrl.roleTypes.get(linkroleUri) if modelRoleTypes: roledefinition = (modelRoleTypes[0].genLabel(lang=lang, strip=True) or modelRoleTypes[0].definition or linkroleUri) else: roledefinition = linkroleUri linkroleUris.add((roledefinition, linkroleUri)) else: linkroleUris.add((None, None)) for roledefinition, linkroleUri in sorted(linkroleUris): for arcrole in arcroles: relationshipType = arcrole.rpartition("/")[2].lower() edgeType = networkEdgeTypes[diagramNetwork][relationshipType] graphRelationshipSet = modelXbrl.relationshipSet(arcrole, linkroleUri) roleprefix = (linkroleUri.replace("/","_").replace(":","_") + "_") if linkroleUri else "" if not graphRelationshipSet: continue if linkroleUri is not None: node(mdl, roleprefix, roledefinition or roleUri) for rootConcept in graphRelationshipSet.rootConcepts: childName = roleprefix + rootConcept.qname.localName node(mdl, childName, rootConcept) nodes.add(childName) mdl.edge(roleprefix, childName, dir=edgeType.get("dir"), arrowhead=edgeType.get("arrowhead"), arrowtail=edgeType.get("arrowtail")) for rel in graphRelationshipSet.modelRelationships: parent = rel.fromModelObject parentName = roleprefix + parent.qname.localName child = rel.toModelObject if child is None: continue childName = roleprefix + child.qname.localName if parentName not in nodes: node(mdl, parentName, parent) nodes.add(parentName) if childName not in nodes: node(mdl, childName, child) nodes.add(childName) edgeKey = (relationshipType, parentName, childName) if edgeKey not in edges: edges.add(edgeKey) mdl.edge(parentName, childName, dir=edgeType.get("dir"), arrowhead=edgeType.get("arrowhead"), arrowtail=edgeType.get("arrowtail")) if diagramNetwork == "dts": def viewDtsDoc(modelDoc, parentDocName, grandparentDocName): docName = modelDoc.basename docType = modelDoc.gettype() if docName not in nodes: node(mdl, docName, modelDoc) if parentDocName: edgeKey = (parentDocName, docType, docName) if edgeKey in edges: return edges.add(edgeKey) edgeType = networkEdgeTypes[diagramNetwork]["all-types"] mdl.edge(parentDocName, docName, dir=edgeType.get("dir"), arrowhead=edgeType.get("arrowhead"), arrowtail=edgeType.get("arrowtail")) for referencedDoc in modelDoc.referencesDocument.keys(): if referencedDoc.basename != parentDocName: # skip reverse linkbase ref viewDtsDoc(referencedDoc, docName, parentDocName) viewDtsDoc(modelXbrl.modelDocument, None, None) mdl.format = "pdf" try: mdl.render(diagramFile.replace(".pdf", ".gv"), view=viewDiagram) except backend.ExecutableNotFound as ex: modelXbrl.warning("objectmaker:graphvizExecutable", "Diagram saving requires installation of graphviz, error: %(error)s:", modelXbrl=modelXbrl, error=ex)
import difflib from graphviz import Digraph terms = [] with open('output/terms.txt') as f: for line in f: terms.append(line.strip()) dot = Digraph() for term in terms: other_words = list(terms) other_words.remove(term) matches = difflib.get_close_matches(term, other_words) for match in matches: dot.edge(term, match) dot.render("output/graph")
from graphviz import Digraph import sys if len(sys.argv) != 2: print("usage: python viz.py FILENUM") FILE_NUMBER = [sys.argv[1]] for fname in []: with open('cs170_final_inputs/' + fname + '.in') as f: dot = Digraph() n = int(next(f)) A = [] for line in f: A.append(list(map(int, line.rstrip().split(' ')))) for i in range(n): dot.node(str(i), str(A[i][i]) + ", (" + str(i) + ")") for i in range(n): for j in range(n): if A[i][j] and i != j: dot.edge(str(i), str(j)) dot.render("graphpdf/" + fname, view=True)
operation_dvs=None, exog=[ 'heat_CAPEX', 'heat_OPEX', 'heat_lifetime', 'heat_el_efficiency' ])) d.attr('node', shape='none') d.node('curtailed', 'curtailed_el_kWh*', fontcolor='blue') d.attr('node', shape='doublecircle') d.node('kerosene', string_generator('Kerosene')) d.node('diesel', string_generator('Diesel')) d.node('gasoline', string_generator('Gasoline')) # Define electricity flows d.attr('edge', color='darkgreen', fontcolor='blue') d.edge('wind', 'electricity', 'wind_production_kWh*') d.edge('electricity', 'battery', 'battery_chr_kWh*') d.edge('battery', 'electricity', 'battery_dis_kWh*') d.edge('pv', 'electricity', 'PV_production_kWh*') d.edge('electricity', 'electrolyzer', 'H2_el_kWh*') d.edge('electricity', 'CO2', 'CO2_el_kWh*') d.edge('electricity', 'H2tL', 'H2tL_el_kWh*') d.edge('electricity', 'heat', 'heat_el_kWh*') d.edge('electricity', 'curtailed') #Define H2 flows d.attr('edge', color='cyan') d.edge('electrolyzer', 'H2_mb', 'H2_production_kWh*') d.edge('H2_mb', 'H2tL', 'H2_consumption_kWh*') d.edge('H2stor', 'H2_mb', 'H2stor_dis_kWh*') d.edge('H2_mb', 'H2stor', 'H2stor_chr_kWh*')
def write(self, file_name, engine='fdp', show_publications=True, show_subscriptions=True): """ write the graph to a file :param engine: graphviz engine - fdp works for large graphs - neato works better for smaller graphs - circo works for single modules CLI: fdp graph.fv -Tpdf -o test.pdf """ print('Writing to ' + file_name) ratio = 1 # aspect ratio modules = self._graph.modules topics = self._graph.topics topic_colors = self._graph.topic_colors module_publications = self._graph.module_publications module_subscriptions = self._graph.module_subscriptions graph_attr = { 'splines': 'true', 'ratio': str(ratio), 'overlap': 'false' } graph_attr['sep'] = '"+15,15"' # increase spacing between nodes graph = Digraph( comment='autogenerated graph with graphviz using uorb_graph.py', engine=engine, graph_attr=graph_attr) # nodes for module in modules: graph.node('m_' + module, module, shape='box', fontcolor='#ffffff', style='filled', color='#666666', fontsize='16') for topic in topics: graph.node('t_' + topic, topic, shape='ellipse', fontcolor='#ffffff', style='filled', color=topic_colors[topic]) # edges if show_publications: for module in modules: if module in module_publications: for topic in module_publications[module]: if topic in topics: graph.edge('m_' + module, 't_' + topic, color=topic_colors[topic], style='dashed') if show_subscriptions: for module in modules: if module in module_subscriptions: for topic in module_subscriptions[module]: if topic in topics: graph.edge('t_' + topic, 'm_' + module, color=topic_colors[topic]) graph.render(file_name, view=False)
if __name__ == "__main__": print('\n## Derivation Trees') from graphviz import Digraph if __name__ == "__main__": tree = Digraph("root") tree.attr('node', shape='plain') tree.node(r"\<start\>") if __name__ == "__main__": tree if __name__ == "__main__": tree.edge(r"\<start\>", r"\<expr\>") if __name__ == "__main__": tree if __name__ == "__main__": tree.edge(r"\<expr\>", r"\<expr\> ") tree.edge(r"\<expr\>", r"+") tree.edge(r"\<expr\>", r"\<term\>") if __name__ == "__main__": tree if __name__ == "__main__": tree.edge(r"\<expr\> ", r"\<term\> ") tree.edge(r"\<term\> ", r"\<factor\> ")
dot.node('build-tzar', 'Automated triaging \n for secondary pipeline', fontcolor='Red', color='blue', fontsize="30") # Features dot.node( 'features', 'Dynamic \n No code changes required \n for addition/ deletion of branches/test suites', style='dashed', color='darkgreen', fontcolor='darkgreen') dot.edge('build-tzar', 'features', label='Salient Features', style='dashed', fontcolor='darkgreen', color='darkgreen') # Case-1 dot.node( 'case-1', 'Test case failures for which \n JIRA bugs have been raised in \n previous failures / other branches', fontcolor='blue', shape='rectangle') dot.edge('build-tzar', 'case-1', label='Case-1', fontcolor='blue') # Case-1 Example dot.node( 'case-1-ex', 'Test com......ScheduleDrsTest failed \n but in previous run product bug VSUIR-335 was raised',
class R2RML_visualizer: def __init__(self, loadNamespaces=None, loadTerminologies=None, excludePredicates=None, remoteTermEndpoint=None): self.termStore = rdflib.Graph() self.remoteTermStore = remoteTermEndpoint self.rmlStore = rdflib.Graph() self.rdfStore = None self.graph = None self.excludedLiteralPredicates = [] self.namespaces = { "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#": "ncit:", "http://www.cancerdata.org/roo/": "roo:", "http://mapping.local/": "map_", "http://purl.obolibrary.org/obo/UO_": "UO:", "http://www.w3.org/2001/XMLSchema#": "xsd:", "http://www.w3.org/2000/01/rdf-schema#": "rdfs:", "http://purl.bioontology.org/ontology/ICD10/": "icd:" } if loadNamespaces is not None: self.namespaces = loadNamespaces if loadTerminologies is not None: for url in loadTerminologies: self.termStore.load(url) if excludePredicates is not None: self.excludedLiteralPredicates = excludePredicates def loadScript(self, fileLocation, clear=False): if (clear): self.rmlStore = rdflib.Graph() self.rmlStore.parse(fileLocation, format="n3") def uploadR2RML(self, endpointUrl): rdfString = self.rmlStore.serialize(format='nt') # Create insert query insertQuery = "INSERT { %s } WHERE { }" % rdfString # Execute insert query endpoint = SPARQLWrapper(endpointUrl + "/statements") endpoint.setQuery(insertQuery) endpoint.method = "POST" try: endpoint.query() print("Mapping succesfully uploaded") except: print("Something went wrong during upload.") def uploadTermStore(self, endpointUrl): turtle = self.termStore.serialize(format='nt') try: loadRequest = requests.post( endpointUrl, data=turtle, headers={"Content-Type": "text/turtle"}) print("Mapping succesfully uploaded") except: print("Something went wrong during upload.") def clearRemoteR2RMLStore(self, endpointUrl): endpoint = SPARQLWrapper(endpointUrl + "/statements") endpoint.setQuery("DROP ALL;") endpoint.method = "POST" endpoint.query() def replaceToNamespace(self, uriObj): classString = str(uriObj) for key in self.namespaces.keys(): classString = classString.replace(key, self.namespaces[key]) return classString def plotGraph(self): # create new graphviz canvas self.graph = Digraph(comment='R2RML Structure', format="png") self.graph.node_attr.update(color='lightblue2', style='filled') # create in-memory rdf store and load mapping and terminologies self.rdfStore = rdflib.Graph() self.rdfStore.parse(data=self.rmlStore.serialize()) self.rdfStore.parse(data=self.termStore.serialize()) #loop over nodes and start plotting nodes = self.getNodes() for node in nodes: self.plotNode(node) # Get all object predicates predicateObjects = self.getNodeRelations(node) for predicateObject in predicateObjects: self.plotPredicatObjectForNode(node, predicateObject) # Get all literal predicates predicateLiterals = self.getNodeLiterals(node) for predicateLiteral in predicateLiterals: self.plotPredicateLiteralForNode(node, predicateLiteral) return self.graph def getNodes(self): res = self.rdfStore.query("""prefix rr: <http://www.w3.org/ns/r2rml#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?map ?mapClass WHERE { ?map a rr:TriplesMap. ?map rr:subjectMap [ rr:class ?mapClass ] }""") return res def getNodeRelations(self, node): res = self.rdfStore.query("""prefix rr: <http://www.w3.org/ns/r2rml#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?predicate ?otherMap WHERE { <%s> rr:predicateObjectMap [ rr:predicate ?predicate; rr:objectMap [ rr:parentTriplesMap ?otherMap ] ]. }""" % str(node["map"])) return res def getNodeLiterals(self, node): res = self.rdfStore.query("""prefix rr: <http://www.w3.org/ns/r2rml#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?predicate ?literalType WHERE { <%s> rr:predicateObjectMap [ rr:predicate ?predicate; rr:objectMap [ rr:datatype ?literalType ] ] }""" % str(node["map"])) return res def getLabelForUri(self, uri, includeNewline=True): myQuery = """prefix rr: <http://www.w3.org/ns/r2rml#> prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?uriLabel WHERE { <%s> rdfs:label ?uriLabel. }""" % str(uri) if (len(self.termStore) > 0): return self.getLabelForUriLocal(myQuery, includeNewline) else: if not self.remoteTermStore == None: return self.getLabelForUriRemote(myQuery, self.remoteTermStore, includeNewline) def getLabelForUriRemote(self, myQuery, endpoint, includeNewline): endpoint = SPARQLWrapper(endpoint) endpoint.setQuery(myQuery) endpoint.method = "POST" endpoint.setReturnFormat(JSON) results = endpoint.query().convert() for result in results["results"]["bindings"]: retVal = str(result["uriLabel"]["value"]) if includeNewline: retVal + "\n" return retVal return "" def getLabelForUriLocal(self, myQuery, includeNewLine): res = self.rdfStore.query(myQuery) for row in res: retVal = str(row["uriLabel"]) if includeNewline: retVal + "\n" return retVal return "" def plotNode(self, node): mapClass = self.replaceToNamespace(node["map"]) targetClass = self.replaceToNamespace(node["mapClass"]) targetClassLabel = self.getLabelForUri(node["mapClass"]) self.graph.node(mapClass, targetClassLabel + "\n[" + targetClass + "]") def plotPredicatObjectForNode(self, node, predicateObject): mapClass = self.replaceToNamespace(node["map"]) predicateUri = self.replaceToNamespace(predicateObject["predicate"]) predicateLabel = self.getLabelForUri(predicateObject["predicate"]) objClass = self.replaceToNamespace(predicateObject["otherMap"]) self.graph.edge(mapClass, objClass, predicateLabel + "\n[" + predicateUri + "]") def plotPredicateLiteralForNode(self, node, predicateLiteral): mapClass = self.replaceToNamespace(node["map"]) predicateUri = self.replaceToNamespace(predicateLiteral["predicate"]) if predicateUri not in self.excludedLiteralPredicates: predicateLabel = self.getLabelForUri(predicateLiteral["predicate"]) literal = self.replaceToNamespace(predicateLiteral["literalType"]) nodeName = mapClass + "_" + literal.replace(":", "_") self.graph.node(nodeName, "LITERAL\n[" + literal + "]") self.graph.edge(mapClass, nodeName, predicateLabel + "\n[" + predicateUri + "]")
# -*- coding: UTF-8 -*- from graphviz import Digraph from PIL import Image, ImageTk, ImageDraw, ImageFont dot = Digraph(comment='这是一个有向图') dot.node('A', '作者') dot.node('B', '医生') dot.node('C', '律师') dot.edges(['AB', 'AC']) dot.edge('B', 'C') dot.format = 'png' dot.render('output-graph.gv', view=True) Image(dot.render('output-graph.gv'))