def generate_graph(verbose: bool, file: str):
    docker_client = docker.from_env()

    networks = get_networks(docker_client, verbose)
    containers, links = get_containers(docker_client, verbose)

    if file:
        base, ext = os.path.splitext(file)
        g = Graph(comment="Docker Network Graph",
                  engine="sfdp",
                  format=ext[1:],
                  graph_attr=dict(splines="true"))
    else:
        g = Graph(comment="Docker Network Graph",
                  engine="sfdp",
                  graph_attr=dict(splines="true"))

    for _, network in networks.items():
        draw_network(g, network)

    for container in containers:
        draw_container(g, container)

    for link in links:
        if link.network_name != "none":
            draw_link(g, networks, link)

    if file:
        g.render(base)
    else:
        print(g.source)
Esempio n. 2
0
def viz(config: Config, directed: bool, in_index_base: int, out_index_base: int):
    from graphviz import Digraph, Graph  # type: ignore

    firstline = input().split()
    G = None
    n, m = -1, -1
    if (len(firstline) == 1):
        # this is tree
        G = Graph()
        n = int(firstline[0])
        m = n - 1
    else:
        n, m = map(int, firstline)
        if directed:
            G = Digraph()
        else:
            G = Graph()

    for i in range(n):
        G.node(str(i))

    for i in range(m):
        u, v = map(int, input().split())
        if in_index_base == 1:
            u -= 1
            v -= 1
        G.edge(str(u), str(v), cost='1')

    output_filepath = os.path.expanduser('~/Dropbox/graph')
    G.render(output_filepath, view=True)
Esempio n. 3
0
    def __init__(self):
        self._graph = Graph('equation')
        self._subgraph_terms = Graph('terms')
        self._terms = {}

        self._graph.attr(rankdir='BT', ordering='out')  #, splines='false')
        self._subgraph_terms.attr(rank='same', rankdir='LR')
Esempio n. 4
0
def compartment_to_dot(compartment):
    g = Graph(name=compartment.id,cluster=True,subgraph=True)
    for subsystem in compartment.subsystems:
        gsub = subsystem_to_dot(subsystem)
        gsub.subgraph = True
        gsub.tag('::'+subsystem.id)
        g.add(gsub)
    for comp in compartment.compartments:
        gcomp = compartment_to_dot(comp)
        gcomp.subgraph = True
        gcomp.tag('::'+comp.id)
        g.add(gcomp)
    label = AttrStmt('graph',label=compartment.name,
                     fontsize=compartment.get_param('COMPARTMENT_FONTSIZE'))
    g.add(label)
    
    SHOW_EXCHANGES = compartment.get_param('SHOW_EXCHANGES')
    if SHOW_EXCHANGES and compartment.local_exchanges:
        gex = Graph(name=compartment.id+"::EX",cluster=True)
        gex.add(g)
        gex.add(AttrStmt('graph',style="dotted"))
        for ex in compartment.local_exchanges:
            gex.add(exchange_to_dot(ex)) 
        return gex
    else:
        return g
Esempio n. 5
0
def show(sql, filename):
    # 优化前的树
    g = Graph(filename, format='png', node_attr={'shape': 'plaintext'})
    etree = parsesql(sql)
    showtree(etree, g)
    g.render()
    img = Image.open(filename + '.gv.png')
    plt.figure('before optim')
    plt.imshow(img)
    plt.axis('off')

    # 优化后的树
    og = Graph(filename + 'optim',
               format='png',
               node_attr={'shape': 'plaintext'})
    # 两步优化
    relation2 = []
    otree = down_select(etree, '', relation2)
    otree = down_proj(otree, '', relation2, '')
    showtree(otree, og)
    og.render()
    img = Image.open(filename + 'optim' + '.gv.png')
    plt.figure('after optim')
    plt.imshow(img)
    plt.axis('off')
    plt.show()
