def test_get_node(self): assert self.P3.get_node(1) == "1" one = self.P3.get_node(1) nh = one.get_handle() node = pgv.Node(self.P3, 1) assert node.get_handle() == nh assert node == "1" with pytest.raises(KeyError): pgv.Node(self.P3, 10)
def render_string_graph(string: str, start: str, end: str, transitions: TransitionsTable, name: str = 'output.png', draw: bool = True, engine: str = 'circo') -> gv.AGraph: ''' Given a string, a start state, an end state, end a transitions table, produces the graph resulting in the traversal of the string through the states defined in the transitions table. By default, it will output a png file of the result, but that can be suppressed. ''' graph = gv.AGraph(directed=True) graph.graph_attr['label'] = f'Evaluating {string}' node_names = it.count() current_state = start node_name = next(node_names) graph.add_node(node_name) current_node = gv.Node(graph, node_name) current_node.attr['label'] = current_state current_node.attr['fillcolor'] = '#0000FF' current_node.attr['style'] = 'filled' for letter in string: node_name = next(node_names) graph.add_node(node_name) next_node = gv.Node(graph, node_name) # TODO: The algorithm prioritizes just the first # found state, which may not produce a correct # answer. Needs to fix this next_state = transitions[current_state][letter][0] next_node.attr['label'] = next_state graph.add_edge(current_node, next_node, label=letter) current_node = next_node current_state = next_state if current_state == end: current_node.attr['style'] = 'filled' current_node.attr['fillcolor'] = '#00FF00' if draw: graph.layout(prog=engine) graph.draw(name) return graph
def pygraphviz_layout_with_rank(self, G, prog="dot", root=None, sameRank=[], args=""): try: import pygraphviz except ImportError: raise ImportError('requires pygraphviz ', 'http://networkx.lanl.gov/pygraphviz ', '(not available for Python3)') if root is not None: args += "-Groot=%s" % root A = nx.nx_agraph.to_agraph(G) for sameNodeHeight in sameRank: if type(sameNodeHeight) == str: print("node \"%s\" has no peers in its rank group" % sameNodeHeight) A.add_subgraph(sameNodeHeight, rank="same") A.layout(prog=prog, args=args) node_pos = {} for n in G: node = pygraphviz.Node(A, n) try: xx, yy = node.attr["pos"].split(',') node_pos[n] = (float(xx), float(yy)) except: print("no position for node", n) node_pos[n] = (0.0, 0.0) return node_pos
def test_get_node(self): assert_equal(self.P3.get_node(1), '1') one = self.P3.get_node(1) nh = one.get_handle() node = pgv.Node(self.P3, 1) assert_equal(node.get_handle(), nh) assert_equal(node, '1') assert_raises(KeyError, pgv.Node, self.P3, 10)
def pygraphviz_layout(G, prog="neato", root=None, args=""): """Create node positions for G using Graphviz. Parameters ---------- G : NetworkX graph A graph created with NetworkX prog : string Name of Graphviz layout program root : string, optional Root node for twopi layout args : string, optional Extra arguments to Graphviz layout program Returns ------- node_pos : dict Dictionary of x, y, positions keyed by node. Examples -------- >>> G = nx.petersen_graph() >>> pos = nx.nx_agraph.graphviz_layout(G) >>> pos = nx.nx_agraph.graphviz_layout(G, prog="dot") Notes ----- If you use complex node objects, they may have the same string representation and GraphViz could treat them as the same node. The layout may assign both nodes a single location. See Issue #1568 If this occurs in your case, consider relabeling the nodes just for the layout computation using something similar to:: >>> H = nx.convert_node_labels_to_integers(G, label_attribute="node_label") >>> H_layout = nx.nx_agraph.pygraphviz_layout(G, prog="dot") >>> G_layout = {H.nodes[n]["node_label"]: p for n, p in H_layout.items()} """ try: import pygraphviz except ImportError as err: raise ImportError( "requires pygraphviz " "http://pygraphviz.github.io/" ) from err if root is not None: args += f"-Groot={root}" A = to_agraph(G) A.layout(prog=prog, args=args) node_pos = {} for n in G: node = pygraphviz.Node(A, n) try: xs = node.attr["pos"].split(",") node_pos[n] = tuple(float(x) for x in xs) except: print("no position for node", n) node_pos[n] = (0.0, 0.0) return node_pos
def add_latents(self, *ls: Iterable[str]): ls = set(ls) for n in self.graph.nodes(): if n.name in ls: node_set_attr(n, self.LATENT, self.BUG_AVOID) ls.remove(n.name) for l in ls: n = g.Node(self.graph, name=l) node_set_attr(n, self.LATENT, self.BUG_AVOID) self.graph.add_node(n)
def exposure(self, exp: str): attr_set = False for n in self.graph.nodes(): if n.name == exp: node_set_attr(n, self.EXPOSURE, self.BUG_AVOID) if node_has_attr(n, self.EXPOSURE): node_del_attr(n, self.EXPOSURE) if not attr_set: n = g.Node(self.graph, exp) node_set_attr(n, self.EXPOSURE, self.BUG_AVOID) self.graph.add_node(n)
def outcome(self, out: str): attr_set = False for n in self.graph.nodes(): if n.name == out: node_set_attr(n, self.OUTCOME, self.BUG_AVOID) if node_has_attr(n, self.OUTCOME): node_del_attr(n, self.OUTCOME) if not attr_set: n = g.Node(self.graph, name=out) node_set_attr(n, self.OUTCOME, self.BUG_AVOID) self.graph.add_node(n)
def _graphvizNodePos(self, graph, nodeId): pos = None if pygraphviz is not None: node = pygraphviz.Node(graph, nodeId) if 'pos' in node.attr: pos = node.attr['pos'] else: node = graph.get_node(nodeId) if isinstance(node, pydot.Node): pos = node.get_pos()[1:-1] return pos
def pygraphviz_layout(self, G, prog="neato", bundle=False, root=None, args=""): if root is not None: args += "-Groot=%s" % root A = to_agraph(G) A.layout(prog=prog, args=args) node_pos = [] node_pos_dic = {} edge_pos = [] Nodes = G.nodes() Edges = G.edges() for n in G: node = pygraphviz.Node(A, n) try: xs = node.attr["pos"].split(",") npos = tuple(float(x) for x in xs) except: npos = (0.0, 0.0) node_pos_dic[n] = npos Nodes[n]["pos"] = npos node_pos.append(npos) if bundle: A.layout(prog="mingle") for source, target in Edges: edge = pygraphviz.Edge(A, source, target) edgepos = edge.attr["pos"] edgepos = edgepos.replace(u"\\", "") edgepos = edgepos.replace(u"\r", u"") edgepos = edgepos.replace(u"\n", u"") edgepos = edgepos.split(" ") tmp = [] for i in edgepos: if i != u"": ss = i.split(",") x = float(ss[0]) y = float(ss[1]) tmp.append((x, y)) edge_pos.append(tmp) Edges[(source, target)]["pos"] = tmp else: for source, target in Edges: posb = node_pos_dic[source] pose = node_pos_dic[target] posmx = (posb[0] + pose[0]) / 2 + (pose[1] - posb[1]) / 4 posmy = (posb[1] + pose[1]) / 2 + (posb[0] - pose[0]) / 4 tmp = curves.curve3_bezier( (posb[0], posb[1]), (posmx, posmy), (pose[0], pose[1]) ) edge_pos.append(tmp) Edges[(source, target)]["pos"] = tmp return node_pos, edge_pos
def get_hacked_pos(netx_graph, name_nodes=None, prog='dot'): import pygraphviz import networkx as netx # Add "invisible" edges to induce an ordering # Hack for layout (ordering of top level nodes) netx_graph2 = netx_graph.copy() if getattr(netx_graph, 'ttype2_cpds', None) is not None: grouped_nodes = [] for ttype in netx_graph.ttype2_cpds.keys(): ttype_cpds = netx_graph.ttype2_cpds[ttype] # use defined ordering ttype_nodes = ut.list_getattr(ttype_cpds, 'variable') # ttype_nodes = sorted(ttype_nodes) invis_edges = list(ut.itertwo(ttype_nodes)) netx_graph2.add_edges_from(invis_edges) grouped_nodes.append(ttype_nodes) A = netx.to_agraph(netx_graph2) for nodes in grouped_nodes: A.add_subgraph(nodes, rank='same') else: A = netx.to_agraph(netx_graph2) # if name_nodes is not None: # #netx.set_node_attributes(netx_graph, name='label', values={n: {'label': n} for n in all_nodes}) # invis_edges = list(ut.itertwo(name_nodes)) # netx_graph2.add_edges_from(invis_edges) # A.add_subgraph(name_nodes, rank='same') # else: # A = netx.to_agraph(netx_graph2) args = '' G = netx_graph A.layout(prog=prog, args=args) # A.draw('example.png', prog='dot') node_pos = {} for n in G: node_ = pygraphviz.Node(A, n) try: xx, yy = node_.attr['pos'].split(',') node_pos[n] = (float(xx), float(yy)) except Exception: logger.info('no position for node', n) node_pos[n] = (0.0, 0.0) return node_pos
def pygraphviz_layout(G, prog='neato', root=None, args=''): """Create node positions for G using Graphviz. Parameters ---------- G : NetworkX graph A graph created with NetworkX prog : string Name of Graphviz layout program root : string, optional Root node for twopi layout args : string, optional Extra arguments to Graphviz layout program Returns : dictionary Dictionary of x,y, positions keyed by node. Examples -------- >>> G=nx.petersen_graph() >>> pos=nx.graphviz_layout(G) >>> pos=nx.graphviz_layout(G,prog='dot') """ try: import pygraphviz except ImportError: raise ImportError( "pygraphviz_layout() requires pygraphviz: http://networkx.lanl.gov/pygraphviz (not available for Python3" ) A = to_agraph(G) if root is not None: args += "-Groot=%s" % root A.layout(prog=prog, args=args) node_pos = {} for n in G: node = pygraphviz.Node(A, n) try: xx, yy = node.attr["pos"].split(',') node_pos[n] = (float(xx), float(yy)) except: print("no position for node", n) node_pos[n] = (0.0, 0.0) return node_pos
def get_bayesnet_layout(model, name_nodes=None, prog='dot'): """ Ensures ordering of layers is in order of addition via templates """ import pygraphviz import networkx as nx # Add "invisible" edges to induce an ordering # Hack for layout (ordering of top level nodes) netx_graph2 = model.copy() if getattr(model, 'ttype2_cpds', None) is not None: grouped_nodes = [] for ttype in model.ttype2_cpds.keys(): ttype_cpds = model.ttype2_cpds[ttype] # use defined ordering ttype_nodes = ut.list_getattr(ttype_cpds, 'variable') # ttype_nodes = sorted(ttype_nodes) invis_edges = list(ut.itertwo(ttype_nodes)) netx_graph2.add_edges_from(invis_edges) grouped_nodes.append(ttype_nodes) agraph = nx.nx_agraph.to_agraph(netx_graph2) for nodes in grouped_nodes: agraph.add_subgraph(nodes, rank='same') else: agraph = nx.nx_agraph.to_agraph(netx_graph2) logger.info(agraph) args = '' agraph.layout(prog=prog, args=args) # agraph.draw('example.png', prog='dot') node_pos = {} for n in model: node_ = pygraphviz.Node(agraph, n) try: xx, yy = node_.attr['pos'].split(',') node_pos[n] = (float(xx), float(yy)) except Exception: logger.info('no position for node', n) node_pos[n] = (0.0, 0.0) return node_pos
def pygraphviz_layout(G, prog='neato', root=None, args=''): """ Create layout using pygraphviz and graphviz. Returns a dictionary of positions keyed by node. >>> G=nx.petersen_graph() >>> pos=nx.pygraphviz_layout(G) >>> pos=nx.pygraphviz_layout(G,prog='dot') """ A = to_agraph(G) if root is not None: args += "-Groot=%s" % root A.layout(prog=prog, args=args) node_pos = {} for n in G: node = pygraphviz.Node(A, n) try: xx, yy = node.attr["pos"].split(',') node_pos[n] = (float(xx), float(yy)) except: print "no position for node", n node_pos[n] = (0.0, 0.0) return node_pos
def apply(bpmn_graph, parameters=None): """ Layouts a BPMN graph (inserting the positions of the nodes and the layouting of the edges) Parameters ------------- bpmn_graph BPMN graph parameters Parameters of the algorithm Returns ------------- bpmn_graph BPMN graph with layout information """ if parameters is None: parameters = {} try: import pygraphviz except ImportError: raise ImportError('missing pygraphviz: ', 'http://pygraphviz.github.io/') nodes = bpmn_graph.get_nodes() flows = bpmn_graph.get_flows() graph = bpmn_graph.get_graph() # convert nx graph to pygraphviz graph A = pygraphviz.AGraph(name=bpmn_graph.get_name(), strict=True, directed=True, rankdir="LR") graph_nodes, graph_edges = get_sorted_nodes_edges(bpmn_graph) for n in graph_nodes: A.add_node(n) for tup in graph_edges: A.add_edge(tup[0], tup[1]) # use built-in layout function from pygraphviz A.layout(prog="dot") focus = exec_utils.get_param_value(Parameters.FOCUS, parameters, 0.42) scaling_fact_x = exec_utils.get_param_value(Parameters.SCALING_FACT_X, parameters, 320.0) * focus scaling_fact_y = exec_utils.get_param_value(Parameters.SCALING_FACT_Y, parameters, 150.0) * focus task_wh = exec_utils.get_param_value(Parameters.TASK_WH, parameters, 60) # add node positions to BPMN nodes for n in graph_nodes: node = pygraphviz.Node(A, n) xs = node.attr["pos"].split(',') node_pos = tuple(float(x) for x in xs) # width = round(100.0 * float(node.attr["width"]) / 7.0) n.set_x(int(node_pos[0])) n.set_y(int(node_pos[1])) n.set_height(task_wh) if isinstance(n, BPMN.Task): this_width = min(round(2 * task_wh), round(2 * (len(n.get_name()) + 7) * task_wh / 22.0)) n.set_width(this_width) else: n.set_width(task_wh) # stretch BPMN a bit, cause y coordinates are ususally pretty small compared to x max_node_x = max(node.get_x() for node in nodes) max_node_y = max(node.get_y() for node in nodes) different_x = len(set(node.get_x() for node in nodes)) different_y = len(set(node.get_y() for node in nodes)) stretch_fact_x = scaling_fact_x * different_x / max_node_x stretch_fact_y = scaling_fact_y * different_y / max_node_y for node in nodes: node.set_x(round(node.get_x() * stretch_fact_x)) node.set_y(round(node.get_y() * stretch_fact_y)) outgoing_edges = dict() ingoing_edges = dict() sources_dict = dict() targets_dict = dict() for flow in flows: source = flow.get_source() target = flow.get_target() x_src = source.get_x() x_trg = target.get_x() y_src = source.get_y() y_trg = target.get_y() sources_dict[(x_src, y_src)] = source targets_dict[(x_trg, y_trg)] = target diff_x = abs(x_trg - x_src) diff_y = abs(y_src - y_trg) if not (x_src, y_src) in outgoing_edges: outgoing_edges[(x_src, y_src)] = {} outgoing_edges[(x_src, y_src)][(x_trg, y_trg)] = {EndpointDirection.RIGHT: 0.0, EndpointDirection.LEFT: 0.0, EndpointDirection.TOP: 0.0, EndpointDirection.BOTTOM: 0.0} if not (x_trg, y_trg) in ingoing_edges: ingoing_edges[(x_trg, y_trg)] = {} ingoing_edges[(x_trg, y_trg)][(x_src, y_src)] = {EndpointDirection.RIGHT: 0.0, EndpointDirection.LEFT: 0.0, EndpointDirection.TOP: 0.0, EndpointDirection.BOTTOM: 0.0} if x_trg > x_src: outgoing_edges[(x_src, y_src)][(x_trg, y_trg)][EndpointDirection.RIGHT] = diff_x / (diff_x + diff_y) ingoing_edges[(x_trg, y_trg)][(x_src, y_src)][EndpointDirection.LEFT] = diff_x / (diff_x + diff_y) else: outgoing_edges[(x_src, y_src)][(x_trg, y_trg)][EndpointDirection.LEFT] = diff_x / (diff_x + diff_y) ingoing_edges[(x_trg, y_trg)][(x_src, y_src)][EndpointDirection.RIGHT] = diff_x / (diff_x + diff_y) if y_src > y_trg: outgoing_edges[(x_src, y_src)][(x_trg, y_trg)][EndpointDirection.TOP] = diff_y / (diff_x + diff_y) ingoing_edges[(x_trg, y_trg)][(x_src, y_src)][EndpointDirection.BOTTOM] = diff_y / (diff_x + diff_y) else: outgoing_edges[(x_src, y_src)][(x_trg, y_trg)][EndpointDirection.BOTTOM] = diff_y / (diff_x + diff_y) ingoing_edges[(x_trg, y_trg)][(x_src, y_src)][EndpointDirection.TOP] = diff_y / (diff_x + diff_y) # normalization outgoing_edges0 = deepcopy(outgoing_edges) ingoing_edges0 = deepcopy(ingoing_edges) for p1 in outgoing_edges: sum_right = 0.0 sum_left = 0.0 sum_top = 0.0 sum_bottom = 0.0 for p2 in outgoing_edges[p1]: sum_right += outgoing_edges0[p1][p2][EndpointDirection.RIGHT] sum_left += outgoing_edges0[p1][p2][EndpointDirection.LEFT] sum_top += outgoing_edges0[p1][p2][EndpointDirection.TOP] sum_bottom += outgoing_edges0[p1][p2][EndpointDirection.BOTTOM] if p1 in ingoing_edges: for p2 in ingoing_edges[p1]: sum_right += ingoing_edges0[p1][p2][EndpointDirection.RIGHT] sum_left += ingoing_edges0[p1][p2][EndpointDirection.LEFT] sum_top += ingoing_edges0[p1][p2][EndpointDirection.TOP] sum_bottom += ingoing_edges0[p1][p2][EndpointDirection.BOTTOM] for p2 in outgoing_edges[p1]: if sum_right > 0: outgoing_edges[p1][p2][EndpointDirection.RIGHT] = outgoing_edges[p1][p2][ EndpointDirection.RIGHT] ** 2 / sum_right if sum_left > 0: outgoing_edges[p1][p2][EndpointDirection.LEFT] = outgoing_edges[p1][p2][ EndpointDirection.LEFT] ** 2 / sum_left if sum_top > 0: outgoing_edges[p1][p2][EndpointDirection.TOP] = outgoing_edges[p1][p2][ EndpointDirection.TOP] ** 2 / sum_top if sum_bottom > 0: outgoing_edges[p1][p2][EndpointDirection.BOTTOM] = outgoing_edges[p1][p2][ EndpointDirection.BOTTOM] ** 2 / sum_bottom for p1 in ingoing_edges: sum_right = 0.0 sum_left = 0.0 sum_top = 0.0 sum_bottom = 0.0 for p2 in ingoing_edges[p1]: sum_right += ingoing_edges0[p1][p2][EndpointDirection.RIGHT] sum_left += ingoing_edges0[p1][p2][EndpointDirection.LEFT] sum_top += ingoing_edges0[p1][p2][EndpointDirection.TOP] sum_bottom += ingoing_edges0[p1][p2][EndpointDirection.BOTTOM] if p1 in outgoing_edges: for p2 in outgoing_edges[p1]: sum_right += outgoing_edges0[p1][p2][EndpointDirection.RIGHT] sum_left += outgoing_edges0[p1][p2][EndpointDirection.LEFT] sum_top += outgoing_edges0[p1][p2][EndpointDirection.TOP] sum_bottom += outgoing_edges0[p1][p2][EndpointDirection.BOTTOM] for p2 in ingoing_edges[p1]: if sum_right > 0: ingoing_edges[p1][p2][EndpointDirection.RIGHT] = ingoing_edges[p1][p2][ EndpointDirection.RIGHT] ** 2 / sum_right if sum_left > 0: ingoing_edges[p1][p2][EndpointDirection.LEFT] = ingoing_edges[p1][p2][ EndpointDirection.LEFT] ** 2 / sum_left if sum_top > 0: ingoing_edges[p1][p2][EndpointDirection.TOP] = ingoing_edges[p1][p2][ EndpointDirection.TOP] ** 2 / sum_top if sum_bottom > 0: ingoing_edges[p1][p2][EndpointDirection.BOTTOM] = ingoing_edges[p1][p2][ EndpointDirection.BOTTOM] ** 2 / sum_bottom # keep best direction for p1 in outgoing_edges: for p2 in outgoing_edges[p1]: vals = sorted([(x, y) for x, y in outgoing_edges[p1][p2].items()], key=lambda x: x[1], reverse=True) outgoing_edges[p1][p2] = vals[0][0] for p1 in ingoing_edges: for p2 in ingoing_edges[p1]: vals = sorted([(x, y) for x, y in ingoing_edges[p1][p2].items()], key=lambda x: x[1], reverse=True) ingoing_edges[p1][p2] = vals[0][0] total_counter = dict() partial_counter = dict() for p1 in outgoing_edges: if p1 not in total_counter: total_counter[p1] = Counter() for p2 in outgoing_edges[p1]: dir = outgoing_edges[p1][p2] total_counter[p1][dir] += 1 for p1 in ingoing_edges: if p1 not in total_counter: total_counter[p1] = Counter() for p2 in ingoing_edges[p1]: dir = ingoing_edges[p1][p2] total_counter[p1][dir] += 1 outgoing_edges_dirs = deepcopy(outgoing_edges) ingoing_edges_dirs = deepcopy(ingoing_edges) # decide exiting/entering point for edges for p1 in outgoing_edges: node = sources_dict[p1] if p1 not in partial_counter: partial_counter[p1] = Counter() sorted_outgoing_edges = sorted(outgoing_edges[p1], key=lambda x: x, reverse=False) for p2 in sorted_outgoing_edges: dir = outgoing_edges[p1][p2] partial_counter[p1][dir] += 1 if dir == EndpointDirection.RIGHT: outgoing_edges[p1][p2] = get_right_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.LEFT: outgoing_edges[p1][p2] = get_left_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.TOP: outgoing_edges[p1][p2] = get_top_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.BOTTOM: outgoing_edges[p1][p2] = get_bottom_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) for p1 in ingoing_edges: node = targets_dict[p1] if p1 not in partial_counter: partial_counter[p1] = Counter() sorted_ingoing_edges = sorted(ingoing_edges[p1], key=lambda x: x, reverse=False) for p2 in sorted_ingoing_edges: dir = ingoing_edges[p1][p2] partial_counter[p1][dir] += 1 if dir == EndpointDirection.RIGHT: ingoing_edges[p1][p2] = get_right_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.LEFT: ingoing_edges[p1][p2] = get_left_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.TOP: ingoing_edges[p1][p2] = get_top_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) elif dir == EndpointDirection.BOTTOM: ingoing_edges[p1][p2] = get_bottom_edge_coord(node, p1, partial_counter[p1], total_counter[p1]) # order the left-entering ingoing edges better for p1 in ingoing_edges: vals = [(x, y) for x, y in ingoing_edges[p1].items() if y[0] == p1[0]] if len(vals) > 1: vals_x = [x[0] for x in vals] vals_y = [x[1] for x in vals] vals_x = sorted(vals_x) vals_y = sorted(vals_y) for i in range(len(vals_x)): ingoing_edges[p1][vals_x[i]] = vals_y[i] # set waypoints for edges for flow in flows: source = flow.get_source() target = flow.get_target() flow.del_waypoints() x_src = source.get_x() x_trg = target.get_x() y_src = source.get_y() y_trg = target.get_y() p1 = (x_src, y_src) p2 = (x_trg, y_trg) source_x = outgoing_edges[p1][p2][0] source_y = outgoing_edges[p1][p2][1] target_x = ingoing_edges[p2][p1][0] target_y = ingoing_edges[p2][p1][1] dir_source = outgoing_edges_dirs[p1][p2] dir_target = ingoing_edges_dirs[p2][p1] middle_x = (source_x + target_x) / 2.0 middle_y = (source_y + target_y) / 2.0 flow.add_waypoint((source_x, source_y)) if dir_source in [EndpointDirection.LEFT, EndpointDirection.RIGHT]: if dir_target in [EndpointDirection.LEFT, EndpointDirection.RIGHT]: flow.add_waypoint((middle_x, source_y)) flow.add_waypoint((middle_x, target_y)) elif dir_target in [EndpointDirection.TOP, EndpointDirection.BOTTOM]: flow.add_waypoint((target_x, source_y)) elif dir_source in [EndpointDirection.TOP, EndpointDirection.BOTTOM]: if dir_target in [EndpointDirection.TOP, EndpointDirection.BOTTOM]: flow.add_waypoint((source_x, middle_y)) flow.add_waypoint((target_x, middle_y)) elif dir_target in [EndpointDirection.LEFT, EndpointDirection.RIGHT]: flow.add_waypoint((source_x, target_y)) flow.add_waypoint((target_x, target_y)) return bpmn_graph
def to_agraph(N, graph_attr=None, node_attr=None, strict=True): """Return a pygraphviz graph from a NetworkX graph N. If N is a Graph or DiGraph, graphviz attributes can be supplied through the arguments graph_attr: dictionary with default attributes for graph, nodes, and edges keyed by 'graph', 'node', and 'edge' to attribute dictionaries node_attr: dictionary keyed by node to node attribute dictionary If N has an dict N.graph_attr an attempt will be made first to copy properties attached to the graph (see from_agraph) and then updated with the calling arguments if any. """ directed = N.directed strict = not N.multigraph # FIXME and N.number_of_selfloops()==0 A = pygraphviz.AGraph(name=N.name, strict=strict, directed=directed) # default graph attributes try: A.graph_attr.update(N.graph_attr['graph']) except: pass try: A.graph_attr.update(graph_attr['graph']) except: pass # default node attributes try: A.node_attr.update(N.graph_attr['node']) except: pass try: A.node_attr.update(graph_attr['node']) except: pass # default edge attributes try: A.edge_attr.update(N.graph_attr['edge']) except: pass try: A.edge_attr.update(graph_attr['edge']) except: pass # add nodes for n in N: A.add_node(n) node = pygraphviz.Node(A, n) # try node attributes attached to graph try: if n in N.node_attr: node.attr.update(N.node_attr[n]) except: pass # update with attributes from calling parameters try: if n in node_attr: node.attr.update(node_attr[n]) except: pass # loop over edges for e in N.edges_iter(): if len(e) == 2: (u, v) = e d = None else: (u, v, d) = e if d is None: # no data, just add edge A.add_edge(u, v) else: if hasattr(d, "__iter__"): # edge data is dictionary-like, treat it as attributes # check for user assigned key if 'key' in d: key = d['key'] del d['key'] else: key = str(d) data = d else: # edge data is some other object key = str(d) data = {'data': key} A.add_edge(u, v, key=key, **data) edge = pygraphviz.Edge(A, u, v, key) return A
def make_agraph(graph_, inplace=False): import pygraphviz patch_pygraphviz() if not inplace: graph_ = graph_.copy() # Convert to agraph format num_nodes = len(graph_) LARGE_GRAPH = 100 is_large = num_nodes > LARGE_GRAPH if is_large: print('Making agraph for large graph %d nodes. ' 'May take time' % (num_nodes)) # nx_ensure_agraph_color(graph_) # Reduce size to be in inches not pixels # FIXME: make robust to param settings # Hack to make the w/h of the node take thae max instead of # dot which takes the minimum shaped_nodes = [n for n, d in graph_.nodes(data=True) if 'width' in d] node_dict = graph_.nodes node_attrs = ub.dict_take(node_dict, shaped_nodes) width_px = np.array([n['width'] for n in node_attrs]) height_px = np.array([n['height'] for n in node_attrs]) scale = np.array([n.get('scale', 1.0) for n in node_attrs]) inputscale = 72.0 width_in = width_px / inputscale * scale height_in = height_px / inputscale * scale width_in_dict = dict(zip(shaped_nodes, width_in)) height_in_dict = dict(zip(shaped_nodes, height_in)) nx.set_node_attributes(graph_, name='width', values=width_in_dict) nx.set_node_attributes(graph_, name='height', values=height_in_dict) nx_delete_node_attr(graph_, name='scale') # Check for any nodes with groupids node_to_groupid = nx.get_node_attributes(graph_, 'groupid') if node_to_groupid: groupid_to_nodes = ub.group_items(*zip(*node_to_groupid.items())) else: groupid_to_nodes = {} # Initialize agraph format nx_delete_None_edge_attr(graph_) agraph = nx.nx_agraph.to_agraph(graph_) # Add subgraphs labels # TODO: subgraph attrs group_attrs = graph_.graph.get('groupattrs', {}) for groupid, nodes in groupid_to_nodes.items(): # subgraph_attrs = {} subgraph_attrs = group_attrs.get(groupid, {}).copy() cluster_flag = True # FIXME: make this more natural to specify if 'cluster' in subgraph_attrs: cluster_flag = subgraph_attrs['cluster'] del subgraph_attrs['cluster'] name = groupid if cluster_flag: # graphviz treast subgraphs labeld with cluster differently name = 'cluster_' + groupid else: name = groupid agraph.add_subgraph(nodes, name, **subgraph_attrs) for node in graph_.nodes(): anode = pygraphviz.Node(agraph, node) # TODO: Generally fix node positions ptstr_ = anode.attr['pos'] if (ptstr_ is not None and len(ptstr_) > 0 and not ptstr_.endswith('!')): ptstr = ptstr_.strip('[]').strip(' ').strip('()') ptstr_list = [x.rstrip(',') for x in re.split(r'\s+', ptstr)] pt_list = list(map(float, ptstr_list)) pt_arr = np.array(pt_list) / inputscale new_ptstr_list = list(map(str, pt_arr)) new_ptstr_ = ','.join(new_ptstr_list) if anode.attr['pin'] is True: anode.attr['pin'] = 'true' if anode.attr['pin'] == 'true': new_ptstr = new_ptstr_ + '!' else: new_ptstr = new_ptstr_ anode.attr['pos'] = new_ptstr if graph_.graph.get('ignore_labels', False): for node in graph_.nodes(): anode = pygraphviz.Node(agraph, node) if 'label' in anode.attr: try: del anode.attr['label'] except KeyError: pass return agraph