在Tkinter窗口中显示networkx图

时间:2019-04-06 22:00:28

标签: python tkinter networkx

我正在尝试制作一个使用Ford-Fulkerson方法查找图内最大流量的应用程序。我面临的问题是,单击窗口右侧的MaxFlow按钮后,我无法显示图形。

我已经设置好图形,最大流量算法有效。

from tkinter import *
import networkx as nx
from pandas import DataFrame
from digraph import ford_fulkerson
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
window = Tk()
window.title("Graphs")

graph = nx.DiGraph()
graph.add_nodes_from('ABCDEFGH')
graph.add_edges_from([
    ('A', 'B', {'capacity': 4, 'flow': 0}),
    ('A', 'C', {'capacity': 5, 'flow': 0}),
    ('A', 'D', {'capacity': 7, 'flow': 0}),
    ('B', 'E', {'capacity': 7, 'flow': 0}),
    ('C', 'E', {'capacity': 6, 'flow': 0}),
    ('C', 'F', {'capacity': 4, 'flow': 0}),
    ('C', 'G', {'capacity': 1, 'flow': 0}),
    ('D', 'F', {'capacity': 8, 'flow': 0}),
    ('D', 'G', {'capacity': 1, 'flow': 0}),
    ('E', 'H', {'capacity': 7, 'flow': 0}),
    ('F', 'H', {'capacity': 6, 'flow': 0}),
    ('G', 'H', {'capacity': 4, 'flow': 0}),

])

layout = {
    'A': [0, 1], 'B': [1, 2], 'C': [1, 1], 'D': [1, 0],
    'E': [2, 2], 'F': [2, 1], 'G': [2, 0], 'H': [3, 1],
}

def draw_graph():
    f = plt.Figure(figsize=(5, 5), dpi=100)
    a = f.add_subplot(111)
    a.plot()
    a.draw_networkx_nodes(graph, layout, node_color='steelblue', node_size=600)
    a.draw_networkx_edges(graph, layout, edge_color='gray')
    a.draw_networkx_labels(graph, layout, font_color='white')

    for u, v, e in graph.edges(data=True):
        label = '{}/{}'.format(e['flow'], e['capacity'])
        color = 'green' if e['flow'] < e['capacity'] else 'red'
        x = layout[u][0] * .6 + layout[v][0] * .4
        y = layout[u][1] * .6 + layout[v][1] * .4
        t = plt.text(x, y, label, size=16, color=color,
                     horizontalalignment='center', verticalalignment='center')

    plt.show()

def flow_debug(graph, path, reserve, flow):
    print('flow increased by', reserve,
          'at path', path,
          '; current flow', flow)
    draw_graph()

def plot_max_flow():
    ford_fulkerson(graph, 'A', 'H', flow_debug)


VertexData = Entry(window)
VertexData.grid(row = 0, column = 0)
Button(window, text = "Insert Vertex").grid(sticky = W, row = 0, column = 1, padx = 4)
Button(window, text = "Delete Vertex").grid(sticky = W, row = 0, column = 2, padx = 4)
Button(window, text = "MaxFlow").grid(sticky = W, row = 0, column = 3, padx = 4, command = ford_fulkerson(graph, 'A', 'H', flow_debug))
df3 = DataFrame()


window.mainloop()

DFS和Ford-Fulkerson算法,以防万一:

def ford_fulkerson(graph, source, sink, debug=None):
    flow, path = 0, True

    while path:
        # search for path with flow reserve
        path, reserve = depth_first_search(graph, source, sink)
        flow += reserve

        # increase flow along the path
        for v, u in zip(path, path[1:]):
            if graph.has_edge(v, u):
                graph[v][u]['flow'] += reserve
            else:
                graph[u][v]['flow'] -= reserve

        # show intermediate results
        if callable(debug):
            debug(graph, path, reserve, flow)


def depth_first_search(graph, source, sink):
    undirected = graph.to_undirected()
    explored = {source}
    stack = [(source, 0, dict(undirected[source]))]

    while stack:
        v, _, neighbours = stack[-1]
        if v == sink:
            break

        # search the next neighbour
        while neighbours:
            u, e = neighbours.popitem()
            if u not in explored:
                break
        else:
            stack.pop()
            continue

        # current flow and capacity
        in_direction = graph.has_edge(v, u)
        capacity = e['capacity']
        flow = e['flow']
        neighbours = dict(undirected[u])

        # increase or redirect flow at the edge
        if in_direction and flow < capacity:
            stack.append((u, capacity - flow, neighbours))
            explored.add(u)
        elif not in_direction and flow:
            stack.append((u, flow, neighbours))
            explored.add(u)

    # (source, sink) path and its flow reserve
    reserve = min((f for _, f, _ in stack[1:]), default=0)
    path = [v for v, _, _ in stack]

    return path, reserve

我希望绘制的图形将显示在窗口的右侧,但我不知道如何实现。

1 个答案:

答案 0 :(得分:0)

您有窗口

window = Tk()

和图中的networkx

f = plt.Figure(figsize=(5, 5), dpi=100)

所以你需要

# create matplotlib canvas using figure `f` and assign to widget `window`
canvas = FigureCanvasTkAgg(f, window)

# get canvas as tkinter's widget and `gird` in widget `window`
canvas.get_tk_widget().grid(row=..., column=...)

我无法测试它,但是我有一个自己的示例,put matplot figure in tkinter window