Esempio n. 6
0
 def viz(self):
     """ Build a dotmap for graphviz 
         but also constructs the connected_stitch structures
     """
     flatmap = flatten(self.stitch_map())
     if self.pattern_type == 'round':
         dot = Graph(engine="twopi",
                     graph_attr={
                         'root': 'a1',
                         'overlap': 'false'
                     },
                     node_attr={
                         'shape': 'circle',
                         'margin': '0.00001 0.0001'
                     },
                     format="png",
                     name=self.name)
     else:
         dot = Graph(format="png", name=self.name)
     # first pass nodes
     for stitch in flatmap:
         dot.node("a" + str(stitch.id), str(stitch.stitch))
     # second pass edges
     for stitch in flatmap:
         if (stitch.prev):
             dot.edge("a" + str(stitch.id), "a" + str(stitch.prev.id))
         if (stitch.bottom):
             dot.edge("a" + str(stitch.id), "a" + str(stitch.bottom.id))
     dot.render(view=True)
Esempio n. 7
0
 def __init__(self, filename=None, name=None, start_graph=True):
     if name is None:
         self.graph = Graph(name=self.create_name())
     else:
         self.graph = Graph(name=name)
     if filename is None:
         self.filename = "grafy_startowe\\" + self.graph.name + ".dot"
     else:
         self.filename = filename
     self.create_nodes()
     self.create_edges()
     self.finish_creating(self.filename, start_graph)
Esempio n. 8
0
def init_graph():
    dot = Graph(comment='Topology')
    dot.node('A')
    dot.node('B')
    dot.node('C')
    dot.node('D')
    dot.node('E')
    dot.node('F')
    dot.node('G')
    dot.node('H')
    dot.node('I')

    dot.edge('A', 'B', label='2')
    dot.edge('A', 'D', label='5')
    dot.edge('B', 'C', label='7')
    dot.edge('B', 'E', label='1')
    dot.edge('C', 'F', label='9')
    dot.edge('D', 'E', label='3')
    dot.edge('D', 'G', label='3')
    dot.edge('E', 'H', label='30')
    dot.edge('E', 'F', label='2')
    dot.edge('H', 'G', label='5')
    dot.edge('H', 'I', label='8')
    dot.edge('F', 'I', label='6')

    dot.view()
Esempio n. 9
0
 def newBlock(self, value, dataObj=None):
     '''
     ### Function Description
     Create new block diagram. This is the main function to create a new block diagram object. 
     This module use Graph for visualiztion. There's no direction edge in this method.
     ### Parameters Description
      * value: 
       * type: str, int
       * description: text for block diagram. Identifier for user to name the node 
      * id:
       * type: int
       * description: serial number for each node
      * dataObj: 
       * type: object
       * description: store object item in node for advanced application 
     '''
     if self.rootNode == None:
         self.rootNode = Node(value, self.nodeIDCount, dataObj)
         self.nodeIDCount += 1
         self.rootNode.isRootNode = True
         self.currNodePtr = self.rootNode
         self.newNodePtr = self.rootNode
         self.add2NodeListPtr(self.rootNode)
         print('*Block Diagram is created. The root node ID is %d' %
               self.currNodePtr.id)
         self.graph = Graph(name='BlockDiagram',
                            filename='BlockDiagram.gv',
                            engine='dot')
         self.addGraphvizNode()
