def construct_directed_graph(collections_data: List[CollectionData]) -> AGraph: graph = AGraph(directed=True, fontzise=10, fontname='Verdana') graph.node_attr['fontname'] = 'Verdana' graph.node_attr['shape'] = 'record' collection_direction_order_ids = [ collection.id for collection in collections_data ] collection_names = [collection.name for collection in collections_data] # draw "y axe" with tree ordering graph.add_nodes_from(collection_names, shape='plaintext', fontsize=14) graph.add_edges_from(zip(collection_names, collection_names[1:])) graph.add_subgraph(collection_names) # combine all pages in one graph for collection_data in collections_data: for page in collection_data.pages: node = get_node(page) graph.add_node(node, label=page.title) # don't include reversed relations: edges = get_edges(page, collection_direction_order_ids) graph.add_edges_from(edges) # align all nodes for one level in one line (include element from "y" line for alignment) one_level_nodes = [collection_data.name] + [ get_node(page) for page in collection_data.pages ] graph.add_subgraph(one_level_nodes, None, rank='same') return graph
def cm_json_to_graph(cm_json): """Return pygraphviz Agraph from Kappy's contact map JSON. Parameters ---------- cm_json : dict A JSON dict which contains a contact map generated by Kappy. Returns ------- graph : pygraphviz.Agraph A graph representing the contact map. """ cmap_data = get_cmap_data_from_json(cm_json) # Initialize the graph graph = AGraph() # In this loop we add sites as nodes and clusters around sites to the # graph. We also collect edges to be added between sites later. edges = [] for node_idx, node in enumerate(cmap_data): sites_in_node = [] for site_idx, site in enumerate(node['node_sites']): # We map the unique ID of the site to its name site_key = (node_idx, site_idx) sites_in_node.append(site_key) graph.add_node(site_key, label=site['site_name'], style='filled', shape='ellipse') # Each port link is an edge from the current site to the # specified site if not site['site_type'] or not site['site_type'][0] == 'port': continue # As of kappy 4.1.2, the format of port links have changed # Old format: [[1, 0]], New format: [[[0, 1], 0]] for port_link in site['site_type'][1]['port_links']: port_link = tuple([ link[1] if isinstance(link, list) else link for link in port_link ]) if isinstance(port_link, list): port_link = port_link[1] edge = (site_key, tuple(port_link)) edges.append(edge) graph.add_subgraph(sites_in_node, name='cluster_%s' % node['node_type'], label=node['node_type']) # Finally we add the edges between the sites for source, target in edges: graph.add_edge(source, target) return graph
def render(self, filename): g = AGraph(strict=False, directed=True) # create nodes for frame_id, node in self.callers.items(): label = "{ %s }" % node g.add_node(frame_id, shape='Mrecord', label=label, fontsize=13, labelfontsize=13) # create edges for frame_id, node in self.callers.items(): child_nodes = [] for child_id in node.child_methods: child_nodes.append(child_id) g.add_edge(frame_id, child_id) # order edges l to r if len(child_nodes) > 1: sg = g.add_subgraph(child_nodes, rank='same') sg.graph_attr['rank'] = 'same' prev_node = None for child_node in child_nodes: if prev_node: sg.add_edge(prev_node, child_node, color="#ffffff") prev_node = child_node g.layout() g.draw(path=filename, prog='dot') print("callviz: rendered to %s" % filename) self.clear()
def render(self, filename): g = AGraph(strict=False, directed=True) # create nodes for frame_id, node in self.callers.items(): label = "{ %s }" % node g.add_node(frame_id, shape='Mrecord', label=label, fontsize=13, labelfontsize=13) # create edges for frame_id, node in self.callers.items(): child_nodes = [] for child_id in node.child_methods: child_nodes.append(child_id) g.add_edge(frame_id, child_id) # order edges l to r if len(child_nodes) > 1: sg = g.add_subgraph(child_nodes, rank='same') sg.graph_attr['rank'] = 'same' prev_node = None for child_node in child_nodes: if prev_node: sg.add_edge(prev_node, child_node, color="#ffffff") prev_node = child_node g.layout() g.draw(path=filename, prog='dot') print("rendered to %s" % filename) self.clear()
def cm_json_to_graph(im_json): """Return pygraphviz Agraph from Kappy's contact map JSON. Parameters ---------- im_json : dict A JSON dict which contains a contact map generated by Kappy. Returns ------- graph : pygraphviz.Agraph A graph representing the contact map. """ cmap_data = im_json['contact map']['map'] # Initialize the graph graph = AGraph() # In this loop we add sites as nodes and clusters around sites to the # graph. We also collect edges to be added between sites later. edges = [] for node_idx, node in enumerate(cmap_data): sites_in_node = [] for site_idx, site in enumerate(node['node_sites']): # We map the unique ID of the site to its name site_key = (node_idx, site_idx) sites_in_node.append(site_key) graph.add_node(site_key, label=site['site_name'], style='filled', shape='ellipse') # Each port link is an edge from the current site to the # specified site if not site['site_type'] or not site['site_type'][0] == 'port': continue for port_link in site['site_type'][1]['port_links']: edge = (site_key, tuple(port_link)) edges.append(edge) graph.add_subgraph(sites_in_node, name='cluster_%s' % node['node_type'], label=node['node_type']) # Finally we add the edges between the sites for source, target in edges: graph.add_edge(source, target) return graph
def plot(table_names=None): """ Plot relationships between columns and tables using Graphviz. Parameters ---------- table_names : iterable of str, optional Names of UrbanSim registered tables to plot. Defaults to all registered tables. Returns ------- graph : pygraphviz.AGraph PyGraphviz graph object. """ if not table_names: # Default to all registered tables. table_names = simulation.list_tables() graph = AGraph(directed=True) graph.graph_attr['fontname'] = 'Sans' graph.graph_attr['fontsize'] = 28 graph.node_attr['shape'] = 'box' graph.node_attr['fontname'] = 'Sans' graph.node_attr['fontcolor'] = 'blue' graph.edge_attr['weight'] = 2 # Add each registered table as a subgraph with columns as nodes. for table_name in table_names: subgraph = graph.add_subgraph(name='cluster_' + table_name, label=table_name, fontcolor='red') table = simulation.get_table(table_name) for column_name in table.columns: full_name = table_name + '.' + column_name subgraph.add_node(full_name, label=column_name) # Iterate over computed columns to build nodes. for key, wrapped_col in simulation._COLUMNS.items(): table_name = key[0] column_name = key[1] # Combine inputs from argument names and argument default values. args = list(wrapped_col._argspec.args) if wrapped_col._argspec.defaults: default_args = list(wrapped_col._argspec.defaults) else: default_args = [] inputs = args[:len(args) - len(default_args)] + default_args # Create edge from each input column to the computed column. for input_name in inputs: full_name = table_name + '.' + column_name graph.add_edge(input_name, full_name) graph.layout(prog='dot') return graph
def cm_json_to_graph(im_json): """Return pygraphviz Agraph from Kappy's contact map JSON. Parameters ---------- im_json : dict A JSON dict which contains a contact map generated by Kappy. Returns ------- graph : pygraphviz.Agraph A graph representing the contact map. """ cmap_data = im_json['contact map']['map'] # Initialize the graph graph = AGraph() # In this loop we add sites as nodes and clusters around sites to the # graph. We also collect edges to be added between sites later. edges = [] for node_idx, node in enumerate(cmap_data): sites_in_node = [] for site_idx, site in enumerate(node['node_sites']): # We map the unique ID of the site to its name site_key = (node_idx, site_idx) sites_in_node.append(site_key) graph.add_node(site_key, label=site['site_name'], style='filled', shape='ellipse') # Each port link is an edge from the current site to the # specified site if not site['site_type'] or not site['site_type'][0] == 'port': continue for port_link in site['site_type'][1]['port_links']: edge = (site_key, tuple(port_link)) edges.append(edge) graph.add_subgraph(sites_in_node, name='cluster_%s' % node['node_type'], label=node['node_type']) # Finally we add the edges between the sites for source, target in edges: graph.add_edge(source, target) return graph
def plot(table_names=None): """ Plot relationships between columns and tables using Graphviz. Parameters ---------- table_names : iterable of str, optional Names of UrbanSim registered tables to plot. Defaults to all registered tables. Returns ------- graph : pygraphviz.AGraph PyGraphviz graph object. """ if not table_names: # Default to all registered tables. table_names = simulation.list_tables() graph = AGraph(directed=True) graph.graph_attr['fontname'] = 'Sans' graph.graph_attr['fontsize'] = 28 graph.node_attr['shape'] = 'box' graph.node_attr['fontname'] = 'Sans' graph.node_attr['fontcolor'] = 'blue' graph.edge_attr['weight'] = 2 # Add each registered table as a subgraph with columns as nodes. for table_name in table_names: subgraph = graph.add_subgraph(name='cluster_' + table_name, label=table_name, fontcolor='red') table = simulation.get_table(table_name) for column_name in table.columns: full_name = table_name + '.' + column_name subgraph.add_node(full_name, label=column_name) # Iterate over computed columns to build nodes. for key, wrapped_col in simulation._COLUMNS.items(): table_name = key[0] column_name = key[1] # Combine inputs from argument names and argument default values. args = list(wrapped_col._argspec.args) if wrapped_col._argspec.defaults: default_args = list(wrapped_col._argspec.defaults) else: default_args = [] inputs = args[:len(args) - len(default_args)] + default_args # Create edge from each input column to the computed column. for input_name in inputs: full_name = table_name + '.' + column_name graph.add_edge(input_name, full_name) graph.layout(prog='dot') return graph
def _generate_legend(graph: pgv.AGraph): # create subgraph called legends legend = graph.add_subgraph(name=f"cluster_legends", label="Legend", nodesep="0.25", ranksep="0.25") # change graph legend.add_node("legend_m", color="red", label="Machine", shape="box") legend.add_node("legend_s", color="green", label="Sequential", shape="box") legend.add_node("legend_p", color="blue", label="Parallel", shape="box")
def get_dot(self, labeller=None): self.labeller = labeller a_graph = AGraph(directed=True) nx_graph = self.graph.nx_graph # TODO: Add some default stuff? # a_graph.graph_attr.update(N.graph.get('graph',{})) # a_graph.node_attr.update(N.graph.get('node',{})) # a_graph.edge_attr.update(N.graph.get('edge',{})) structural_nodes = [] output_nodes = [] input_nodes = [] # First, add nodes for node in nx_graph.nodes(): name, attrs = self.get_node_attributes(node) if self.graph.is_input(node): input_nodes.append(name) elif self.graph.is_structural(node): structural_nodes.append(name) elif self.graph.is_output(node): output_nodes.append(name) # Keep a reference to the original node a_graph.add_node(name, **attrs) # We need to add subgraphs to cluster stuff on rank sub = a_graph.add_subgraph(input_nodes, name='input') sub.graph_attr['rank'] = 'source' sub = a_graph.add_subgraph(structural_nodes, name='structural') sub.graph_attr['rank'] = 'same' sub = a_graph.add_subgraph(output_nodes, name='output') sub.graph_attr['rank'] = 'sink' # Now add edges for u, v, edgedata in nx_graph.edges_iter(data=True): attrs = {} a_graph.add_edge(self.graph.node_to_name(u), self.graph.node_to_name(v), **attrs) return a_graph
class Visualizer: def __init__(self, hsm): self.graph = AGraph(strict=False, directed=True, name=type(hsm).__name__) self._load_transitions(hsm) def _load_transitions(self, hsm, group=None): prefix = group + "." if group else "" nodes = [] for t in hsm.transitions: # if origin is an HSM we have to connect from it's final node if issubclass(t["from"], HSM): u = prefix + t["from"].__name__ + ".FINAL" else: u = prefix + t["from"].__name__ nodes.append(u) # if we connect to an HSM we must create a new substructure and load from the hsm recursively if issubclass(t["to"], HSM): sub = t["to"].__name__ v = prefix + sub + "." + t["to"].init_state.__name__ nodes.append(v) self._load_transitions(t["to"], group=sub) # there is always only one FAILED elif issubclass(t["to"], FAILED): v = FAILED.__name__ else: v = prefix + t["to"].__name__ nodes.append(v) # finally add it to the graph self.graph.add_edge(u, v, label=self._get_condition_string( t["condition"])) sg = self.graph.add_subgraph(nodes, name="cluster_" + prefix, style="dotted") #TODO not done here yet def _get_condition_string(self, cond): if isinstance(cond, dict): return str(list(cond.keys())[0].name) + ": " + str( list(cond.values())[0]) elif callable(cond): return cond.__name__ return cond.name def save_graph(self, filename): self.graph.layout(prog="dot") self.graph.draw(filename)
def draw(self, path="graph.pdf"): # TODO add edges for shared state try: from pygraphviz import AGraph def add_graph(g: AGraph, layer_graph: tx.Graph, cluster): for node in layer_graph.nodes: # HTML for record nodes https://graphviz.org/doc/info/shapes.html#top g.add_node(f"{cluster}_{node.name}", shape="none", margin=0, label=tx.utils.vizstyle(node)) for node in layer_graph.nodes: for other_node in layer_graph.edges_out[node]: g.add_edge(f"{cluster}_{node.name}", f"{cluster}_{other_node.name}") dg = AGraph(directed=True) if self.run_graph and self.run_graph.nodes: dg.add_subgraph(name="cluster_run", label="run") g = dg.subgraphs()[-1] add_graph(g, self.run_graph, cluster="run") if self.train_graph and self.train_graph.nodes: dg.add_subgraph(name="cluster_train", label="train") g = dg.subgraphs()[-1] add_graph(g, self.train_graph, "train") if self.eval_graph and self.eval_graph.nodes: dg.add_subgraph(name="cluster_eval", label="eval") g = dg.subgraphs()[-1] add_graph(g, self.eval_graph, cluster="eval") dg.layout(prog="dot") dg.draw(path=path) except ImportError: raise ImportError("Could't find required pygraphviz module")
def draw_graph(input_file, out, ref_chain=[], aim_chain=[], freq_min=1, draw_all=False): ps = AGraph(directed=True) ps.graph_attr['rankdir'] = 'LR' ps.graph_attr['mode'] = 'hier' nodes = delete_nodes(ref_chain, input_file[1], freq_min) print('Number of nodes: ', end='') if draw_all == False: print(len(nodes)) elif draw_all == True: print(len(input_file[1])) cluster_main = ps.add_subgraph() cluster_main.graph_attr['rank'] = '0' for i in range(len(ref_chain)): shape = 'circle' if ref_chain[i] in aim_chain: cluster_main.add_node(ref_chain[i], shape=shape, color='red') else: cluster_main.add_node(ref_chain[i], shape=shape, color='pink') for i in input_file[0]: if 'PATH' in i: shape = 'box' if i in aim_chain or i in ref_chain: continue if i in nodes: ps.add_node(str(i)) continue else: if draw_all == True: ps.add_node(str(i), color='grey') continue for i in input_file[1]: color = 'black' try: if ref_chain.index(i[1]) - ref_chain.index(i[0]) == 1: color = 'red' ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) continue except ValueError: pass if i[2] < freq_min: if draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') continue elif i[0] in nodes and i[1] in nodes: ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) elif draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') ps.draw(out + '.ps', prog='dot') ps.write(out + '.dot')
class GraphGeneratingReporter(BaseReporter): def __init__(self): self.evolution = [] # List[str] self._evaluating = None # Dict[Candidate, Set[Requirement]] self._dependencies = defaultdict(set) # Dict[Candidate.name, Counter[Requirement]] self._active_requirements = defaultdict(Counter) self._node_names = {} self._counter = count() self.graph = AGraph( directed=True, rankdir="LR", labelloc="top", labeljust="center", nodesep="0", concentrate="true", ) self.graph.add_node("root", label=":root:", shape="Mdiamond") self._node_names[self._key(None)] = "root" del self.graph.node_attr["label"] self.graph.edge_attr.update({ "arrowhead": "empty", "style": "dashed", "color": "#808080" }) # # Internal Graph-handling API # def _prepare_node(self, obj): cls = obj.__class__.__name__ n = next(self._counter) node_name = f"{cls}_{n}" self._node_names[self._key(obj)] = node_name return node_name def _key(self, obj): if obj is None: return None return ( obj.__class__.__name__, repr(obj), ) def _get_subgraph(self, name, *, must_exist_already=True): name = canonicalize_name(name) c_name = f"cluster_{name}" subgraph = self.graph.get_subgraph(c_name) if subgraph is None: if must_exist_already: existing = [s.name for s in self.graph.subgraphs_iter()] raise RuntimeError( f"Graph for {name} not found. Existing: {existing}") else: subgraph = self.graph.add_subgraph(name=c_name, label=name) return subgraph def _add_candidate(self, candidate): if candidate is None: return if self._key(candidate) in self._node_names: return node_name = self._prepare_node(candidate) # A candidate is only seen after a requirement with the same name. subgraph = self._get_subgraph(candidate.name, must_exist_already=True) subgraph.add_node(node_name, label=candidate.version, shape="box") def _add_requirement(self, req): if self._key(req) in self._node_names: return name = self._prepare_node(req) subgraph = self._get_subgraph(req.name, must_exist_already=False) subgraph.add_node(name, label=str(req.specifier) or "*", shape="cds") def _ensure_edge(self, from_, *, to, **attrs): from_node = self._node_names[self._key(from_)] to_node = self._node_names[self._key(to)] try: existing = self.graph.get_edge(from_node, to_node) except KeyError: attrs.update(headport="w", tailport="e") self.graph.add_edge(from_node, to_node, **attrs) else: existing.attr.update(attrs) def _get_node_for(self, obj): node_name = self._node_names[self._key(obj)] node = self.graph.get_node(node_name) assert node is not None return node_name, node def _track_evaluating(self, candidate): if self._evaluating != candidate: if self._evaluating is not None: self.backtracking(self._evaluating, internal=True) self.evolution.append(self.graph.to_string()) self._evaluating = candidate # # Public reporter API # def starting(self): print("starting(self)") def starting_round(self, index): print(f"starting_round(self, {index})") # self.graph.graph_attr["label"] = f"Round {index}" self.evolution.append(self.graph.to_string()) def ending_round(self, index, state): print(f"ending_round(self, {index}, state)") def ending(self, state): print("ending(self, state)") def adding_requirement(self, req, parent): print(f"adding_requirement(self, {req!r}, {parent!r})") self._track_evaluating(parent) self._add_candidate(parent) self._add_requirement(req) self._ensure_edge(parent, to=req) self._active_requirements[canonicalize_name(req.name)][req] += 1 self._dependencies[parent].add(req) if parent is None: return # We're seeing the parent candidate (which is being "evaluated"), so # color all "active" requirements pointing to the it. # TODO: How does this interact with revisited candidates? for parent_req in self._active_requirements[canonicalize_name( parent.name)]: self._ensure_edge(parent_req, to=parent, color="#80CC80") def backtracking(self, candidate, internal=False): print(f"backtracking(self, {candidate!r}, internal={internal})") self._track_evaluating(candidate) self._evaluating = None # Update the graph! node_name, node = self._get_node_for(candidate) node.attr.update(shape="signature", color="red") for edge in self.graph.out_edges_iter([node_name]): edge.attr.update(style="dotted", arrowhead="vee", color="#FF9999") _, to = edge to.attr.update(color="black") for edge in self.graph.in_edges_iter([node_name]): edge.attr.update(style="dotted", color="#808080") # Trim "active" requirements to remove anything not relevant now. for requirement in self._dependencies[candidate]: active = self._active_requirements[canonicalize_name( requirement.name)] active[requirement] -= 1 if not active[requirement]: del active[requirement] def pinning(self, candidate): print(f"pinning(self, {candidate!r})") assert self._evaluating == candidate or self._evaluating is None self._evaluating = None self._add_candidate(candidate) # Update the graph! node_name, node = self._get_node_for(candidate) node.attr.update(color="#80CC80") # Requirement -> Candidate edges, from this candidate. for req in self._active_requirements[canonicalize_name( candidate.name)]: self._ensure_edge(req, to=candidate, arrowhead="vee", color="#80CC80") # Candidate -> Requirement edges, from this candidate. for edge in self.graph.out_edges_iter([node_name]): edge.attr.update(style="solid", arrowhead="vee", color="#80CC80") _, to = edge to.attr.update(color="#80C080")
def _recursive_visualize_state(state: State, graph: pgv.AGraph, visited_list: typing.List[str], leaf_list: typing.Mapping[str, str], root: bool = False) -> str: # get name of state state_name = state._name label_name = state_name if root: label_name = f"[init]{label_name}" parent_name = graph.name # remove cluster if it is part of it if parent_name.startswith("cluster_"): parent_name = parent_name[8:] global_name = f"{parent_name}_{state_name}" valid_node_name = "" # [Base Case] ignore if we already visited it. if state_name in visited_list: return # Check if its a nest class or machine sub_graph = None if not hasattr(state, "_children") and not isinstance(state, Machine): # add it to the graph graph.add_node(global_name, label=label_name) valid_node_name = global_name else: sub_graph = graph.add_subgraph(name=f"cluster_{global_name}", label=label_name) if isinstance(state, Machine): state: Machine sub_graph.graph_attr["pencolor"] = "red" valid_node_name = _recursive_visualize_state(state._root, sub_graph, [], {}, True) else: if isinstance(state, SequentialState) or isinstance(state, SelectorState): sub_graph.graph_attr["pencolor"] = "green" if isinstance(state, SelectorState): sub_graph.graph_attr["pencolor"] = "yellow" prev_valid_name = "" for children in state._children: valid_node_name = _recursive_visualize_state(children, sub_graph, [], {}) if prev_valid_name != "": sub_graph.add_edge(prev_valid_name, valid_node_name) prev_valid_name = valid_node_name else: sub_graph.graph_attr["pencolor"] = "blue" for children in state._children: valid_node_name = _recursive_visualize_state(children, sub_graph, [], {}) # registered as visited visited_list.append(state_name) leaf_list[state_name] = valid_node_name # Create connection between each states. for transition in state._transitions: # get references to the next state nxt_state = transition[1] nxt_state_name = nxt_state._name # run the recursive visualization function if not visted: if nxt_state_name not in visited_list: nxt_valid_node_name = _recursive_visualize_state(nxt_state, graph, visited_list, leaf_list) else: # we get a valid node to connect the clusters. nxt_valid_node_name = leaf_list[nxt_state_name] # construct the name if its a cluster nxt_cluster_name = f"cluster_{parent_name}_{nxt_state_name}" # HACK: graphviz require nodes to be linked up and cannot use cluster. Their way is to just hide it if graph.get_subgraph(nxt_cluster_name) is None: if sub_graph is None: graph.add_edge(valid_node_name, nxt_valid_node_name) else: graph.add_edge(valid_node_name, nxt_valid_node_name, ltail=sub_graph.name) else: nxt_graph = graph.get_subgraph(nxt_cluster_name) if sub_graph is None: graph.add_edge(valid_node_name, nxt_valid_node_name, lhead=nxt_graph.name) else: graph.add_edge(valid_node_name, nxt_valid_node_name, ltail=sub_graph.name, lhead=nxt_cluster_name) return valid_node_name
class UmlPygraphVizDiagram(): """ Creates a diagram similar to the class diagrams and objects diagrams from UML using pygraphviz """ def __init__(self): logging.basicConfig() self.graph = AGraph(directed=True, strict=False) self.graph.node_attr['shape'] = 'record' self.graph.graph_attr['fontsize'] = '8' self.graph.graph_attr['fontname'] = "Bitstream Vera Sans" self.graph.graph_attr['label'] = "" self.connected_nodes = set() self.described_nodes = set() def _add_node(self, node_id, node_label): self.graph.add_node(node_id, label=node_label) def add_class_node(self, class_name, attributes): self.described_nodes.add(class_name) label = "<{<b>%s</b> | %s }>" % ( class_name, "<br align='left'/>".join(attributes).strip() + "<br align='left'/>") self.subgraph.add_node(graphviz_id(class_name), label=label) def add_object_node(self, object_name, class_name, attributes): self.described_nodes.add(object_name) if class_name: label = "<{<b><u>%s (%s)</u></b>| %s }>" % ( object_name, class_name, "<br align='left'/>".join(attributes) + "<br align='left'/>") else: label = "<{<b><u>%s</u></b>| %s }>" % ( object_name, "<br align='left'/>".join(attributes) + "<br align='left'/>") self.subgraph.add_node(graphviz_id(object_name), label=label) def add_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open") def add_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=card + "..." + card, labelangle=-65.0) def add_min_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=card + "...*", labelangle=-65.0) def add_max_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel="0..." + card, labelangle=-65.0) def add_min_max_cardinality_edge(self, src, dst, name, min, max): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=min + "..." + max, labelangle=-65.0) def add_list_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowtail="ediamond", dir="back", headlabel="0...*", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0) # self.graph.add_edge(graphviz_id(src), graphviz_id(dst),label=name,arrowtail="ediamond", dir="back",headlabel="0...*", taillabel=(dst.split(":")[1])+"s",labeldistance=2.0,labelfontcolor="black") def add_symmetric_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="none") def add_functional_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", headlabel="1...1", taillabel="0...*", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0) def add_inversefunctional_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", headlabel="0...*", taillabel="1...1", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0) def add_equivalentclass_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label="\<\<equivalentClass\>\>", arrowhead="none", style="dashed") def add_unionof_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label="\<\<unionOf\>\>", arrowhead="open", style="dashed") def add_oneof_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label="\<\<instanceOf\>\>", arrowhead="open", style="dashed", dir="back") def add_subclass_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), arrowhead="empty") def set_label(self, label): self.graph.graph_attr['label'] = label def start_subgraph(self, graph_name): self.subgraph = self.graph.add_subgraph(name="cluster_%s" % graphviz_id(graph_name)) self.subgraph.graph_attr['label'] = graph_name def add_undescribed_nodes(self): s = self.connected_nodes - self.described_nodes for node in s: self.graph.add_node(graphviz_id(node), label=node) def write_to_file(self, filename_dot): f = open(filename_dot, 'w') f.write(self.graph.string()) print("dot file created: " + filename_dot) def visualize(self, filename, namespaceList=None): self.graph.layout(prog='dot') self.graph.draw(filename) if filename.endswith(".svg"): self._add_links_to_svg_file(filename, namespaceList) print("graphic file created: " + filename) def _add_links_to_svg_file(self, output, namespaceList=None): # SVG Datei anpassen svg_string = open(output).read() # Titel der SVG Datei anpassen svg_string = svg_string.replace("%3", output) # Hyperlinks mit den Internetseiten hinzufügen for ns in namespaceList: namespace = str(ns[0]) # Präfix des Namespaces url = str(ns[1]) # URL des Namespaces if namespace: regex_str = """%s:(\w+)""" % namespace regex = re.compile(regex_str) svg_string = regex.sub( """<a xlink:href='%s\\1'>%s:\\1</a>""" % (url, namespace), svg_string) # Datei schreiben svg_file = open(output, "w") svg_file.write(svg_string) svg_file.close()
def convert(graph, desired_ns=[], exclude_ns=[]): # graph.parse('rdf-schema.ttl', format='turtle') # network.feedFactsToAdd(generateTokenSet(graph)) # for n in network.inferredFacts.triples((None, None, None)): # graph.add(n) agraph = AGraph(directed=True, clusterrank="global", rankdir="LR") namespaces = {} nsm = graph.namespace_manager deferred_resources = set() included_resources = set() def prefix(ressource): return nsm.qname(ressource).split(':')[0] def add_ressource(ressource): if ressource not in included_resources: qname = nsm.qname(ressource) prefix = qname.split(':')[0] shape = 'rect' if (ressource, RDF.type, OWL.Class) in graph else 'oval' color = 'black' if prefix in desired_ns else 'grey' if prefix in namespaces: namespaces[prefix].add_node(qname, shape=shape, color=color) else: agraph.add_node(qname, shape=shape, color=color) included_resources.add(ressource) if ressource in deferred_resources: deferred_resources.remove(ressource) def add_edge(r1, r2, **kwargs): pr1, pr2 = prefix(r1), prefix(r2) if pr1 in exclude_ns or pr2 in exclude_ns: return if pr1 in desired_ns or pr2 in desired_ns: add_ressource(r1) add_ressource(r2) agraph.add_edge(nsm.qname(r1), nsm.qname(r2), **kwargs) for kprefix, namespace in graph.namespaces(): namespaces[kprefix] = agraph.add_subgraph(name="cluster_" + kprefix, color="grey") for k in graph.subjects(RDF.type, OWL.Class): if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subClassOf, None)), graph.triples((None, OWL.subClassOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") prop_types = [ OWL.Property, OWL.AnnotationProperty, OWL.DatatypeProperty, OWL.AsymmetricProperty, OWL.ObjectProperty, OWL.FunctionalProperty, OWL.InverseFunctionalProperty ] properties = set() for prop in prop_types: properties.update(graph.subjects(RDF.type, prop)) for k in properties: if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subPropertyOf, None)), graph.triples((None, OWL.subPropertyOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") for (s, p, o) in graph.triples((None, OWL.equivalentClass, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead="odot", arrowtail="odot", color="blue") for (s, p, o) in graph.triples((None, RDFS.domain, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") continue add_edge(o, s, arrowhead="open") for (s, p, o) in graph.triples((None, RDFS.range, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") continue add_edge(s, o, arrowhead="open") for (s, p, o) in graph.triples((None, OWL.inverseOf, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue if str(o) < str(s): s, o = o, s add_edge(o, s, arrowhead="crow", arrowtail="crow", dir="both") for ressource in included_resources: labels = graph.objects(ressource, RDFS.label) en_labels = [l for l in labels if l.language == 'eng'] if en_labels: label = en_labels[0] qname = nsm.qname(ressource) prefix, name = qname.split(':', 1) if normalize_label(name) != normalize_label(label): node = agraph.get_node(qname) node.attr['label'] = "%s\n(%s)" % (qname, label) return agraph
def dot_layout(cy_elements, edge_labels=False, subgraph_boxes=False, node_gt=None): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. edge_labels is true if labels should appear on edges subgraph_boxes is true if boxes should be drawn around subgraphs Returns the object. """ elements = cy_elements.elements # g = AGraph(directed=True, strict=False) g = AGraph(directed=True, strict=False, forcelabels=True) # make transitive relations appear top to bottom elements = list(elements) nodes_by_id = dict((e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [ (nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and "transitive" in e["data"] and e["data"]["transitive"] ] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # get the node id's and stable sort them by cluster # the idea here is to convert the graph into a dag by sorting # the nodes, then reversing the back edges. In particular, we try to make # all the edges between two clusters go in the same direction so clustering # doesn't result in horizontal edges, which dot renders badly. sorted_nodes = [e["data"]["id"] for e in elements if e["group"] == "nodes"] sorted_nodes = sorted(enumerate(sorted_nodes), key=lambda x: (nodes_by_id[x[1]]["data"]["cluster"], x[0])) sorted_nodes = [y for idx, y in sorted_nodes] node_key = dict((id, idx) for idx, id in enumerate(sorted_nodes)) if node_gt is None: node_gt = lambda X, y: False else: node_gt = lambda x, y: node_key[x] > node_key[y] # add nodes to the graph for e in elements: if e["group"] == "nodes" and e["classes"] != "non_existing": g.add_node(e["data"]["id"], label=e["data"]["label"].replace("\n", "\\n")) # TODO: remove this, it's specific to leader_demo weight = {"reach": 10, "le": 10, "id": 1} constraint = {"pending": False} # add edges to the graph for e in elements: if e["group"] == "edges": # kwargs = {'weight': weight.get(e["data"]["obj"], 0)}, kwargs = {"label": e["data"]["label"]} if edge_labels else {} if node_gt(e["data"]["source"], e["data"]["target"]): g.add_edge( e["data"]["target"], e["data"]["source"], e["data"]["id"], dir="back", **kwargs # constraint=constraint.get(e["data"]["obj"], True), ) else: g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], **kwargs # constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None and e["classes"] != "non_existing": clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph(name="cluster_{}".format(i), nbunch=clusters[k], rank="min") # now get positions, heights, widths, and bsplines g.layout(prog="dot") # get the y origin. we want the top left of the graph to be a # fixed coordinate (hopefully (0,0)) so the graph doesn't jump when # its height changes. Unfortunately, pygraphviz has a bug a gives # the wrong bbox, so we compute the max y coord. # bbox = pygraphviz.graphviz.agget(g.handle,'bb') global y_origin y_origin = 0.0 for n in g.nodes(): top = float(n.attr["pos"].split(",")[1]) + float(n.attr["height"]) / 2 if top > y_origin: y_origin = top if subgraph_boxes: for sg in g.subgraphs(): top = float(sg.graph_attr["bb"].split(",")[3]) if top > y_origin: y_origin = top for e in elements: if e["group"] == "nodes" and e["classes"] != "non_existing": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr["pos"]) e["data"]["width"] = 72 * float(attr["width"]) e["data"]["height"] = 72 * float(attr["height"]) elif e["group"] == "edges": if node_gt(e["data"]["source"], e["data"]["target"]): attr = g.get_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"]).attr pos = attr["pos"] pe = pos.split() ppe = pe[1:] ppe.reverse() pos = " ".join([pe[0].replace("s", "e")] + ppe) else: attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr pos = attr["pos"] e["data"].update(_to_edge_position(pos)) if edge_labels and e["data"]["label"] != "": e["data"]["lp"] = _to_position(attr["lp"]) # g.draw('g.png') if subgraph_boxes: for sg in g.subgraphs(): box = cy_elements.add_shape(sg.name, classes="subgraphs") coords = _to_coord_list(sg.graph_attr["bb"]) box["data"]["coords"] = coords return cy_elements
def get_graphviz_layout(input_subgraph, ref_chain=[], aim_chain=[], freq_min=1, draw_all=False): print('SD') ps = AGraph(directed=True) ps.graph_attr['rankdir'] = 'LR' ps.graph_attr['mode'] = 'hier' nodes = delete_nodes(ref_chain, input_subgraph[1], freq_min) print('Number of nodes: ', end='') if draw_all == False: print(len(nodes)) elif draw_all == True: print(len(input_subgraph[1])) cluster_main = ps.add_subgraph() cluster_main.graph_attr['rank'] = '0' for i in range(len(ref_chain)): shape = 'circle' if ref_chain[i] in aim_chain: cluster_main.add_node(ref_chain[i], shape=shape, color='red') else: cluster_main.add_node(ref_chain[i], shape=shape, color='pink') for i in input_subgraph[0]: if i in aim_chain or i in ref_chain: continue if i in nodes: ps.add_node(str(i)) continue else: if draw_all == True: ps.add_node(str(i), color='grey') continue for i in input_subgraph[1]: color = 'black' try: if ref_chain.index(i[1]) - ref_chain.index(i[0]) == 1: color = 'red' ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) continue except ValueError: pass if i[2] < freq_min: if draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') continue elif i[0] in nodes and i[1] in nodes: ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) elif draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') ps.layout(prog='dot') positions = {n: n.attr['pos'] for n in ps.nodes()} edge_points = {edge: edge.attr['pos'] for edge in ps.edges()} return positions, edge_points
def draw_graph(input_file, out, ref_chain=[], aim_chain=[], freq_min=1, draw_all=False): ps = AGraph(directed=True) ps.graph_attr['rankdir'] = 'LR' ps.graph_attr['mode'] = 'hier' # Deleting nodes that occures less than freq_min times nodes = delete_nodes(ref_chain, input_file[1], freq_min) print('Number of nodes: ', end='') if draw_all == False: print(len(nodes)) elif draw_all == True: print(len(input_file[1])) cluster_main = ps.add_subgraph() cluster_main.graph_attr['rank'] = '0' nodes_list = [] for i in range(len(ref_chain)): shape = 'circle' if ref_chain[i] in aim_chain: cluster_main.add_node(ref_chain[i], shape=shape, color='red') nodes_list.append({ 'id': ref_chain[i], 'shape': shape, 'color': 'red' }) else: cluster_main.add_node(ref_chain[i], shape=shape, color='pink') nodes_list.append({ 'id': ref_chain[i], 'shape': shape, 'color': 'pink' }) for i in input_file[0]: if 'PATH' in i: shape = 'box' if i in aim_chain or i in ref_chain: continue if i in nodes: ps.add_node(str(i)) nodes_list.append({'id': str(i), 'shape': shape, 'color': 'green'}) continue else: if draw_all == True: nodes_list.append({ 'id': str(i), 'shape': shape, 'color': 'grey' }) ps.add_node(str(i), color='grey') continue print(nodes_list) edges_list = [] for i in input_file[1]: color = 'black' try: if ref_chain.index(i[1]) - ref_chain.index(i[0]) == 1: color = 'red' ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) edges_list.append({ 'source': str(i[0]), 'target': str(i[1]), 'color': color, 'penwidth': str(math.sqrt(i[2])) }) continue except ValueError: pass if i[2] < freq_min: if draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') edges_list.append({ 'source': str(i[0]), 'target': str(i[1]), 'color': 'grey', 'penwidth': str(math.sqrt(i[2])) }) continue elif i[0] in nodes and i[1] in nodes: ps.add_edge(str(i[0]), str(i[1]), color=color, penwidth=str(math.sqrt(i[2]))) edges_list.append({ 'source': str(i[0]), 'target': str(i[1]), 'color': color, 'penwidth': str(math.sqrt(i[2])) }) elif draw_all == True: ps.add_edge(str(i[0]), str(i[1]), color='grey', penwidth=str(math.sqrt(i[2])), constraint='false') edges_list.append({ 'source': str(i[0]), 'target': str(i[1]), 'color': 'grey', 'penwidth': str(math.sqrt(i[2])) }) print(edges_list) ps.draw(out + '.ps', prog='dot', format='png') ps.write(out + '.dot')
class UmlPygraphVizDiagram: """ Creates a diagram similar to the class diagrams and objects diagrams from UML using pygraphviz """ def __init__(self): logging.basicConfig() self.graph = AGraph(directed=True, strict=False) self.graph.node_attr["shape"] = "record" self.graph.graph_attr["fontsize"] = "8" self.graph.graph_attr["fontname"] = "Bitstream Vera Sans" self.graph.graph_attr["label"] = "" self.connected_nodes = set() self.described_nodes = set() def _add_node(self, node_id, node_label): self.graph.add_node(node_id, label=node_label) def add_class_node(self, class_name, attributes): self.described_nodes.add(class_name) label = "<{<b>%s</b> | %s }>" % ( class_name, "<br align='left'/>".join(attributes).strip() + "<br align='left'/>", ) self.subgraph.add_node(graphviz_id(class_name), label=label) def add_object_node(self, object_name, class_name, attributes): self.described_nodes.add(object_name) if class_name: label = "<{<b><u>%s (%s)</u></b>| %s }>" % ( object_name, class_name, "<br align='left'/>".join(attributes) + "<br align='left'/>", ) else: label = "<{<b><u>%s</u></b>| %s }>" % ( object_name, "<br align='left'/>".join(attributes) + "<br align='left'/>", ) self.subgraph.add_node(graphviz_id(object_name), label=label) def add_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open") def add_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=card + "..." + card, labelangle=-65.0, ) def add_min_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=card + "...*", labelangle=-65.0, ) def add_max_cardinality_edge(self, src, dst, name, card): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel="0..." + card, labelangle=-65.0, ) def add_min_max_cardinality_edge(self, src, dst, name, min, max): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", labeldistance=2.0, headlabel=min + "..." + max, labelangle=-65.0, ) def add_list_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowtail="ediamond", dir="back", headlabel="0...*", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0, ) # self.graph.add_edge(graphviz_id(src), graphviz_id(dst),label=name,arrowtail="ediamond", dir="back",headlabel="0...*", taillabel=(dst.split(":")[1])+"s",labeldistance=2.0,labelfontcolor="black") def add_symmetric_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), label=name, arrowhead="none") def add_functional_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", headlabel="1...1", taillabel="0...*", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0, ) def add_inversefunctional_edge(self, src, dst, name): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label=name, arrowhead="open", headlabel="0...*", taillabel="1...1", labeldistance=2.0, labelfontcolor="black", labelangle=-65.0, ) def add_equivalentclass_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label="\<\<equivalentClass\>\>", arrowhead="none", style="dashed" ) def add_unionof_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label="\<\<unionOf\>\>", arrowhead="open", style="dashed" ) def add_oneof_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge( graphviz_id(src), graphviz_id(dst), label="\<\<instanceOf\>\>", arrowhead="open", style="dashed", dir="back" ) def add_subclass_edge(self, src, dst): self.connected_nodes.add(src) self.connected_nodes.add(dst) self.graph.add_edge(graphviz_id(src), graphviz_id(dst), arrowhead="empty") def set_label(self, label): self.graph.graph_attr["label"] = label def start_subgraph(self, graph_name): self.subgraph = self.graph.add_subgraph(name="cluster_%s" % graphviz_id(graph_name)) self.subgraph.graph_attr["label"] = graph_name def add_undescribed_nodes(self): s = self.connected_nodes - self.described_nodes for node in s: self.graph.add_node(graphviz_id(node), label=node) def write_to_file(self, filename_dot): f = open(filename_dot, "w") f.write(self.graph.string()) print("dot file created: " + filename_dot) def visualize(self, filename, namespaceList=None): self.graph.layout(prog="dot") self.graph.draw(filename) if filename.endswith(".svg"): self._add_links_to_svg_file(filename, namespaceList) print("graphic file created: " + filename) def _add_links_to_svg_file(self, output, namespaceList=None): # SVG Datei anpassen svg_string = open(output).read() # Titel der SVG Datei anpassen svg_string = svg_string.replace("%3", output) # Hyperlinks mit den Internetseiten hinzufügen for ns in namespaceList: namespace = str(ns[0]) # Präfix des Namespaces url = str(ns[1]) # URL des Namespaces regex_str = """%s:(\w+)""" % namespace regex = re.compile(regex_str) svg_string = regex.sub("""<a xlink:href='%s\\1'>%s:\\1</a>""" % (url, namespace), svg_string) # Datei schreiben svg_file = open(output, "w") svg_file.write(svg_string) svg_file.close()
def dot_layout(cy_elements, edge_labels=False, subgraph_boxes=False, node_gt=None): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. edge_labels is true if labels should appear on edges subgraph_boxes is true if boxes should be drawn around subgraphs Returns the object. """ elements = cy_elements.elements # g = AGraph(directed=True, strict=False) g = AGraph(directed=True, strict=False, forcelabels=True) # make transitive relations appear top to bottom elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [(nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and "transitive" in e["data"] and e["data"]["transitive"]] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # get the node id's and stable sort them by cluster # the idea here is to convert the graph into a dag by sorting # the nodes, then reversing the back edges. In particular, we try to make # all the edges between two clusters go in the same direction so clustering # doesn't result in horizontal edges, which dot renders badly. sorted_nodes = [e["data"]["id"] for e in elements if e["group"] == "nodes"] sorted_nodes = sorted(enumerate(sorted_nodes), key=lambda x: (nodes_by_id[x[1]]["data"]["cluster"], x[0])) sorted_nodes = [y for idx, y in sorted_nodes] node_key = dict((id, idx) for idx, id in enumerate(sorted_nodes)) if node_gt is None: node_gt = lambda X, y: False else: node_gt = lambda x, y: node_key[x] > node_key[y] # add nodes to the graph for e in elements: if e["group"] == "nodes" and e["classes"] != 'non_existing': g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": # kwargs = {'weight': weight.get(e["data"]["obj"], 0)}, kwargs = {'label': e["data"]["label"]} if edge_labels else {} if node_gt(e["data"]["source"], e["data"]["target"]): g.add_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"], dir='back', **kwargs #constraint=constraint.get(e["data"]["obj"], True), ) else: g.add_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"], **kwargs #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"][ "cluster"] is not None and e["classes"] != 'non_existing': clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], rank='min', ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') # get the y origin. we want the top left of the graph to be a # fixed coordinate (hopefully (0,0)) so the graph doesn't jump when # its height changes. Unfortunately, pygraphviz has a bug a gives # the wrong bbox, so we compute the max y coord. # bbox = pygraphviz.graphviz.agget(g.handle,'bb') global y_origin y_origin = 0.0 for n in g.nodes(): top = float(n.attr['pos'].split(',')[1]) + float(n.attr['height']) / 2 if top > y_origin: y_origin = top if subgraph_boxes: for sg in g.subgraphs(): top = float(sg.graph_attr['bb'].split(',')[3]) if top > y_origin: y_origin = top for e in elements: if e["group"] == "nodes" and e["classes"] != 'non_existing': attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": if node_gt(e["data"]["source"], e["data"]["target"]): attr = g.get_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"]).attr pos = attr['pos'] pe = pos.split() ppe = pe[1:] ppe.reverse() pos = ' '.join([pe[0].replace('s', 'e')] + ppe) else: attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr pos = attr['pos'] e["data"].update(_to_edge_position(pos)) if edge_labels and e["data"]["label"] != '': e["data"]["lp"] = _to_position(attr['lp']) # g.draw('g.png') if subgraph_boxes: for sg in g.subgraphs(): box = cy_elements.add_shape(sg.name, classes='subgraphs') coords = _to_coord_list(sg.graph_attr['bb']) box["data"]["coords"] = coords return cy_elements
def dot_layout(cy_elements): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. Returns the object. """ elements = cy_elements.elements g = AGraph(directed=True, strict=False) # make transitive relations appear top to bottom # TODO: make this not specific to leader example elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes" ) order = [ (nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and e["data"]["obj"] in ('reach', 'le') ] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # add nodes to the graph for e in elements: if e["group"] == "nodes": g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], weight=weight.get(e["data"]["obj"], 0), #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None: clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') for e in elements: if e["group"] == "nodes": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr e["data"].update(_to_edge_position(attr['pos'])) g.draw('g.png') return cy_elements
buildrequires.append(f"{br}") g = AGraph(directed=True, name="G", strict=False, label="Build Order Graph") ranks = {} refs = {} for key, value in yml['data']['components']['rpms'].items(): # Add each buildorder rank as a distinct sub-graph rank = value['buildorder'] if rank not in ranks: ranks[rank] = [key] else: ranks[rank].append(key) subg = g.get_subgraph(f"{rank}") if subg is None: subg = g.add_subgraph(name=f"{rank}", label=f"Build Order {rank}", rank="same") subg.add_node(f"{rank}") # Extract git ref from which to build if key not in refs: refs[key] = value['ref'] # Parse the dependency relationships reqs = [] breqs = [] api = False for r in value['rationale'].replace('\n', ' ').split('.'): r = r.strip() if not r: continue if r == 'Module API': api = True
def convert(graph, desired_ns=[], exclude_ns=[]): # graph.parse('rdf-schema.ttl', format='turtle') # network.feedFactsToAdd(generateTokenSet(graph)) # for n in network.inferredFacts.triples((None, None, None)): # graph.add(n) agraph = AGraph(directed=True, clusterrank="global", rankdir="LR") namespaces = {} nsm = graph.namespace_manager deferred_resources = set() included_resources = set() def prefix(ressource): return nsm.qname(ressource).split(':')[0] def add_ressource(ressource): if ressource not in included_resources: qname = nsm.qname(ressource) prefix = qname.split(':')[0] shape = 'rect' if ( ressource, RDF.type, OWL.Class) in graph else 'oval' color = 'black' if prefix in desired_ns else 'grey' if prefix in namespaces: namespaces[prefix].add_node(qname, shape=shape, color=color) else: agraph.add_node(qname, shape=shape, color=color) included_resources.add(ressource) if ressource in deferred_resources: deferred_resources.remove(ressource) def add_edge(r1, r2, **kwargs): pr1, pr2 = prefix(r1), prefix(r2) if pr1 in exclude_ns or pr2 in exclude_ns: return if pr1 in desired_ns or pr2 in desired_ns: add_ressource(r1) add_ressource(r2) agraph.add_edge(nsm.qname(r1), nsm.qname(r2), **kwargs) for kprefix, namespace in graph.namespaces(): namespaces[kprefix] = agraph.add_subgraph( name="cluster_"+kprefix, color="grey") for k in graph.subjects(RDF.type, OWL.Class): if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subClassOf, None)), graph.triples((None, OWL.subClassOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") prop_types = [OWL.Property, OWL.AnnotationProperty, OWL.DatatypeProperty, OWL.AsymmetricProperty, OWL.ObjectProperty, OWL.FunctionalProperty, OWL.InverseFunctionalProperty] properties = set() for prop in prop_types: properties.update(graph.subjects(RDF.type, prop)) for k in properties: if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subPropertyOf, None)), graph.triples((None, OWL.subPropertyOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") for (s, p, o) in graph.triples((None, OWL.equivalentClass, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead="odot", arrowtail="odot", color="blue") for (s, p, o) in graph.triples((None, RDFS.domain, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") continue add_edge(o, s, arrowhead="open") for (s, p, o) in graph.triples((None, RDFS.range, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") continue add_edge(s, o, arrowhead="open") for (s, p, o) in graph.triples((None, OWL.inverseOf, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue if str(o) < str(s): s, o = o, s add_edge(o, s, arrowhead="crow", arrowtail="crow", dir="both") for ressource in included_resources: labels = graph.objects(ressource, RDFS.label) en_labels = [l for l in labels if l.language == 'eng'] if en_labels: label = en_labels[0] qname = nsm.qname(ressource) prefix, name = qname.split(':', 1) if normalize_label(name) != normalize_label(label): node = agraph.get_node(qname) node.attr['label'] = "%s\n(%s)" % (qname, label) return agraph
use_case.add_edge("ecg_vlbw", "no hsPDA", color="green", constraint=False) use_case.add_edge("ecg_vlbw", "hsPDA", color="red") use_case.add_node("wait", label=insert_newline("consider watchful waiting and symptomatic treatment (>= 6 days postnatally)",width), shape="rectangle") use_case.add_edge("hsPDA", "wait") use_case.add_node("hsPDA_ib", label=insert_newline("consider treatment of symptomatic (> 2L/minute, >0.25 FiO2) infants with hsPDA with ibuprofen (>=6 days postnatally)",width), shape="rectangle") use_case.add_edge("hsPDA_ib", "wait", style="invis") # fake edge use_case.add_edge("hsPDA", "hsPDA_ib") use_case.add_node("ecg_repeat", label=insert_newline("reassess clinical status and echocardiography and consider repeating treatment",width), shape="rectangle") use_case.add_edge("wait", "ecg_repeat") use_case.add_edge("hsPDA_ib", "ecg_repeat") use_case.add_edge("ecg_repeat", "effective", color="green") use_case.add_edge("ecg_repeat", "not effective", color="red") use_case.add_edge("not effective", "consider rescue treatment (paracetamol)") use_case.add_node("close_duct", label=insert_newline("consider definite ductal closure by catheter intervention or surgical ligation if persistent and symptomatic over time",width), shape="rectangle") use_case.add_node("consider rescue treatment (paracetamol)", shape="rectangle") use_case.add_edge("consider rescue treatment (paracetamol)", "close_duct", label="if not effective", color="red", shape="rectangle") use_case.add_edge("not effective", "close_duct") use_case.add_edge("hsPDA", "close_duct", label="option") # https://groups.google.com/g/pygraphviz-discuss/c/t2KWtmpV-sc b = use_case.add_subgraph(["done_after_hsPDA", "ecg_assess"]) b.graph_attr['rank']='same' c = use_case.add_subgraph(["done_after_pda", "ecg_vlbw"]) c.graph_attr['rank']='same' d = use_case.add_subgraph(["no hsPDA", "hsPDA"]) d.graph_attr['rank']='same' use_case.write("pda_preterm.dot") use_case.draw("pda_preterm.png", format="png", prog="dot")
def dot_layout(cy_elements): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. Returns the object. """ elements = cy_elements.elements g = AGraph(directed=True, strict=False) # make transitive relations appear top to bottom # TODO: make this not specific to leader example elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [(nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and e["data"]["obj"] in ('reach', 'le')] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # add nodes to the graph for e in elements: if e["group"] == "nodes": g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], weight=weight.get(e["data"]["obj"], 0), #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None: clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') for e in elements: if e["group"] == "nodes": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr e["data"].update(_to_edge_position(attr['pos'])) g.draw('g.png') return cy_elements