6

I need your help to write a script in Python that will take dynamically changed data, the source of data is not matter here, and display graph on the screen.

I know how to use matplotlib, but the problem with matplotlib, that I can display graph only once, at the end of the script. I need to be able not only to display graph one time, but also update it on the fly, each time when data changes.

I found that it is possible to use wxPython with matplotlib to do this, but it is little bit complicate to do this for me, because i am not familiar with wxPython at all.

So I will be very happy if someone will show me simple example how to use wxPython with matplotlib to show and update simple graph. Or, if it is some other way to do this, it will be good to me too.

PS:
Ok, since no one answered and looked at matplotlib help noticed by @janislaw and wrote some code. This is some dummy example:


import time
import matplotlib.pyplot as plt


def data_gen():
    a=data_gen.a
    if a>10:
        data_gen.a=1
    data_gen.a=data_gen.a+1
    return range (a,a+10)

def run(*args):
    background = fig.canvas.copy_from_bbox(ax.bbox)

    while 1:
        time.sleep(0.1)
        # restore the clean slate background
        fig.canvas.restore_region(background)
        # update the data
        ydata = data_gen()
        xdata=range(len(ydata))

        line.set_data(xdata, ydata)

        # just draw the animated artist
        ax.draw_artist(line)
        # just redraw the axes rectangle
        fig.canvas.blit(ax.bbox)

data_gen.a=1
fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot([], [], animated=True)
ax.set_ylim(0, 20)
ax.set_xlim(0, 10)
ax.grid()

manager = plt.get_current_fig_manager()
manager.window.after(100, run)

plt.show()

This implementation have problems, like script stops if you trying to move the window. But basically it can be used.

Brian Tompsett - 汤莱恩
  • 5,438
  • 68
  • 55
  • 126
Alex
  • 1,874
  • 5
  • 23
  • 27
  • I was just trying to do this today and gave up on matplotlib. I just settled on sending all the data over a socket to a Processing script that does all the drawing, but that's probably not the answer you were hoping for. – Nathan Apr 11 '11 at 08:27
  • 4
    matplotlib is easily embeddable inside any GUI you like, and does not need to be static. There are examples in the [docs](http://matplotlib.sourceforge.net/examples/index.html) - see User interfaces section. There are also traits/traitsgui/chaco, maybe more suited to this kind of job, but require a paradigm shift [link](http://code.enthought.com/projects/traits_gui) – janislaw Apr 11 '11 at 10:39

5 Answers5

2

Here is a class I wrote that handles this issue. It takes a matplotlib figure that you pass to it and places it in a GUI window. Its in its own thread so that it stays responsive even when your program is busy.

import Tkinter
import threading
import matplotlib
import matplotlib.backends.backend_tkagg

class Plotter():
    def __init__(self,fig):
        self.root = Tkinter.Tk()
        self.root.state("zoomed")

        self.fig = fig
        t = threading.Thread(target=self.PlottingThread,args=(fig,))
        t.start()

    def PlottingThread(self,fig):     
        canvas = matplotlib.backends.backend_tkagg.FigureCanvasTkAgg(fig, master=self.root)
        canvas.show()
        canvas.get_tk_widget().pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

        toolbar = matplotlib.backends.backend_tkagg.NavigationToolbar2TkAgg(canvas, self.root)
        toolbar.update()
        canvas._tkcanvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

        self.root.mainloop()

In your code, you need to initialize the plotter like this:

import pylab
fig = matplotlib.pyplot.figure()
Plotter(fig)

Then you can plot to it like this:

fig.gca().clear()
fig.gca().plot([1,2,3],[4,5,6])
fig.canvas.draw()
Emma
  • 1,237
  • 1
  • 18
  • 22
  • I couldnt get your solution to work, since I am new to Tkinter I am not sure what is wrong, however what I have figured out so far is that the mainloop cannot be in a thread. – Jehandad Jan 20 '18 at 18:54
2

As an alternative to matplotlib, the Chaco library provides nice graphing capabilities and is in some ways better-suited for live plotting.

See some screenshots here, and in particular, see these examples:

Chaco has backends for qt and wx, so it handles the underlying details for you rather nicely most of the time.

Isaiah Norton
  • 4,006
  • 1
  • 22
  • 37
  • Updated. That said, there are *many* new libraries in the Python ecosystem since this answer: [Bokeh](https://bokeh.org/), [Altair](https://altair-viz.github.io/), [Holoviews](http://holoviews.org/), and others. – Isaiah Norton Nov 13 '19 at 00:12
0

Instead of matplotlib.pyplot.show() you can just use matplotlib.pyplot.show(block=False). This call will not block the program to execute further.

Ankur
  • 5,048
  • 19
  • 36
  • 62
Apogentus
  • 6,011
  • 4
  • 31
  • 32
0

example of dynamic plot , the secret is to do a pause while plotting , here i use networkx:

    G.add_node(i,)
    G.add_edge(vertic[0],vertic[1],weight=0.2)
    print "ok"
    #pos=nx.random_layout(G)
    #pos = nx.spring_layout(G)
    #pos = nx.circular_layout(G)
    pos = nx.fruchterman_reingold_layout(G)

    nx.draw_networkx_nodes(G,pos,node_size=40)
    nx.draw_networkx_edges(G,pos,width=1.0)
    plt.axis('off') # supprimer les axes

    plt.pause(0.0001)
    plt.show()  # display
miken32
  • 39,644
  • 15
  • 91
  • 133
Saydo
  • 1
0

I had the need to create a graph that updates with time. The most convenient solution I came up was to create a new graph each time. The issue was that the script won't be executed after the first graph is created, unless the window is closed manually. That issue was avoided by turning the interactive mode on as shown below

    for i in range(0,100): 
      fig1 = plt.figure(num=1,clear=True) # a figure is created with the id of 1
      createFigure(fig=fig1,id=1) # calls a function built by me which would insert data such that figure is 3d scatterplot
      plt.ion() # this turns the interactive mode on
      plt.show() # create the graph
      plt.pause(2) # pause the script for 2 seconds , the number of seconds here determine the time after that graph refreshes

There are two important points to note here

  1. id of the figure - if the id of the figure is changed a new graph will be created every time, but if it is same it relevant graph would be updated.
  2. pause function - this stops the code from executing for the specified time period. If this is not applied graph will refresh almost immediately
dinith jayabodhi
  • 381
  • 1
  • 6
  • 16