Esempio n. 10
0
def draw_pacs_tree_colored(log_file, out):
    log = pd.read_csv(log_file, header=None)
    log = np.array(log)
    n_cycles = log.shape[0]
    # G = Graph(format='pdf')
    G = Graph(format='svg')
    G.attr('node', shape='circle', style='filled')
    G.graph_attr.update(size="30")
    color_hex = value2hex(0)
    G.node('0-0', '0', fillcolor=color_hex)
    # G.node('0-0', '', fillcolor=color_hex, color='white', width='12')
    color_hex = value2hex(255 / n_cycles * 1)
    for i in range(len(log[0])):
        state = '1-' + str(i)
        G.node(state, str(state), fillcolor=color_hex)
        # G.node(state, '', fillcolor=color_hex, color='white', width='12')
        G.edge('0-0', state, color='black')
    for i in range(1, len(log) + 1):
        log_i = log[i - 1]
        color_hex = value2hex(255 / n_cycles * (i + 1))
        for j, l in enumerate(log_i):
            state = str(i + 1) + '-' + str(j)
            pstate = str(i) + '-' + str(int(l))
            G.node(state, str(state), fillcolor=color_hex)
            # G.node(state, '', fillcolor=color_hex, color='white', width='12')
            G.edge(pstate, state, color='black')
    G.render(out)
    make_colorbar(0, n_cycles * 5, out + '_colorbar')
Esempio n. 11
0
def gen_graph_from_nodes(nodes, type_fail=None):
    graph = Graph(format='png', strict=True)
    graph.node_attr['fontname'] = 'Courier New'
    graph.edge_attr['fontname'] = 'Courier New'
    for node in nodes:
        graph.node(
            _type_str(node.type),
            '{type: %s|ast_node: %s|parent\'s type: %s}' %
            (_type_str(node.type), node.ast_node.as_string().replace(
                '<', '\\<').replace('>', '\\>') if node.ast_node else 'None',
             _type_str(node.parent.type) if node.parent else 'NA'),
            shape='record',
            style='rounded')
        for neighb, ctx_node in node.adj_list:
            graph.edge(_type_str(node.type),
                       _type_str(neighb.type),
                       label=(f' {ctx_node.as_string()}' if ctx_node else ''))
    if type_fail:
        graph.node('tf',
                   '{TypeFail|src_node: %s}' %
                   (type_fail.src_node.as_string().replace('<', '\\<').replace(
                       '>', '\\>') if type_fail.src_node else 'None'),
                   shape='record')
        graph.edge('tf', _type_str(type_fail.tnode1.type), style='dashed')
        graph.edge('tf', _type_str(type_fail.tnode2.type), style='dashed')
    graph.view('tnode_graph')
Esempio n. 12
0
def _topology_graph():
    g = Graph(engine='dot',
              graph_attr={
                  'ratio': '0.41',
                  'pad': '0.7 ',
                  'newrank': 'false',
                  'splines': 'compound'
              })

    for isd in ISD.objects.iterator():
        g_isd = _make_isd_graph(isd)

        # hard-coding backbone ISDs to be at the top
        if isd.isd_id in [16, 26]:
            g_isd.attr(rank='source')

        # putting core ASes into a subgraph, laid out at the top
        with g_isd.subgraph() as s:
            s.attr(rank='min')
            for as_ in isd.ases.filter(owner=None, is_core=True):
                _add_as_node(s, as_)

        # putting non-core ASes into a subgraph, without rank
        with g_isd.subgraph() as s:
            s.attr(rank='none')
            for as_ in isd.ases.filter(owner=None, is_core=False):
                _add_as_node(s, as_)

        g.subgraph(g_isd)

    for link in Link.objects.filter(interfaceA__AS__owner=None,
                                    interfaceB__AS__owner=None):
        _add_link(g, link)

    return g
Esempio n. 13
0
def gen_img(graph: Graph,
            node_num,
            rm_ratio: float = 0.2,
            root_folder='train',
            source_folder='',
            source_file='train.txt'):
    """
    在graph上,以rm_ratio的概率随机删除一些链路,然后用随机选取的一对节点作为源宿点,判断其是否联通。并将生成的图像放到root_folder目录中,
    对应的文件名称和标签放到source_folder目录下的train.txt文件中。
    """
    # 生成原始数据
    rds = rand_edges(graph, rm_ratio)
    graph.remove_edges_from(rds)
    src, dst = gen_src_dst(0, node_num)
    label = get_label(src, dst, graph)
    # 构造graphviz对象
    name = str(time.time())
    g = Graph(format='jpeg', engine='neato')
    g.attr('node', shape='circle')
    g.attr('edge')
    for node in graph.nodes():
        g.node(name=str(node))
    g.node(name=str(src), shape='triangle')
    g.node(name=str(dst), shape='triangle')
    for edge in graph.edges():
        g.edge(str(edge[0]), str(edge[1]))
    for edge in rds:
        g.edge(str(edge[0]), str(edge[1]), color='white')
    g.render(filename=name, directory=root_folder, view=False, cleanup=True)
    # 存储到文件中去
    file = open(os.path.join(source_folder, source_file), 'a')
    file.write(name + '.jpeg ' + str(label) + '\n')
    file.flush()
    file.close()
