Search code examples
pythonmatplotlibtkinterbackground-colornetworkx

animated NetworkX Graph in TkCanvas: background color


For a demonstration of a Graph algorithm i need to draw a networkx graph to a Tkinter Canvas and be able to modify that graph (and the plot) at runtime.

I have pieced together the following code (I hope it is the minimal code leading to my problem, but I'm new to this so I'm not sure):

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import Tkinter as Tk
import networkx as nx
from tkMessageBox import showinfo

root = Tk.Tk()
root.wm_title("Animated Graph embedded in TK")
root.wm_protocol('WM_DELETE_WINDOW', root.quit())

f = plt.figure(figsize=(5,4))
a = f.add_subplot(111)
plt.axis('off')

# the networkx part
G=nx.complete_graph(5)
nx.draw_networkx(G,pos=nx.spring_layout(G),ax=a)

# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

def next_graph():
    if G.order():
        a.cla()
        G.remove_node(G.nodes()[-1])
        nx.draw(G, pos=nx.circular_layout(G), ax=a)
        canvas.draw()

b = Tk.Button(root, text="next",command=next_graph)
b.pack()  

Tk.mainloop()

My problem now is this: The first display of the graph is like I want it (backgroundcolor-wise), but after you first click 'Next' the backgroundcolor of the graph changes to white. I have tried changing the background color of the figure and the canvas. I don't even know what brings that change about, I think it is simply drawing to the same canvas twice.

How can I modify the code to have the graph always have the same background color?

On an unrelated note: the root.quit() I added does not help in ending the application properly. This might be stupid on my side, but what did go wrong here?


Solution

  • I think you are very close. If you use nx.draw_networkx() in your event loop then it works (turn off the axis there too).

    Here is your example with those modifications and also with a single layout computed at the beginning that is reused in the loop:

    import matplotlib
    matplotlib.use('TkAgg')
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    import matplotlib.pyplot as plt
    import Tkinter as Tk
    import networkx as nx
    from tkMessageBox import showinfo
    
    root = Tk.Tk()
    root.wm_title("Animated Graph embedded in TK")
    # Quit when the window is done
    root.wm_protocol('WM_DELETE_WINDOW', root.quit)
    
    f = plt.figure(figsize=(5,4))
    a = f.add_subplot(111)
    plt.axis('off')
    
    # the networkx part
    G=nx.complete_graph(5)
    pos=nx.circular_layout(G)
    nx.draw_networkx(G,pos=pos,ax=a)
    xlim=a.get_xlim()
    ylim=a.get_ylim()
    
    
    
    # a tk.DrawingArea
    canvas = FigureCanvasTkAgg(f, master=root)
    canvas.show()
    canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
    
    def next_graph():
        if G.order():
            a.cla()
            G.remove_node(G.nodes()[-1])
            nx.draw_networkx(G, pos, ax=a)
            a.set_xlim(xlim)
            a.set_ylim(ylim)
            plt.axis('off')
            canvas.draw()
    
    b = Tk.Button(root, text="next",command=next_graph)
    b.pack()
    
    Tk.mainloop()