Example #1
0
 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)
Example #2
0
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
Example #4
0
 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)
Example #5
0
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
Example #6
0
 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)
Example #7
0
 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)
Example #8
0
 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)
Example #9
0
 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
Example #10
0
    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
Example #11
0
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
Example #12
0
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
Example #13
0
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
Example #14
0
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
Example #15
0
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
Example #16
0
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
Example #17
0
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