Esempio n. 14
0
def main():
    SIZE = 20
    PLOIDY = 2
    MUTATIONS = 2

    indices = range(SIZE)
    # Build fake data
    seqA = list("0" * SIZE)
    allseqs = [seqA[:] for x in range(PLOIDY)]  # Hexaploid
    for s in allseqs:
        for i in [choice(indices) for x in range(MUTATIONS)]:
            s[i] = "1"

    allseqs = [make_sequence(s, name=name) for (s, name) in \
                zip(allseqs, [str(x) for x in range(PLOIDY)])]

    # Build graph structure
    G = Graph("Assembly graph", filename="graph")
    G.attr(rankdir="LR", fontname="Arial", splines="true")
    G.attr(ranksep=".2", nodesep="0.02")
    G.attr('node', shape='point')
    G.attr('edge', dir='none', penwidth='4')

    colorset = get_map('Set2', 'qualitative', 8).mpl_colors
    colorset = [to_hex(x) for x in colorset]
    colors = sample(colorset, PLOIDY)
    for s, color in zip(allseqs, colors):
        sequence_to_graph(G, s, color=color)
    zip_sequences(G, allseqs)

    # Output graph
    G.view()
Esempio n. 15
0
def display_nodes(nodes):
    graph = Graph()
    for node in nodes:
        graph.node(node.identifier, node.name)
        for child in node.children:
            graph.edge(node.identifier, child.identifier)
    return graph
Esempio n. 16
0
def main():

    p = argparse.ArgumentParser(
        description='This script is for generate graph figure')
    p.add_argument('-g', '--graph', type=str,
                   help='path to graph csv file', required=True)

    p.add_argument('-o', '--out', type=str,
                   help='output_file', required=True)

    option_args = p.parse_known_args()[0]
    path = option_args.graph
    out_file = option_args.out

    if not os.path.exists(path):
        print("File not found")
        sys.exit(1)

    adj_matrix = read_graph(path)
    g = Graph(format='png')

    for i in range(len(adj_matrix)):
        for j in range(i + 1, len(adj_matrix)):
            g.edge(str(i), str(j), label=str(adj_matrix[i][j]))

    g.render(out_file)
Esempio n. 17
0
def build_graph():
    g = Graph(format='png')
    node_id = 0

    def build_edge_with_id(context, char, node):
        nonlocal node_id
        for key, child in node._children.items():
            label = key
            number = str(ord(key) + 1)
            if key == '\0':
                label = 'null'
            if child._value is None:
                g.node(context + number,
                       label=label,
                       style='filled',
                       fillcolor='white',
                       fontcolor='black')
            else:
                g.node(context + number,
                       label=label,
                       style='filled',
                       fillcolor='blue',
                       fontcolor='black')
            g.edge(context, context + number, color='black')

    return g, build_edge_with_id
