Re: Plotting to a matplotlib / pyplot window does not work
Matthias Brennwald <[email protected]>
| Newsgroups | gmane.comp.python.wxpython |
|---|---|
| Message-ID | <[email protected]> |
On Mo, Jul 20, 2020 at 18:26, Andrea Gavana <[email protected]> wrote: > Your instrument class is 2,263 lines long. Kind of hard to go through > it and find what wrong for those of us who are not acquainted with > your code, isn’t it? > I use Matplotlib with wxPython all the time and I never had any > problems. You should probably try and create a small runnable sample > that reproduces the problem; also, If you are using separate threads > you haVe to be especially careful when it comes to communicating with > the GUI part in wxPython. Only the main thread can access GUI stuff > (meaning the thread the creates the GUI), and communications from > other threads can be achieved using wx.CallAfter, wx.PostEvent, > PubSub, etc... I didn't expect anyone to go through 2263 lines -- that would be crazy! I just wanted to provide some background of what I am working with. I made a "minimal example" that illustrates what I am trying to do, and hopefully someone can point out why it does not work as intended (I attached the file, I hope the attachment goes through the mailing list). The example should show a pyplot window on the screen, which shows the data being collected from the measurement instrument (one new data point every second). However, the window does not show up. Also, I have to use wx.CallAfter to update the pyplot window in order avoid crashing, although I don't think the pyplot window is part of the wxPython world. Any insights would be very welcome! -- You received this message because you are subscribed to the Google Groups "wxPython-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/wxpython-users/Z5CSDQ.XWF1KXD1QEOT3%40gmail.com.
wx_pyplot_minimal_example
(text/x-python3, 3.1 KB)
#!/usr/bin/env python3
# Example showing how I cannot make pyplot work to plot data in a pyplot window
# (1) Show GUI with a button to start running a measurement instrument
# (2) Once the button is pressed, run the measurement instrument:
# - Get a new data value every second
# - After getting a new value, plot all data in a pyplot window <-- *** THIS DOES NOT SEEM TO WORK ***
#
# The problem is that the pyplot window does not seem to show up on the screen.
import time
import random
from threading import Thread
import wx
from matplotlib import pyplot as plt
# measurement instrument that takes measurement data and plots data in a pyplot window
class instrument:
def __init__(self):
# init the instrument
self.values = [] # container list of the measurement values
# set up plotting:
self.fig = plt.figure(figsize=(200,100)) # pyplot figure
self.axes = self.fig.add_subplot(1,1,1) # pyplot axes
plt.ion() # non-blocking pyplot operation ("interactive mode")
self.fig.show() # show the pyplot window <-- *** THIS DOES NOT SEEM TO WORK ***
def read_value(self):
# get a (fake) measurement value
print('Getting a new data value...')
val = random.random() # determine a (fake) data value
self.values.append(val) # append the value to list of previous values
return val
def plot_data(self):
print('Plotting the data...')
self.axes.cla() # clear plot data
self.axes.plot(self.values) # plot all data
# Thread that gets measurement data from the instrument, with logging to pyplot window
class measurement_thread(Thread):
def __init__(self, main_window):
Thread.__init__(self)
self.main_window = main_window
def run(self):
# get data from instrument and plot the data in pyplot window
while True:
self.main_window.instrument.read_value() # get a measurement value
wx.CallAfter( self.main_window.instrument.plot_data ) # update the pyplot figure <-- *** THIS NEEDS TO BE IN wx.CallAfter TO AVOID CRASHING, BUT I DON'T UNDERSTAND WHY ***
time.sleep(1) # wait a bit for the next measurement
# main window:
class MyFrame(wx.Frame):
def __init__(self):
# define GUI:
wx.Frame.__init__(self, None, title="Instrument Control", size=(200,100))
panel = wx.Panel(self)
button = wx.Button(panel, label='Start measurements')
button.Bind(wx.EVT_BUTTON, self.on_button_press)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(button, 1, wx.ALL | wx.CENTER, 25)
panel.SetSizer(sizer)
# measurement instrument, and thread for measurements:
self.instrument = instrument()
self.measurement_thread = measurement_thread(self)
# show the window:
self.Show()
def on_button_press(self, event):
print('Starting the measurement thread...')
self.measurement_thread.start() # start the measurement thread
# main:
if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()