matplotlib with wxPython GUIs
August 1st, 2008 at 9:24 amAs I wrote in the last post, I found matplotlib to be a very nice library for plotting. So, considering that I really plan to use it for my Python programs at work, I’ve spent a little time to write some proof-of-concept code (I do this often when learning a new library. Nothing serves as a better reference than your own code).
The first demo I wrote displays a bar plot, allowing the user to change the data shown on it in real-time, as well as using the matplotlib navigation toolbar and saving the plot to a file. Additionally, it allows some basic interaction with the plot (clicking on a bar brings up a message box) and playing with the plot’s properties like the grid and the width of the bars.
You can download this demo from here.
The second demo is rather more sophisticated. It explores the dynamic abilities of matplotlib, which allows smooth and flicker-less animation. This demo features a “live” graph that runs continuously (unless the user asks it to pause). The user can explore the graph by selecting limits for the X and Y axes, and select whether he wants to see the grid and the X axis labels.
It can be downloaded from here.
Related posts:

August 1st, 2008 at 10:54
Awesome, thanks.
August 6th, 2008 at 00:46
Fantastic. I’ve been using matplotlib for a while, and have done a bit of wxPython, but have never put the two together. This should get me started. Many thanks.
August 12th, 2008 at 17:35
Live graph one failed with :
RuntimeError: xdata and ydata must be the same length
August 12th, 2008 at 20:38
Chris,
Are you sure you didn’t change anything and / or have the up-to-date version of matplotlib ?
The only two places in the code that populate the plot with data are:
1. In the end of init_plot()
self.plot_data = self.axes.plot( self.data, linewidth=1, color=(1, 1, 0), )[0]This only fills in the y axis, x will be automatically done by axes.plot
2. In the end of draw_plot()
self.plot_data.set_xdata(np.arange(len(self.data))) self.plot_data.set_ydata(np.array(self.data))These two obviously create arrays of the same length.
August 13th, 2008 at 01:25
Sorry - was using latest marked stable on Gentoo 0.91.2 - update to matplotlib-0.98.1 fixed it.
Afaik the problem was between those two lines of draw_plot. Once you updated x - and before you updated y - the two didn’t match. Obviously now matplotlib handle it safely.
Thanks
September 10th, 2008 at 14:54
Eli, looks great! I was just Googling around for wxPython & matplotlib coming across these examples; great starting points.
One thing: when trying on my Mac, the second example didn’t fully work: the radio buttons weren’t available, and I saw only one run of the live data. Could that be because of the wxPython version that ships with OS X 10.5? It’s 2.8.4.0, matplotlib is 0.98.0. Or is it just intrinsic to the OS X GUI?
September 10th, 2008 at 17:40
Evert,
Your version of wxPython does look a bit old…
Though I don’t know much about OS X
September 10th, 2008 at 22:08
Tried with a up-to-date version (2.8.8.1) of wxPython; no luck.
So I guess it’s more intrinsic to OS X/Aqua or so.
If I ever find out, I might come back here to let you know; but that could be a few months (no hurry getting this right, as I don’t need it yet. I’m just playing around right now).
September 15th, 2008 at 18:42
Eli, for your (and possibly other people’s) records: I now know what caused this.
wxStaticBox/Sizer needs to be created before any of the controls inside it are created, otherwise it’ll draw on top of those of controls, and while you may be able to see them, you cannot “reach” (click) them. MS Windows (XP) is apparently a bit more forgiving there, so it worked for you (or it’s actually broken there, as I don’t know what’s the correct way to do this); apparently, with GTK it can even crash.
So, the solution is to take the following two lines in the BoundControlBox’s __init__() method (wx_mpl_dynamic_graph.py), and move them up, just before the self.radio_auto is created:
self.value = initval box = wx.StaticBox(self, -1, label) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.radio_auto = wx.RadioButton(self, -1, label="Auto", style=wx.RB_GROUP)Then it works splendidly for me, and probably also on other platforms/window environments.
More details at the wxwidgets.org wiki or eg this post in a mailinglist.
September 19th, 2008 at 09:18
Evert,
Thanks. I’ve updated the file to reflect this fix.
September 30th, 2008 at 16:34
Exactly what I was looking for. I have graphs in my application, but not on figurecanvas. I was just trying to get a barchart with wx and was headed down the wrong track. Snippits will save me some time. Thanks
January 8th, 2009 at 17:44
This is a fantastic starting place for embedding the power of MPL into WxPy applications. I cannot thank you enough for getting me started and hopefully you will not mind if I shoot you notes here and there every so often.
- Jeff
February 20th, 2009 at 20:59
thx a lot! i’m doing program to communicate with usb recorder (k8047d) and need to do real-time graph. your example is very useful.
February 20th, 2009 at 21:02
оказывается вы знаете русский (прочитал профиль). так что спасибо еще раз - на русском теперь)
February 20th, 2009 at 22:12
Не за что
March 6th, 2009 at 04:10
вот сел наконец разобраться с графиками, но что-то не получается организовать построение нескольких графиков на одном(
очень буду рад если сможешь помочь, т.к. я только начинаю изучать python и не всё понимаю, а туториал по matplotlib как-то сложен.
для простоты я выкинул всё ненужное из примера и оставил только сам график и кнопку пауза. вот что делал потом:
добавил class DataGen2(),
в GraphFrame() добавил self.datagen2=DataGen2(), self.data2 = [self.datagen2.next()],
в init_plot() по аналогии добавил self.plot_data2,
а вот дальше что делать с draw_plot() не знаю. пробовал добавить
self.plot_data2.set_xdata(np.arange(len(self.data2)))
self.plot_data2.set_ydata(np.array(self.data2))
но ничего дельного из этого не вышло((
если что вот полностью код - http://paste.org/5716
в общем если будет время глянь пожалуйста.
March 6th, 2009 at 07:03
@razr,
Answer: http://paste.org/5723
Сделай diff чтоб увидеть что я добавил
March 6th, 2009 at 15:24
спасибо. только я говорил немножко про другое - чтобы был один график и на нем строились две функции, а тут выходит два графика.
или это нельзя сделать?
March 7th, 2009 at 08:57
Then just change the creation of self.plot_data2 in init_plot, so that it’s created in self.axes and not self.axes2
If you don’t need two subplots, just remove axes2 altogether
March 7th, 2009 at 13:09
thx a lot)
April 27th, 2009 at 23:58
Your second example is almost exactly what I’ve been looking for; I had no idea matplotlib would actually perform that well being updated live in WX. Thank you so much for posting such a clear example!
May 5th, 2009 at 10:34
Nice lib…
Полезная библиотечка!
June 1st, 2009 at 14:37
hi. i want to show in x axe “1,2,3…” instead of “10,20,30…” in live plot program (for this timer it’s time in seconds). how can i do this?
June 2nd, 2009 at 17:45
@p4free,
I think that the axes object is trying to space out the grid automatically, depending on the range of your data in X. If you show less data at the same time, you’ll see the units less spaced out.
June 5th, 2009 at 04:07
Great examples (and thanks for putting them in the public domain for easy reuse). The scrolling plot didn’t initially work on my installation, but it was easily fixed by changing the lines
self.plot_data.set_xdata(np.arange(len(self.data)))
self.plot_data.set_ydata(np.array(self.data))
to the single line
self.plot_data.set_data(np.arange(len(self.data)), np.array(self.data))
From the comments, I see this modification is only needed in older versions of MPL. (Clearly, the older versions MPL is updating x and y one at a time and at the first update the lengths don’t match.)
June 26th, 2009 at 15:29
Please help
I’m trying to make dynamic graph of data comming from intrument connected via GPIB. When I run the script I get:
ValueError: need more than 0 values to unpack
#!/usr/bin/python
from pylab import *
from visa import *
keithley = instrument(”ASRL4::INSTR”)
print keithley
# adress instrumentu nastawiony na 16
keithley.write(”++addr 16\n\t”)
keithley.write(”*rst; status:preset; *cls”)
#keithley.write(”trigger:source bus”)
#keithley.write(”trigger:delay %f” % (500.0 / 1000.0))
#keithley.write(”initiate”)
#keithley.trigger()
#keithley.wait_for_srq()
ion()
hold(False)
n=1
while 1:
voltages=keithley.ask_for_values(”trace:data?”)
d=float(sum(voltages)/len(voltages))
plot(n,d,’bo’)
n=n+1
July 7th, 2009 at 15:27
Thank you! Very helpful!
July 9th, 2009 at 05:08
This is great. I used your code for my Arduino project, write-up here.
July 27th, 2009 at 23:33
This examples are the best on internet! Thanks! But, do you know an method to use less CPU? I need to plot some data from a serial sensor but matpotlib uses a lot o CPU. Thanks Again!
July 28th, 2009 at 14:49
matplotlib is quite CPU-hungry. For more performant code consider using PyQwt (search my blog for some relevant code).
July 29th, 2009 at 03:33
Very nice examples! Have you tried shrinking the window size though? For me the contents below the toolbar get merged with the canvas, not sure if it’s just my environment or not.
July 30th, 2009 at 00:20
This is useful stuff. Thanks for sharing!
November 12th, 2009 at 18:13
Dear Eliben,
I’m novice to matplotlib and python . I want to interface your program to my application which generates the ECG data in text format.I want do show it in dynamic/animated way as same u demonstrated in drawing a dynamic mpl (matplotlib) plot in a wxPython application.My query is if I have one text file conating all numerical data values known as ecg.txt conataining only one column.
How I can I put in following code snippet written by you
class DataGen(object):
“”" A silly class that generates pseudo-random data for
display in the plot.
“”"
def __init__(self, init=50):
self.data = self.init = init
def next(self):
self._recalc_data()
return self.data
def _recalc_data(self):
delta = random.uniform(-0.5, 0.5)
r = random.random()
if r > 0.9:
self.data += delta * 15
elif r > 0.8:
# attraction to the initial value
delta += (0.5 if self.init > self.data else -0.5)
self.data += delta
else:
self.data += delta
November 13th, 2009 at 07:34
@yogesh,
DataGenis a simple object on whichnextis continuously called to get a new data point. All you need to plug in another is to re implement it and provide thenextmethod. In you initialization read the input file and then just provide the next value from it on each call ofnext.December 1st, 2009 at 17:54
Eli,
Excellent code that will help me no-end in my application.
What is the easiest way to get this to get this to display an incoming data stream via an np array?
January 12th, 2010 at 15:16
Excellent code, save me a lot of time. Thank you