Esempio n. 18
0
def render_dungeon(dungeon: Dungeon, session_id: str, rogue_position: int):
    filename = f'./dungeons/d-{session_id}.gv'
    g = Graph('Dungeon_graph', filename=filename, format='png', engine='fdp')

    for room in dungeon.rooms:
        contains_key = any(key.room_id == room.id for key in dungeon.keys)

        shape = 'circle'
        if rogue_position == room.id:
            shape = 'triangle'
        elif contains_key:
            shape = 'doublecircle'
        elif room.id == dungeon.finish_room_id:
            shape = 'star'

        g.attr('node', color=str(room.color), shape=shape)
        g.node(str(room.id))

    for door in dungeon.doors:
        if door.is_closed:
            style = 'dashed'
        else:
            style = 'solid'
        g.attr('edge', color=str(door.color), style=style)
        g.edge(str(door.first_room_id), str(door.second_room_id))

    g.render()

    return f'{filename}.png'
Esempio n. 19
0
def plot(overlapping_policies):
    g = Graph("G", filename="Overlapping_policies", engine="sfdp")
    for key in overlapping_policies.keys():
        for value in overlapping_policies[key]:
            g.edge(key, value)
            overlapping_policies[value].remove(key)
    g.view()
    def get_topologie_data(self):
        node_data = {}
        for node in self.nodes:
            node_data[str(node.id)] = {
                "neighbors": node.neighbors
            }

        from graphviz import Graph
        graph = Graph("PLC-Topologie", filename="topologie.gv")
        # graph.edge(str(Node.id), str(alt_id))
        tmp = []
        del_list = []
        for node in self.nodes:
            for neighbor in node.neighbors:
                if str(node.id) == neighbor:
                    del_list.append(node.id)
                elif str(node.id) + ":" + str(neighbor) not in tmp and str(neighbor) + ":" + str(node.id) not in tmp:
                    tmp.append(str(node.id) + ":" + str(neighbor))
                    graph.edge(str(node.id), str(neighbor))

        for node in self.nodes:
            if node.id in del_list:
                del node.neighbors[str(node.id)]
        graph.view()

        return node_data
Esempio n. 21
0
def BFSGetDist(self,v0=0): #搜索无权图其他点到 v0 的最短路径
Q = Queue()
v = v0
path = [[v] for i in range(self.vexnum)]
self.visited[v] = True
Q.enqueue(v)
while not Q.empty():
v = Q.dequeue()
for w in self.arc[v]:
if self.visited[w] == False:
self.visited[w] = True
path[w] = path[v] + [w]
Q.enqueue(w)
for v in range(self.vexnum):
if v != v0:
print(len(path[v]) - 1,end=' ')
print("->".join(str(i) for i in path[v]))
vg = Graph('图及其应用')
with open('case1.txt') as case:
n = int(case.readline()) #n 表示图中的顶点数
for i in range(n):
vg.node(name=str(i),color='red')
vexs = [str(i) for i in range(n)]
matrix = [[0] * n for i in range(n)]
edges = case.readlines()
arcnum = len(edges)
for edge in edges:
v1,v2 = map(int, edge.split())
matrix[v1][v2] = 1
matrix[v2][v1] = 1 #无向图
vg.edge(str(v1),str(v2),color='blue') g = MGraph(vexs,matrix,arcnum)
alg = ALGraph(vexs,matrix,arcnum)
g.findArticul()
alg.BFSGetDist(0)
vg.view()
Esempio n. 22
0
def draw_graph(graph, edges):
    g = Graph()
    for node in graph.get_nodes():
        g.node(node)
    for edge in edges:
        g.edge(edge[0], edge[1], minlen='2')
    g.view("./grafiPDF/grafo")
Esempio n. 23
0
    def update_root(self, position, board, is_my_move):
        '''
        Update the root as the selected child node
        '''
        del self.g
        self.g = Graph(format='png',
                       graph_attr={'fixed_size': 'false'},
                       node_attr={'fontsize': '13'})

        if self.root.child[position] is None or self.root.child[
                position].is_my_move != is_my_move:
            self.root = self.build_node(board)
        else:
            self.root = self.root.child[position]
            del self.root.parent
            self.root.parent = None
            # change name in graph
            self.root.node = self.root.node.split("label=" + str(self.root.position))[0] + "label=" + str('root') + \
                             self.root.node.split("label=" + str(self.root.position))[1]
            self.root.edge = None
            for c in self.root.child:
                if c is not None:
                    c.node = c.node.split("label=\"\"")[0] + "label=" + str(
                        c.position) + c.node.split("label=\"\"")[1]
        self.recycle_tree(self.root)
