Exemplo n.º 1
0
    def graph(data):
        dot = Graph(comment='Kanjis', strict=True)
        dot.engine = 'neato'
        dot.format = 'svg'
        dot.attr(rankdir='TB', overlap="false")
        dot.attr('node', fontsize='30')

        similaredges = defaultdict(set)
        for kanji in data.kanjis:
            #try:
            k = kanji  #.decode('utf-8')
            label = ("<b>" + kanji + "</b>\n " + data.descriptions[kanji]
                     )  #.decode('utf-8')

            shape = "circle"
            fcolor = "0 0 " + str(1 - (0.2 + 0.8 * data.ease[kanji]))
            color = fcolor
            if (kanji in Similarity.dangerzones):
                shape = "doublecircle"
                color = "red"

            node = dot.node(data.descriptions[kanji],
                            label=kanji,
                            shape=shape,
                            color=color,
                            fontcolor=fcolor,
                            fillcolor=data.colors[kanji],
                            style='filled')

            #        constraint='true'
            #        color = "black"
            #        for similar in data.similars[kanji]:
            #            color = "black"
            #            if (similar in dangerzones or kanji in dangerzones):
            #                color = "red"
            #            if not similaredges[kanji] or not similar in similaredges[kanji]:
            #                if random.random() < 0.2 and color != "red": # Random dropoff
            #                    color= "lightgrey"
            #                    constraint='false'
            #                dot.edge(data.descriptions[kanji], data.descriptions[similar], color=color, constraint=constraint)#.decode('utf-8')
            #            similaredges[kanji].add(similar)
            #            similaredges[similar].add(kanji)

            for similar in data.similars[kanji]:
                color = "black"
                style = "invis"
                if (similar in Similarity.dangerzones
                        or kanji in Similarity.dangerzones):
                    color = "red"
                    style = ""
                if not similaredges[kanji] or not similar in similaredges[
                        kanji]:
                    dot.edge(data.descriptions[kanji],
                             data.descriptions[similar],
                             color=color,
                             constraint="true",
                             style=style)  #.decode('utf-8')
                similaredges[kanji].add(similar)
                similaredges[similar].add(kanji)

            for similar in data.semilars[kanji]:
                color = "lightgrey"
                if (similar in Similarity.dangerzones
                        or kanji in Similarity.dangerzones):
                    color = "red"
                if not similaredges[kanji] or not similar in similaredges[
                        kanji]:
                    if random.random() >= 0.3:  # random dropoff
                        dot.edge(data.descriptions[kanji],
                                 data.descriptions[similar],
                                 color=color,
                                 constraint="false")  #.decode('utf-8')
                similaredges[kanji].add(similar)
                similaredges[similar].add(kanji)

        #except Exception:
        #    print("encoding fial")

        return dot
Exemplo n.º 2
0
    def general_graph(self,
                      timeline: Iterable[Optional[List[int]]],
                      edges: Iterable[Iterable[int]],
                      extra_nodes: Iterable[int] = tuple(),
                      view: bool = False,
                      fontsize: int = 20,
                      fontcolor: str = 'black',
                      penwidth: float = 2.2,
                      first_color: str = 'yellow',
                      first_style: str = 'filled',
                      second_color: str = 'green',
                      second_style: str = 'dotted,filled',
                      third_color: str = 'red',
                      graph_name: str = 'graph',
                      file_basename: str = 'graph',
                      do_sort_nodes: bool = True,
                      do_adj_nodes: bool = True,
                      var_name: str = '') -> None:
        """
        Creates one graph emphasized for the given timeline.

        Parameters
        ----------
        edges : Iterable of: {int, int}
            All edges between nodes in the graph.
            Should NOT contain self-edges!
            BOTH edges (x, y) and (y, x) could be in the edgelist.

        extra_nodes : Iterable of int
            Nodes that are probably not in the edges, but should be rendered.

        TIMELINE : Iterable of: None | [int...]
            None if no variables get highlighted in this step.
            Else the 'timeline' provides the set of variables that are
            in the bag(s) under consideration. This function computes all other
            variables that are involved in this timestep using the 'edgelist'.

        colors : Iterable of color
            Colors to use for the graph parts.

        Returns
        -------
        None, but outputs the files with the graph for each timestep.

        """
        _filename = self.outfolder / file_basename
        LOGGER.info("Generating general-graph for '%s'", file_basename)
        vartag_n: str = var_name + '%d'
        # sfdp http://yifanhu.net/SOFTWARE/SFDP/index.html
        default_engine = 'sfdp'

        graph = Graph(graph_name,
                      strict=True,
                      engine=default_engine,
                      graph_attr={
                          'fontsize': str(fontsize),
                          'overlap': 'false',
                          'outputorder': 'edgesfirst',
                          'K': '2'
                      },
                      node_attr={
                          'fontcolor': str(fontcolor),
                          'penwidth': str(penwidth),
                          'style': 'filled',
                          'fillcolor': 'white'
                      })

        if do_sort_nodes:
            bodybaselen = len(graph.body)
            # 1: layout with circo
            graph.engine = 'circo'
            # 2: nodes in edges+extra_nodes make a circle
            nodes = sorted([
                vartag_n % n
                for n in set(itertools.chain(flatten(edges), extra_nodes))
            ],
                           key=lambda x: (len(x), x))
            for i, node in enumerate(nodes):
                graph.edge(str(nodes[i - 1]), str(node))
            # 3: reads in bytes!
            code_lines = graph.pipe('plain').splitlines()
            # 4: save the (sorted) positions
            assert code_lines[0].startswith(b'graph')
            node_positions = [
                line.split()[1:4] for line in code_lines[1:]
                if line.startswith(b'node')
            ]
            # 5: cut layout
            graph.body = graph.body[:bodybaselen]
            for line in node_positions:
                graph.node(line[0].decode(),
                           pos='%f,%f!' % (float(line[1]), float(line[2])))
            # 6: Engine uses previous positions
            graph.engine = 'neato'

        for (src, tar) in edges:
            graph.edge(vartag_n % src, vartag_n % tar)
        for nodeid in extra_nodes:
            graph.node(vartag_n % nodeid)

        bodybaselen = len(graph.body)

        for i, variables in enumerate(timeline, start=1):  # all timesteps
            # reset highlighting
            graph.body = graph.body[:bodybaselen]

            if variables is None:
                graph.render(view=view,
                             format='svg',
                             filename=str(_filename) + str(i))
                continue

            for var in variables:
                graph.node(vartag_n % var,
                           fillcolor=first_color,
                           style=first_style)

            # highlight edges between variables
            for (s, t) in edges:
                if s in variables and t in variables:
                    graph.edge(vartag_n % s,
                               vartag_n % t,
                               color=third_color,
                               penwidth=str(penwidth))

            if do_adj_nodes:
                # set.difference accepts list as argument, "-" does not.
                edges = [set(edge) for edge in edges]
                adjacent = {
                    edge.difference(variables).pop()
                    for edge in edges if len(edge.difference(variables)) == 1
                }

                for var in adjacent:
                    graph.node(vartag_n % var,
                               color=second_color,
                               style=second_style)

            graph.render(view=view,
                         format='svg',
                         filename=str(_filename) + str(i))