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
Beispiel #2
0
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
Beispiel #3
0
    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()
Beispiel #4
0
    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()
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
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")
Beispiel #10
0
    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
Beispiel #11
0
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)
Beispiel #12
0
    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")
Beispiel #13
0
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')
Beispiel #14
0
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")
Beispiel #15
0
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()
Beispiel #17
0
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
Beispiel #18
0
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
Beispiel #19
0
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
Beispiel #20
0
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()
Beispiel #22
0
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
Beispiel #23
0
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
Beispiel #25
0
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
Beispiel #26
0
    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")
Beispiel #27
0
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