Esempio n. 24
0
 def color(self):
     # Dict to save color
     color = defaultdict(list)
     
     for node in self.graph:
         if (len(color) == 0):
             color[0].append(node)
             continue
         else:
             for i in range(len(color)):
                 temp = 0
                 for colored_node in color[i]:
                     if (node in self.graph[colored_node]):
                         temp = 1
                         break
                 if (temp == 1):
                     continue
                 else:
                     color[i].append(node)
                     break
             if (node not in color[i]):
                 color[len(color)].append(node)    
     # Out put file
     output_file = Graph('Coloring graph', filename='Greedy Coloring Graph.gv',strict="True")
     output_file.attr( shape="circle", size='1')
     list_color=["red","blue", "yellow","green","gray","snow","DarkOrange1","MediumPurple1","khaki4","orchid", "cyan2", "blue violet", "GreenYellow", 
     "HotPink", "LightGoldenrod4","DarkSeaGreen", "sienna","brown"]
     for i in range (len(color)):
         for node in color[i]:
             output_file.node(str(node),fillcolor=list_color[i],style="filled")
             for opp_node in self.graph[node]:
                 output_file.edge(str(node),str(opp_node))
     output_file.view()  
Esempio n. 25
0
def visual_decoding(sent, saveto='tmp'):
    """
    Visualize multiple translation from machine translation.

    Example:
    >>> sentence = ['I have a apple',
                    'I have a dream',
                    'H have an egg']
    >>> visual_decoding(sent=sentence, saveto='demo')

    Args:
        sent: a list of str
            Multiple translations.

        saveto: str
            Graph will be saved as 'saveto.png'.

    Returns:
        None

    """
    graph = Graph(format='png',
                  node_attr={'shape': 'box'},
                  graph_attr={'splines': 'polyline'},
                  edge_attr={'dir': 'forward'})

    graph.body.extend(['rankdir=LR'])

    for i, s in enumerate(sent):
        graph = _plot_sent(graph, s, flag=str(i))

    graph.render(filename=saveto, view=True)
    def navigate(self, node: Node):
        chds = node.childrens
        for n in chds:
            self.graph.edge(str(node.ev_id), str(n.ev_id), None, dir='forward')
            if n.validity == Validity.INVALID:
                self.graph.node(str(n.ev_id),
                                self.name_for_node(n),
                                fillcolor=self.INVALID_COLOR,
                                style='filled')
            elif n.validity == Validity.VALID:
                self.graph.node(str(n.ev_id),
                                self.name_for_node(n),
                                fillcolor=self.VALID_COLOR,
                                style='filled')
            elif n.validity == Validity.UNKNOWN:
                self.graph.node(str(n.ev_id), self.name_for_node(n))
            elif n.validity is Validity.NOT_IN_PROV:
                self.graph.node(str(n.ev_id),
                                self.name_for_node(n),
                                fillcolor=self.PROV_PRUNED_NODE_COLOR,
                                style='filled')

        if len(chds) > 0:
            g = Graph()
            for c in chds:
                g.node(str(c.ev_id))
            g.graph_attr['rank'] = 'same'
            self.graph.subgraph(g)

        for n in chds:
            self.navigate(n)
