def __init__(self, root=None): # 添加一个没有数据的 HEAD self._root = root # Dot self.graph = Dot(rankdir='TB') self.graph.set_type('digraph') self.graph.set_name('Tree')
def _create_bpmn_objects(pydot_graph: pydotplus.Dot) -> (list, list): bpmn_nodes = [] # list of bpmn nodes nodes = {} # nodes[node_name] = bpmn_node for graph_node in pydot_graph.get_node_list(): name = graph_node.get_name() shape = graph_node.__get_attribute__('shape') label = graph_node.__get_attribute__('label') height = graph_node.__get_attribute__('height') width = graph_node.__get_attribute__('width') pos = graph_node.__get_attribute__('pos') if pos is not None: # not to include 'system' nodes name = modify_str(name) label = modify_str(label) if name == 'startevent': bpmn_node = StartEvent(pos, height, width) elif name == 'endevent': bpmn_node = EndEvent(pos, height, width) elif shape == 'diamond': bpmn_node = (ParallelGateway if (label == '+') else ExclusiveGateway)(pos, height, width) elif shape == 'box': bpmn_node = Task(label, pos, height, width) else: raise AssertionError( f'type of node {graph_node.get_name()} was not detected!' ) nodes[name] = bpmn_node bpmn_nodes.append(bpmn_node) bpmn_edges = [] # list of SequenceFlow() (bpmn edges) for graph_edge in pydot_graph.get_edge_list(): source_name = modify_str(graph_edge.get_source()) dest_name = modify_str(graph_edge.get_destination()) source_node = nodes[source_name] dest_node = nodes[dest_name] pos = graph_edge.__get_attribute__('pos') bpmn_edge = SequenceFlow(source_node.get_id(), dest_node.get_id()) bpmn_edge.set_pos(pos) source_node.set_outgoing(bpmn_edge.get_id()) dest_node.set_incoming(bpmn_edge.get_id()) bpmn_edges.append(bpmn_edge) return bpmn_nodes, bpmn_edges
def pydot_graph(layers, node_creator=default_create, **kwargs): """Create a :class:`Dot` graph for a list of layers Parameters ---------- layers : list of :class:`Layer` instances The graph will be created with the layers from that list. node_creator : callable (``default_create``) A function that creates a :class:`Node` for a given layer. kwargs : keyword arguments Those will be passed down to ``node_creator`` or :class:`Node`. """ nodes = {} edges = [] for layer in layers: nodes[layer] = node_creator(layer, **kwargs) if hasattr(layer, 'input_layers'): for input_layer in layer.input_layers: edges.append((input_layer, layer)) if hasattr(layer, 'input_layer'): edges.append((layer.input_layer, layer)) graph = Dot('Network', graph_type='digraph') for node in nodes.values(): graph.add_node(node) for start, end in edges: try: graph.add_edge(Edge(nodes[start], nodes[end])) except KeyError: pass return graph
def _graph_with_defaults(name: str) -> Dot: """Return default pydot graph.""" result = Dot(graph_name=f'"{name}"') result.set_graph_defaults(splines="true", ranksep="0.1 equally", pad="0.1", truecolor="true", bgcolor="#00000000") result.set_edge_defaults(fontname="Fira Code", fontcolor="#6f6f6f", color="#6f6f6f", penwidth="2.5") result.set_node_defaults( fontname="Arimo", fontcolor="#ffffff", color="#6f6f6f", fillcolor="#009641", width="1.5", style='"rounded,filled"', shape="box", ) return result
def export(digraph: Subgraph, name: str = "a") -> None: """Generate the dependency digraph plot. Exports the generated digraph from 'build' to 'name'.png file. :param digraph: Dot digraph from 'build'. :type digraph: Dot :param name: export file's basename. :type name: str """ graph = Dot() graph.add_subgraph(digraph) graph.write(name + ".dot") result = graph.create(format="png") if result is None: print("Error!") pass else: with open(name + ".png", "wb") as file: file.write(result) pass pass pass
# -*- coding: utf-8 -*- # coding:utf-8 from pydotplus import Dot, Edge, Node from PIL import Image from q41 import make_chunk_list from q42 import extract_surface txt_path = '../5/ai.ja.txt.parsed' sentences = make_chunk_list(txt_path) sentence_idx = 7 sentence = sentences[sentence_idx] graph = Dot(graph_type='digraph') graph.set_fontname('MS Gothic') # make Node and Edge for id, chunk in enumerate(sentence): word = extract_surface(sentences, sentence_idx, id) node = Node(id, label=word) graph.add_node(node) if chunk.dst != -1: edge = Edge(id, chunk.dst) graph.add_edge(edge) graph.write_png('sentence.png') Image.open('sentence.png')
def __init__(self, *args, **kwargs): self._drawing = Dot(*args, **kwargs) self._frames = []
class MyGraph: def __init__(self, *args, **kwargs): self._drawing = Dot(*args, **kwargs) self._frames = [] def get_node(self, name): return self._drawing.get_node(str(name))[0] def change_color_node(self, name, color): node = self.get_node(name) node.obj_dict['attributes']['color'] = color def get_edge(self, src, dest): return self._drawing.get_edge(src, dest) def change_color_edge(self, src, dest, color): edge = self.get_edge(src, dest)[0] edge.obj_dict['attributes']['color'] = color def make_node(self, name): return Node( name, style='filled', color='turquoise', labelloc='b', fontname="Times-Roman:bold", fontcolor='black', fontsize=50, ) def add_nodes(self, *nodes_names): for name in nodes_names: node = self.make_node(name) self._drawing.add_node(node) def link(self, src, dst, w, color=None): if color: self._drawing.add_edge( Edge(src, dst, label=w, fontcolor='blue', color=color, fontsize=50, penwidth=15)) else: self._drawing.add_edge( Edge(src, dst, label=w, fontcolor='blue', fontsize=50, penwidth=15)) def get_image(self): img = self._drawing.create_png() stream = BytesIO(img) img = Image.open(stream) return img def save_img(self, img_name): self._frames.append(self.get_image()) self._frames[-1].save( img_name + '.png', format="PNG", )
def __init__(self, *args, **kwargs): self._drawing = Dot(*args, **kwargs) self._adjs = {} self._marked = {} self._frames = []
class MyGraph: def __init__(self, *args, **kwargs): self._drawing = Dot(*args, **kwargs) self._adjs = {} self._marked = {} self._frames = [] def add_cluster(self, name, label): cluster = Cluster(name) cluster.set_label(label) self._drawing.add_subgraph(cluster) def get_node(self, name): return self._drawing.get_node(str(name))[0] def make_node(self, name): return Node( name, shape='none', style='filled', color='azure2', image='voter.png', labelloc='b', fontname="Times-Roman:bold", fixedsize='true', width=1.0, height=1.0, fontcolor='white', fontsize=15, ) def add_nodes(self, *nodes_names): this_path = path.dirname(__file__) this_path = path.join(this_path, 'images', 'voter.png') self._drawing.shape_files = [this_path] for name in nodes_names: node = self.make_node(name) self._drawing.add_node(node) self._adjs[name] = [] self._marked[name] = False def add_nodes_cluster(self, cluster_name, *nodes_names): for name in nodes_names: node = self.make_node(name) cluster = self._drawing.get_subgraph("cluster_" + cluster_name) cluster[0].add_node(node) if cluster_name is not "unknows": self._frames.append(self.get_image()) def del_node_cluster(self, cluster_name, node): cluster = self._drawing.get_subgraph("cluster_" + cluster_name) cluster[0].del_node(str(node)) self._frames.append(self.get_image()) def link(self, src, dst): self._adjs[src].append(dst) self._adjs[dst].append(src) src = self.get_node(src) dst = self.get_node(dst) self._drawing.add_edge(Edge(src, dst)) self._frames.append(self.get_image()) def mark_node(self, name, color): node = self.get_node(name) node.set_style('filled') node.set_fillcolor(color) self._marked[name] = True self._frames.append(self.get_image()) def get_image(self): img = self._drawing.create_png() stream = BytesIO(img) img = Image.open(stream) return img def is_node_marked(self, name): return self._marked[name] def bfs(self, name, color, cluster=None): to_visit = [] to_visit.append(name) self.mark_node(name, color) if cluster is not None: self.add_nodes_cluster(cluster, name) self.del_node_cluster("unknows", name) while to_visit: visiting = to_visit.pop(0) for v in self._adjs[visiting]: if not self.is_node_marked(v): self.mark_node(v, color) to_visit.append(v) if cluster is not None: self.add_nodes_cluster(cluster, v) self.del_node_cluster("unknows", v) def count_not_checked_components(self, color): count = 0 for v in self._adjs.keys(): if not self.is_node_marked(v): self.add_cluster( f"unknows_{count+1}", f"Grupo #{count+1} de votos com valor desconhecido") self.bfs(v, color, f"unknows_{count+1}") count += 1 return count def save_gif(self, file_name): self._preprocess_frames() self._frames[0].save(file_name + '.gif', format="GIF", append_images=self._frames[1:], save_all=True, duration=len(self._frames) * 10, loop=0) def save_img(self, img_name): self._frames[-1].save( img_name + '.png', format="PNG", ) def _preprocess_frames(self): biggest_w = max(i.width for i in self._frames) biggest_h = max(i.height for i in self._frames) for i, old_frame in enumerate(self._frames): frame = Image.new('RGBA', (biggest_w, biggest_h), (255, 255, 255, 255)) frame.paste(old_frame) self._frames[i] = frame for i in range(5): self._frames.append(self._frames[-1])
def get(self) -> Dot: """Return pydot graph representation of message.""" result = Dot(graph_name=self.__message.full_name) result.set_graph_defaults(splines="ortho", ranksep="0.8 equally") result.set_edge_defaults(fontname="Fira Code", fontcolor="#6f6f6f", color="#6f6f6f") result.set_node_defaults( fontname="Arimo", fontcolor="#ffffff", color="#6f6f6f", fillcolor="#009641", width="1.5", style='"rounded,filled"', shape="box", ) result.add_node( Node(name="Initial", fillcolor="#ffffff", shape="circle", width="0.5", label="")) for f in self.__message.fields: result.add_node(Node(name=f.name)) for l in self.__message.structure: result.add_edge( Edge(src=l.source.name, dst=l.target.name, xlabel=self.__edge_label(l))) result.add_node( Node(name="Final", fillcolor="#6f6f6f", shape="circle", width="0.5", label="")) return result
class MyGraph: def __init__(self, *args, **kwargs): self._drawing = Dot(*args, **kwargs) self._frames = [] def get_node(self, name): return self._drawing.get_node(str(name))[0] def make_node(self, name): return Node( name, style='filled', color='turquoise', labelloc='b', fontname="Times-Roman:bold", fontcolor='black', fontsize=40, ) def add_nodes(self, *nodes_names): for name in nodes_names: node = self.make_node(name) self._drawing.add_node(node) def link(self, src, dst, label_edge, w=None): if label_edge is "any": font_color = "darkgreen" elif label_edge is "none": font_color = "red" else: font_color = "indigo" if w: label_edge = f"{w} ({label_edge})" self._drawing.add_edge( Edge(src, dst, label=label_edge, fontcolor=font_color, fontsize=40)) else: self._drawing.add_edge( Edge(src, dst, label=label_edge, fontcolor=font_color, fontsize=40)) def get_image(self): img = self._drawing.create_png() stream = BytesIO(img) img = Image.open(stream) return img def save_img(self, img_name): self._frames.append(self.get_image()) self._frames[-1].save( img_name + '.png', format="PNG", )
def dotgraph(graph): __graph = Dot(rankdir='TB', fontname="Fangsong", fontcolor='blue', label="有向图的示例") __graph.set_type('digraph') __graph.set_name('digraph_demo') __graph.set_node_defaults(fontname="Fangsong", style='filled', fillcolor='yellow') __graph.set_edge_defaults(fontname="Fangsong", color='black') for key, value in graph.items(): # 若节点没有特殊label或者其他属性需求 # 可以直接以节点名称显示 # 直接标记方向,不用手动添加 # node = Node(key) # __graph.add_node(node) for v in value: edge = Edge(key, v) __graph.add_edge(edge) ret = __graph.write_raw("demo.dot") if ret is not True: print('生成demo.dot失败') ret = __graph.write_svg("demo.svg") if ret is not True: print('生成graph.svg失败') # ret = __graph.write_png("demo.png") # if ret is not True: # print('生成graph.png失败') return __graph
class Tree(object): def __init__(self, root=None): # 添加一个没有数据的 HEAD self._root = root # Dot self.graph = Dot(rankdir='TB') self.graph.set_type('digraph') self.graph.set_name('Tree') def __str__(self): return str(self._root) __repr__ = __str__ def type_check(fun): def type_check_wapper(self, *args, **kw): if len(args) != 1 or not isinstance(*args, int): raise ValueError('类"{}" -> 方法"{}" -> 参数"{}" 无效'.format( self.__class__.__name__, fun.__name__, args)) fun(self, *args, **kw) return type_check_wapper @type_check def append(self, value): node = TreeNode(value) # DOT添加新节点 self.graph.add_node(node.dot_node()) if self._root is None: self._root = node else: queue = deque() queue.append(self._root) while queue: cur = queue.popleft() if cur.left is None: cur.add_left(node) # DOT 添加 edge 左子树 self.dot_add_edge_left(cur, node) return elif cur.right is None: cur.add_right(node) # dot添加 edge 右子树 self.dot_add_edge_right(cur, node) return else: # 若左右都不为空,则给判断列表加入子树,继续进行子树判断 queue.append(cur.left) queue.append(cur.right) """ # 2019.04.14 23:44:00 # 之所以屏蔽,这种函数多重包含的原因是 # 遍历的时候向使用生成器 yield # 但是似乎,函数嵌套了之后,yield会出现和预期不一致的现象? # def traversal(self, mode='breadth'): if self._root is None: print('空树') else: if mode == 'breadth': print('----- 广度优先遍历 -----', end='\n') self.__traversal_breadth_first() elif mode in ('depth', 'preorder', 'inorder', 'postorder'): print('----- 深度优先遍历 -----', end=' ') self.__traversal_depth_first(mode) else: raise ValueError('类"{}" -> 方法"{}" -> 参数"{}" 无效'.format( self.__class__.__name__, self.traversal.__name__, mode)) def __traversal_depth_first(self, mode='preorder'): if mode == 'preorder' or mode == 'depth': self.__traversal_preorder(self._root) elif mode == 'inorder': self.__traversal_inorder() elif mode == 'postorder': self.__traversal_postorder() else: raise ValueError('类"{}" -> 方法"{}" -> 参数"{}" 无效'.format( self.__class__.__name__, self.__traversal_depth_first.__name__, mode)) print('') """ def traversal_breadth_first(self): """ 广度优先遍历 """ queue = deque() queue.append(self._root) while queue: cur = queue.popleft() if cur is None: continue # print(str(cur) + ' -> ', end='') yield cur queue.append(cur.left) queue.append(cur.right) # print('') # def __traversal_preorder(self, root): def traversal_preorder(self): """ 深度优先遍历 -> 前序遍历 """ # 递归实现 # if root is None: # return # print(root, end=' -> ') # self.__traversal_preorder(root.left) # self.__traversal_preorder(root.right) # 非递归实现 # print('<前序遍历>') queue = deque() cur = self._root while queue or cur: if cur: # print(cur, end=' -> ') yield cur queue.append(cur) cur = cur.left else: cur = queue.pop() cur = cur.right def traversal_inorder(self): """ 深度优先遍历 -> 中序遍历 """ # 非递归实现 # print('<中序遍历>') queue = deque() cur = self._root while queue or cur: if cur: queue.append(cur) cur = cur.left else: cur = queue.pop() # print(cur, end=' -> ') yield cur cur = cur.right def traversal_postorder(self): """ 深度优先遍历 -> 后序遍历 """ # print('<后序遍历>') # """ # # 方法一 # # 借助的思想: # # 前序遍历:根 -> 左 -> 右 # # 后续遍历: 左 -> 右 -> 根 (相当于 前序遍历的先右后左 情况,的逆序) # # 因此: # # 1. 前序遍历,先右后左 # # 2. 利用一个新栈,进行逆序 # """ # queue_temp = deque() # queue = deque() # cur = self._root # while queue or cur: # if cur: # queue_temp.append(cur) # queue.append(cur) # cur = cur.right # else: # cur = queue.pop() # cur = cur.left # for i in range(len(queue_temp)): # print(queue_temp.pop(), end=' -> ') """ # 方法二 # 借助的思想: # 加一个判断量,若当前节点的左右节点都已经被访问过了,那么也需要直接打印 # 为什么直接cur.right==pre也可以呢? ----- 这种说法错误,若某节点仅存在左子树的时候,就不行了 # 其实是和我压栈的顺序相关的 # 右子树后出,因此上一次弹出的子树为右子树的时候,就可以证明左子树必定访问过了 """ queue = deque() queue.append(self._root) pre = None while queue: cur = queue[-1] # 获取栈顶元素 # if (cur.left is None and cur.right is None) or\ # (pre is not None and (cur.right == pre)): # 此法考虑不够全面 if (cur.left is None and cur.right is None) or\ (pre is not None and (cur.left is pre or cur.right is pre)): # print(cur, end=' -> ') yield cur cur = queue.pop() pre = cur else: if cur.right: queue.append(cur.right) if cur.left: queue.append(cur.left) def dot_add_edge_left(self, node_src, node_des): if not isinstance(node_src, TreeNode) or not isinstance( node_src, TreeNode): raise ValueError('类"{}" -> 方法"{}" -> 参数"{}"or"{}" 无效'.format( self.__class__.__name__, fun.__name__, node_src, node_des)) edge = Edge(node_src.dot_left(), node_des.dot_value()) self.graph.add_edge(edge) edge = Edge(node_des.dot_parent(), node_src.dot_value(), color='red') self.graph.add_edge(edge) def dot_add_edge_right(self, node_src, node_des): if not isinstance(node_src, TreeNode) or not isinstance( node_src, TreeNode): raise ValueError('类"{}" -> 方法"{}" -> 参数"{}"or"{}" 无效'.format( self.__class__.__name__, fun.__name__, node_src, node_des)) edge = Edge(node_src.dot_right(), node_des.dot_value()) self.graph.add_edge(edge) edge = Edge(node_des.dot_parent(), node_src.dot_value(), color='red') self.graph.add_edge(edge) def dot_show(self): ret = self.graph.write_raw("demo.dot") if ret is not True: print('生成demo.dot失败') ret = self.graph.write_svg("graph.svg") if ret is not True: print('生成graph.svg失败') os.system("graph.svg")
# png和jpg生成的中文是乱码,不知道为啥。svg没有乱码问题 graph.write_png("graph.png") # 将dot源码写入文件"demo.dot" ret = graph.write_raw("demo.dot") print(ret) #返回True """ import pydotplus import sys import os from pydotplus import graph_from_dot_data from pydotplus import Dot, Node, Edge graph = Dot(rankdir='TB') graph.set_type('digraph') graph.set_name('Dot_Demo') data = {'start': '开始', '1': '第一步', '2': '第二步', '3': '第三步', 'end': '结束'} node_name = tuple(data.keys()) graph.set_node_defaults(shape='record') # 将结点和边关联 i = 0 for key, value in data.items(): if i == 0 or i == len(data) - 1: # node label中{}的作用,相当于开辟新的作用域,且垂直水平方向会相对于当前来进行切换 """ digraph G {
def write_graph(graph: Dot, filename: Path, fmt: str = "svg") -> None: log.info("Creating %s", filename) with open(filename, "wb") as f: graph.write(f, format=fmt)