I have an application that displays a GUI using GTK3 for python 3. It has a plot rendered by matplotlib. When the plot is included in the code the UI gets zoomed in (see pictures). This happens on a mac with retina display. On Ubuntu it works perfectly. Here is the code that draws the GUI:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from matplotlib.figure import Figure
import matplotlib.cm as cm
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
from threading import Thread
import os
from instruction import *
from instructionwriter import *
class UI:
def __init__(self):
self.instructions = None
self.builder = Gtk.Builder()
self.builder.add_from_file(os.path.dirname(os.path.realpath(__file__)) + os.path.sep + "UI.glade")
self.builder.connect_signals(self)
scale = self.builder.get_object("scale")
scale.set_label("Välj skalfaktor")
scale.set_relief(Gtk.ReliefStyle.NORMAL)
# This part has to be commented out to make the GUI display correctly but is needed for the application.
#self.fig = Figure()
#self.fig.suptitle("Förhandsvisning")
#self.ax = self.fig.add_subplot(1, 1, 1)
#self.canvas = FigureCanvas(self.fig)
#self.builder.get_object("scrolledwindow1").add_with_viewport(self.canvas)
#self._preview()
self.buttons = [
self.builder.get_object("filechooser"),
self.builder.get_object("centerbutton"),
self.builder.get_object("scale"),
self.builder.get_object("autobutton"),
self.builder.get_object("preview"),
self.builder.get_object("save")
]
self.lastScale = 0.5
statusBar = self.builder.get_object("statusBar")
self.context_id = statusBar.get_context_id("id")
def show(self):
self.builder.get_object("window1").show_all()
def on_exit(self, *args):
Gtk.main_quit()
def on_file_select(self, *args):
filename = self.builder.get_object("filechooser").get_filename()
self.builder.get_object("snurrare").start()
self._disable_ui()
Thread(target=self._load, args=(filename,)).start()
def on_preview(self, *args):
self._preview()
self._display_time()
def on_center(self, *args):
self.instructions.center()
def on_fit(self, *args):
self.instructions.fit()
def on_save(self, *args):
dialog = Gtk.FileChooserDialog("Välj mapp", self.builder.get_object("window1"),
Gtk.FileChooserAction.SELECT_FOLDER,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
"Välj", Gtk.ResponseType.OK))
dialog.set_default_size(800, 400)
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.builder.get_object("snurrare").start()
self._disable_ui()
Thread(target=self._save, args=(dialog.get_filename(),)).start()
dialog.destroy()
def _load(self, filename):
self.lastScale = 0.5
self.builder.get_object("scale").set_value(0.5)
ext = os.path.splitext(filename)[1]
if ext == ".svg":
self.instructions = InstructionList.from_svg(filename)
elif ext == ".py":
self.instructions = InstructionList.from_code(filename)
self.builder.get_object("snurrare").stop()
self._display_time()
self._enable_ui()
def _save(self, folder):
writer = InstructionWriter(self.instructions, 0)
writer.write(folder)
self.builder.get_object("snurrare").stop()
self._enable_ui()
def _disable_ui(self):
for button in self.buttons:
button.set_sensitive(False)
def _enable_ui(self):
for button in self.buttons:
button.set_sensitive(True)
def _preview(self):
if not self.instructions is None:
if self.builder.get_object("scale").get_value() != self.lastScale:
self.lastScale = self.builder.get_object("scale").get_value()
self.instructions.scale(2*self.lastScale)
self.ax.clear()
x = []
y = []
for inst in self.instructions.instructions:
if inst.type == Instruction.MOVE:
self.ax.plot(x, y, 'b')
x = [inst.dest.real]
y = [inst.dest.imag]
elif inst.type == Instruction.LINE:
x.append(inst.dest.real)
y.append(inst.dest.imag)
self.ax.plot(x, y, 'b')
self.ax.plot([-XLIM, XLIM, XLIM, -XLIM, -XLIM], [-YLIM, -YLIM, YLIM, YLIM, -YLIM], 'r')
self.ax.plot([-585, 585, 585, -585, -585], [-413.5, -413.5, 413.5, 413.5, -413.5], 'g:')
self.ax.axis("equal")
self.fig.canvas.draw()
def _display_time(self):
t = self.instructions.time()
self.builder.get_object("statusBar").push(self.context_id, "Uppskattad tid: %dmin %ds" % (t//60, t%60))
ui = UI()
ui.show()
Gtk.main()
GUI when plot is included
GUI when plot is excluded
Related
from PySide2.QtWidgets import QApplication, QMainWindow,QDialog,QLineEdit,QPushButton
from PySide2.QtCore import Qt
import sys
from ui618 import Ui_MainWindow
from numpad import Ui_Dialog
class MyWindow:
def __init__(self) -> None:
self.lastSelectedEditLine = None
# main ui
self.MainWindow = QMainWindow()
self.ui = Ui_MainWindow()
self.ui.setupUi(self.MainWindow)
# numpad
self.QDialog = QDialog(self.MainWindow)
self.numpad = Ui_Dialog()
self.numpad.setupUi(self.QDialog)
self.QDialog.setWindowFlags(Qt.Popup)
# bind editline with numpad
self.lineEdits = self.MainWindow.findChildren(QLineEdit)
for item in self.lineEdits:
item.focusInEvent = lambda e,item=item:self.test(e,item)
def save_quit(self):
sys.exit()
def bindbtn(self):
self.ui.quit.clicked.connect(self.save_quit)
def numpad_btn(self,a,item):
if item.text() != '←':
self.lastSelectedEditLine.setText(self.lastSelectedEditLine.text()+item.text())
else:
self.lastSelectedEditLine.setText(self.lastSelectedEditLine.text()[:-1])
def bindNumpad(self):
numpad_btns = self.QDialog.findChildren(QPushButton)
for item in numpad_btns:
item.clicked.connect(lambda ignore='ignore',item=item : self.numpad_btn(ignore,item))
def test(self,e,item):
self.lastSelectedEditLine = item
this = item
x = self.MainWindow.x()
y = self.MainWindow.y() + self.ui.selectX.rect().bottom()
while this.parentWidget().objectName() != 'MainWindow':
x += this.x()
y += this.y()
this = this.parentWidget()
self.QDialog.move(x, y)
self.QDialog.show()
item.clearFocus()
def show(self):
self.MainWindow.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
myWindow.bindbtn()
myWindow.bindNumpad()
sys.exit(app.exec_())
The code works as expected, the numpad shows while focusing in a qlineedit. and can write and delete to target input line.
I am new to pyside2. Is there a better way to implement the numpad? I this way, the cursor is disable, I have to edit at the end of each editline.
It take several seconds while starting, Some one know how to improve it?
I am looking for a way to create a grid of graphs that can be dragged/dropped to rearrange the order. My first try was using QDockWidgets as they allow for drag/drop, however they were limited in a lot of other ways. Would it be possible to implement this function in a QGridLayout?
For now I have a QGridLayout with 3x3 matplotlib widgets.
Here is an example of the desired layout outcome.
Sample code:
import sys
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import random
from PyQt5.QtWidgets import QGridLayout, QVBoxLayout, QHBoxLayout, QScrollArea, QWidget, QDialog, QApplication, QFrame
class IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.layout = QtWidgets.QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
for i in range(3):
for j in range(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("background-color: white;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # a figure to plot on
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # create an axis
data = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # plot data
self.canvas.draw() # refresh canvas
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())
Here is an implementation that will swap the positions of the items involved in a drag/drop. The 3 main steps are:
(1) Reimplement mousePressEvent to get the index of the LayoutItem based on mouse coordinates.
(2) Reimplement mouseMoveEvent to set up a QDrag of the FigureCanvas.
(3) Reimplement dropEvent to swap the target items in the layout.
Since the matplotlib widgets absorb mouse events you also need to reimplement eventFilter to detect them.
import sys, random
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.target = None
self.setAcceptDrops(True)
self.layout = QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
for i in range(3):
for j in range(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("background-color: white;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # a figure to plot on
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # create an axis
data = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # plot data
self.canvas.draw() # refresh canvas
self.canvas.installEventFilter(self)
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
def eventFilter(self, watched, event):
if event.type() == QEvent.MouseButtonPress:
self.mousePressEvent(event)
elif event.type() == QEvent.MouseMove:
self.mouseMoveEvent(event)
elif event.type() == QEvent.MouseButtonRelease:
self.mouseReleaseEvent(event)
return super().eventFilter(watched, event)
def get_index(self, pos):
for i in range(self.gridLayout.count()):
if self.gridLayout.itemAt(i).geometry().contains(pos) and i != self.target:
return i
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.target = self.get_index(event.windowPos().toPoint())
else:
self.target = None
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton and self.target is not None:
drag = QDrag(self.gridLayout.itemAt(self.target))
pix = self.gridLayout.itemAt(self.target).itemAt(0).widget().grab()
mimedata = QMimeData()
mimedata.setImageData(pix)
drag.setMimeData(mimedata)
drag.setPixmap(pix)
drag.setHotSpot(event.pos())
drag.exec_()
def mouseReleaseEvent(self, event):
self.target = None
def dragEnterEvent(self, event):
if event.mimeData().hasImage():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if not event.source().geometry().contains(event.pos()):
source = self.get_index(event.pos())
if source is None:
return
i, j = max(self.target, source), min(self.target, source)
p1, p2 = self.gridLayout.getItemPosition(i), self.gridLayout.getItemPosition(j)
self.gridLayout.addItem(self.gridLayout.takeAt(i), *p2)
self.gridLayout.addItem(self.gridLayout.takeAt(j), *p1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())
I am trying to add new lines to an existing and open Plot.
I wrote a watchdog watching a folder with measurement data. Every few secs there will be a new data file. The Application I try to generate should read the file when triggered by the watchdog and add the data to the plot.
Dynamic plots using QTimer and stuff is easy when updating existing data, but I don't get a hook for new lines.
Also, do I have to use multithreading when I want to run a script while having a plot on _exec()?
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pq
import sys
import numpy as np
import time
class Plot2d(object):
def __init__(self):
self.traces = dict()
self.num = 0
pq.setConfigOptions(antialias=True)
self.app = QtGui.QApplication(sys.argv)
self.win = pq.GraphicsWindow(title='examples')
self.win.resize(1000, 600)
self.win.setWindowTitle('Windowtitle')
self.canvas = self.win.addPlot(title='Plot')
def starter(self):
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
def trace(self, name, dataset_x, dataset_y):
if name in self.traces:
self.traces[name].setData(dataset_x, dataset_y)
else:
self.traces[name] = self.canvas.plot(pen='y')
def update(self, i):
x_data = np.arange(0, 3.0, 0.01)
y_data = x_data*i
self.trace(str(i), x_data, y_data)
self.trace(str(i), x_data, y_data)
if __name__ == '__main__':
p = Plot2d()
p.update(1)
p.starter()
time.sleep(1)
p.update(2)
This is what I tried. The update function should be called by the watchdog when new data is available in the dir.
import time as time
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
if __name__ == "__main__":
patterns = "*"
ignore_patterns = ""
ignore_directories = False
case_sensitive = True
go_recursively = False
my_event_handler = PatternMatchingEventHandler(patterns, ignore_patterns, ignore_directories, case_sensitive)
def on_created(event):
print(f" {event.src_path} has been created!") #this function should call the plot update
my_event_handler.on_created = on_created
path = (r'C:\Users\...') #path from GUI at some point
my_observer = Observer()
my_observer.schedule(my_event_handler, path, recursive=go_recursively)
my_observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
my_observer.stop()
my_observer.join()
The exec_() method is blocking, so starter() will be too, and will be unlocked when the window is closed, which implies that all the code after starter will only be executed after closing the window. On the other hand you should not use time.sleep in the GUI thread as it blocks the execution of the GUI event loop.
Depending on the technology used, ways of updating elements are offered, in the case of Qt the appropriate way is to use signals so that all the logic of the watchdog will be encapsulated in a QObject that will transmit the information to the GUI through a signal, Then the GUI takes that information to plot.
import sys
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pq
import numpy as np
class QObserver(QtCore.QObject):
dataChanged = QtCore.pyqtSignal(object)
def __init__(self, parent=None):
super(QObserver, self).__init__(parent)
patterns = "*"
ignore_patterns = ""
ignore_directories = False
case_sensitive = True
go_recursively = False
path = r"C:\Users\..." # path from GUI at some point
event_handler = PatternMatchingEventHandler(
patterns, ignore_patterns, ignore_directories, case_sensitive
)
event_handler.on_created = self.on_created
self.observer = Observer()
self.observer.schedule(event_handler, path, recursive=go_recursively)
self.observer.start()
def on_created(self, event):
print(
f" {event.src_path} has been created!"
) # this function should call the plot update
self.dataChanged.emit(np.random.randint(1, 5))
class Plot2d(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.traces = dict()
self.num = 0
pq.setConfigOptions(antialias=True)
self.app = QtGui.QApplication(sys.argv)
self.win = pq.GraphicsWindow(title="examples")
self.win.resize(1000, 600)
self.win.setWindowTitle("Windowtitle")
self.canvas = self.win.addPlot(title="Plot")
def starter(self):
if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"):
QtGui.QApplication.instance().exec_()
def trace(self, name, dataset_x, dataset_y):
if name in self.traces:
self.traces[name].setData(dataset_x, dataset_y)
else:
self.traces[name] = self.canvas.plot(pen="y")
#QtCore.pyqtSlot(object)
def update(self, i):
x_data = np.arange(0, 3.0, 0.01)
y_data = x_data * i
self.trace(str(i), x_data, y_data)
self.trace(str(i), x_data, y_data)
if __name__ == "__main__":
p = Plot2d()
qobserver = QObserver()
qobserver.dataChanged.connect(p.update)
p.starter()
Here is my code:
import sys
import numpy as np
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
class MyGraph(QWidget):
def __init__(self):
super(MyGraph, self).__init__()
self.resize(600, 600)
pg.setConfigOption('background', 'w')
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)
self.pw = pg.PlotWidget(self)
self.pw.plot(x, y, pen=None, symbol='o', symbolBrush='r')
self.plot_btn = QPushButton('Replot', self)
self.plot_btn.clicked.connect(self.plot_slot)
self.v_layout = QVBoxLayout()
self.v_layout.addWidget(self.pw)
self.v_layout.addWidget(self.plot_btn)
self.setLayout(self.v_layout)
def plot_slot(self):
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)
# The new data is added to the existed one
self.pw.plot(x, y, pen=None, symbol='o', symbolBrush='r')
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = MyGraph()
demo.show()
sys.exit(app.exec_())
Every time I clicked the button, I want to clean the existed data and replot the new one, but PlotWidget doesn't seem to have the relative function to let me do that.
Is there any way I can clean the data?
Thanks!
The plot method of PlotWidget generates an item that is responsible for drawing, in your case each time you press the button another plot is created so you observe that
behavior. The solution is to reuse
class MyGraph(QWidget):
def __init__(self):
super(MyGraph, self).__init__()
self.resize(600, 600)
pg.setConfigOption("background", "w")
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)
self.pw = pg.PlotWidget(self)
self.plot = self.pw.plot(x, y, pen=None, symbol="o", symbolBrush="r")
self.plot_btn = QPushButton("Replot", self, clicked=self.plot_slot)
v_layout = QVBoxLayout(self)
v_layout.addWidget(self.pw)
v_layout.addWidget(self.plot_btn)
def plot_slot(self):
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)
self.plot.setData(x, y)
I have a small program that plots a figure with 4 subplots. I make a little GUI and call that plotting function from a thread, so each time I click the button, it should recollect data and redraw that figure (with 4 subplot), without closing the script. The script can plot for the first time, however at the second time (click button without closing the script), it stops at initialize the subplots. I have tried plt.close('all'), plt.close(fig), plt.clf(),... but it doesnt help. I really run out of idea why it stops at the second time.
Here is my full little script. Much appreciate for any inputs
import sys, os
import time
import wx
import traceback
from textwrap import wrap
import shutil
import itertools
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import threading
def test():
Do = Data()
Do.PlotGraph()
class Data(object):
def __init__(self):
self.SavePath = "C:\\Plots\\"
def f(self, t):
return np.exp(-t) * np.cos(2*np.pi*t)
def PlotGraph(self):
#Plotting
print "***** Generating plot"
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
print "Initialize subplots"
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows = 2, ncols = 2, frameon=False, figsize=(20, 10))
fontSize = 13
print "Creating ax1"
ax1title = "ax1"
ax1.set_title(ax1title, fontsize = fontSize)
ax1.plot(t1, self.f(t1), 'bo', t2, self.f(t2), 'k')
print "Creating ax2"
ax2title = "ax2"
ax2.set_title(ax2title, fontsize = fontSize)
ax2.plot(t1, self.f(t1), 'bo', t2, self.f(t2), 'k')
print "Creating ax3"
ax3title = "ax3"
ax3.set_title(ax3title, fontsize = fontSize)
ax3.plot(t1, self.f(t1), 'bo', t2, self.f(t2), 'k')
print "Creating ax4"
ax4title = "ax4"
ax4.set_title(ax4title, fontsize = fontSize)
ax4.plot(t1, self.f(t1), 'bo', t2, self.f(t2), 'k')
fig.subplots_adjust(hspace = 0.35) #make room for axes title and x-axis label
fig.subplots_adjust(bottom = 0.07) #make room for axes title and x-axis label
fig.subplots_adjust(wspace = 0.30)
fig.subplots_adjust(top = .86)
filename= "Test"
if not os.path.exists(self.SavePath):
os.makedirs(self.SavePath)
savefilename = self.unique_file(self.SavePath, filename, "png")
print "***** Saving plot to: " + self.SavePath + savefilename
fig.savefig(self.SavePath + savefilename, dpi = 200)
plt.close(fig)
def unique_file(self, path, basename, ext):
actualname = "%s.%s" % (basename, ext)
c = itertools.count()
while os.path.exists(path + actualname):
actualname = "%s_[%d].%s" % (basename, next(c), ext)
#print "actualname: " + actualname
return actualname
################## THREAD UPDATE GUI ######################
#1. Create new custom event to update the display
DisplayEventType = wx.NewEventType();
EVT_DISPLAY = wx.PyEventBinder(DisplayEventType, 1);
def GetDataThreadStart(window):
GetDataThread(window)
class GetDataThread(threading.Thread):
def __init__(self, output_window):
threading.Thread.__init__(self)
self.output_window = output_window
print "Thread started"
self.start()
def run(self):
test()
print "Test Done\n\n"
self.UpdateFunction("Enable Go Button")
def UpdateFunction(self, msg):
evt = UpdateDisplayEvent(DisplayEventType, -1) #initialize update display event
evt.UpdateText(str(msg)); #update display event
wx.PostEvent(self.output_window, evt)
#Define event
class UpdateDisplayEvent(wx.PyCommandEvent):
def __init__(self, evtType, id):
wx.PyCommandEvent.__init__(self, evtType, id)
self.msg = ""
def UpdateText(self,text):
self.msg = text
def GetText(self):
return self.msg
######## Define GUI ###########
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
class MyFrame(wx.Frame):
def __init__(self, parent):
self.title = 'Testing'
wx.Frame.__init__(self, parent, -1, self.title, size = (300,350))
pnl = MyPanel(self)
self.Go_Button = wx.Button(pnl, -1, "Goooooo!")
self.Bind(wx.EVT_BUTTON, self.ClickGo, self.Go_Button)
BoxSizerMain = wx.BoxSizer(wx.VERTICAL)
BoxSizerMain.Add(self.Go_Button, 0, wx.ALIGN_CENTER_HORIZONTAL)
self.Bind(EVT_DISPLAY, self.OnThreadUpdate)
def ClickGo(self, event):
self.Go_Button.Disable()
GetDataThreadStart(self)
def OnThreadUpdate(self, event):
msg = event.GetText()
if msg == "Enable Go Button":
self.Go_Button.Enable()
def invokeGUI():
app = wx.PySimpleApp()
frame = MyFrame(None)
frame.Show()
frame.Iconize(True)
frame.Iconize(False)
frame.CenterOnScreen()
app.MainLoop()
if __name__ == '__main__':
invokeGUI()
The result
I believe you need to change the matplotlib backend to wx via the matplotlib.use() function in order to embed matplotlib plots within wx graphics.
Here's what I changed in your script:
import matplotlib
matplotlib.use('WX')
import matplotlib.pyplot as plt
This produced the following image after testing:
Console output:
Initialize subplots
Creating ax1
Creating ax2
Creating ax3
Creating ax4
***** Saving plot to: /Users/luccary/Downloads/foo/Test_[0].png
/Users/luccary/.virtualenvs/numpy/lib/python2.7/site-packages/matplotlib/cbook.py:136: MatplotlibDeprecationWarning: The WX backend is deprecated. It's untested and will be removed in Matplotlib 2.2. Use the WXAgg backend instead. See Matplotlib usage FAQ for more info on backends.
warnings.warn(message, mplDeprecation, stacklevel=1)
Test Done
Please note the deprecation warning, since wx will be removed as a backend in Matplotlib 2.2, and you should likely use wxagg instead.
References: See this matplotlib tutorial which I found after reading a Stack Overflow answer to a similar question here.
Hope that answers your question. Good luck!