Esempio n. 27
0
def draw_pats_tree_colored(pkl, out, col_style='contact', **kwarg):
    with open(pkl, 'rb') as f:
        var_list = pickle.load(f)
        rootnode = var_list[0]
    if col_style == 'order':
        num_state = dfs(rootnode)
        print('num_state  ' + str(num_state))
        values = np.arange(num_state)
    elif col_style == 'rmsd':
        values = None
    elif col_style == 'contact':
        native = kwarg['native']
        traj = kwarg['traj']
        values = frac_native_contacts(native, traj)
    elif col_style == 'f1':
        native = kwarg['native']
        traj = kwarg['traj']
        values = calc_f1(native, traj)
    else:
        print('Error!: you can not use such color style ' + col_style)
        exit(1)
    if values is not None:
        make_colorbar(min(values), max(values), out + '_colorbar')
    else:
        make_colorbar(0, rootnode.childNodes[0].rmsd, out + '_colorbar')
    # G = Graph(format='pdf')
    G = Graph(format='svg')
    G.attr("node", shape="circle", style="filled")
    G.graph_attr.update(size="30")
    make_graph(G, rootnode, values)
    G.render(out)
Esempio n. 28
0
def display(ref, filename='temp'):
    """Render a tree to SVG format.

    *Warning:* Made for use within IPython/Jupyter only.

    Args:
        ref (Tree).
        filename (str): Temporary filename to store SVG output.

    Returns:
        SVG: IPython SVG wrapper object for tree.

    """

    # Ensure all modules are available
    try:
        from graphviz import Graph
        from IPython.display import SVG
    except:
        raise Exception("Missing module: graphviz and/or IPython.")
    # Traverse tree and generate temporary Graph object
    output_format = 'svg'
    graph = Graph(filename, format=output_format)
    q = Queue()
    q.enqueue(ref)
    while not q.isempty():
        ref = q.dequeue()
        graph.node(str(id(ref)), label=str(ref.key))
        for child in ref.children:
            graph.edge(str(id(ref)), str(id(child)))
            q.enqueue(child)
    # Render to temporary file and SVG object
    graph.render(filename=filename, cleanup=True)
    return SVG(filename + '.' + output_format)
Esempio n. 29
0
 def concrete_bipartite_as_graph(self, subjects, patterns) -> Graph:  # pragma: no cover
     """Returns a :class:`graphviz.Graph` representation of this bipartite graph."""
     if Graph is None:
         raise ImportError('The graphviz package is required to draw the graph.')
     bipartite = self._build_bipartite(subjects, patterns)
     graph = Graph()
     nodes_left = {}  # type: Dict[TLeft, str]
     nodes_right = {}  # type: Dict[TRight, str]
     node_id = 0
     for (left, right), value in bipartite._edges.items():
         if left not in nodes_left:
             subject_id, i = left
             name = 'node{:d}'.format(node_id)
             nodes_left[left] = name
             label = '{}, {}'.format(i, self.subjects_by_id[subject_id])
             graph.node(name, label=label)
             node_id += 1
         if right not in nodes_right:
             pattern, i = right
             name = 'node{:d}'.format(node_id)
             nodes_right[right] = name
             label = '{}, {}'.format(i, self.automaton.patterns[pattern][0])
             graph.node(name, label=label)
             node_id += 1
         edge_label = value is not True and str(value) or ''
         graph.edge(nodes_left[left], nodes_right[right], edge_label)
     return graph
    def draw(self, filename='test.gv'):
        """
        Отрисовывает граф используя библиотеку Graphviz. Больше примеров:
        https://graphviz.readthedocs.io/en/stable/examples.html
        """
        g = Graph('G', filename=filename, engine='sfdp')

        for v, attr in enumerate(self.attributes):
            if 'color' in '':
                g.attr('node', style='filled', fillcolor=attr['color'])
                if attr['color'] == 'black':
                    g.attr('node', fontcolor='white')
            else:
                g.attr('node', style='', color='', fontcolor='', fillcolor='')

            if 'name' in '':
                g.node(str(v), label='{} ({})'.format(attr['name'], v))
            else:
                g.node(str(v))

        for i in range(self.number_of_vertices()):
            for j in self.adj[i]:
                if i < j:
                    g.edge(str(i), str(j))

        g.view()