From 5013dc8d82b95f46b22f3141ad993865d43ce00b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 4 Sep 2013 23:07:00 -0500 Subject: [PATCH 1/8] replaced `col2hex` which seems to have gotten lost in a bad merge --- lib/matplotlib/backends/qt4_editor/formlayout.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index 470d12b8e60d..e219dd63897e 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -60,6 +60,12 @@ import datetime + +def col2hex(color): + """Convert matplotlib color to hex before passing to Qt""" + return rgb2hex(colorConverter.to_rgb(color)) + + class ColorButton(QtGui.QPushButton): """ Color choosing push button From c5abc50492ae1b660c8ac28a8e14149610481f5b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 4 Sep 2013 23:08:09 -0500 Subject: [PATCH 2/8] pep8 fixes --- .../backends/qt4_editor/formlayout.py | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index e219dd63897e..8aa4c7ac6d9e 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -107,9 +107,9 @@ def to_qcolor(color): color = col2hex(color) except ValueError: #print('WARNING: ignoring invalid color %r' % color) - return qcolor # return invalid QColor - qcolor.setNamedColor(color) # set using hex color - return qcolor # return valid QColor + return qcolor # return invalid QColor + qcolor.setNamedColor(color) # set using hex color + return qcolor # return valid QColor class ColorLayout(QtGui.QHBoxLayout): @@ -130,7 +130,7 @@ def __init__(self, color, parent=None): def update_color(self): color = self.text() qcolor = to_qcolor(color) - self.colorbtn.color = qcolor # defaults to black if not qcolor.isValid() + self.colorbtn.color = qcolor # defaults to black if not qcolor.isValid() def update_text(self, color): self.lineedit.setText(color.name()) @@ -141,7 +141,9 @@ def text(self): def font_is_installed(font): """Check if font is installed""" - return [fam for fam in QtGui.QFontDatabase().families() if six.text_type(fam)==font] + return [fam for fam in QtGui.QFontDatabase().families() + if six.text_type(fam) == font] + def tuple_to_qfont(tup): """ @@ -162,10 +164,12 @@ def tuple_to_qfont(tup): font.setBold(bold) return font + def qfont_to_tuple(font): return (six.text_type(font.family()), int(font.pointSize()), font.italic(), font.bold()) + class FontLayout(QtGui.QGridLayout): """Font selection""" def __init__(self, value, parent=None): @@ -214,6 +218,7 @@ def is_edit_valid(edit): return state == QtGui.QDoubleValidator.Acceptable + class FormWidget(QtGui.QWidget): def __init__(self, data, comment="", parent=None): QtGui.QWidget.__init__(self, parent) @@ -264,8 +269,8 @@ def setup(self): selindex = value.pop(0) field = QtGui.QComboBox(self) if isinstance(value[0], (list, tuple)): - keys = [ key for key, _val in value ] - value = [ val for _key, val in value ] + keys = [key for key, _val in value] + value = [val for _key, val in value] else: keys = value field.addItems(value) @@ -274,7 +279,7 @@ def setup(self): elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, int): - print("Warning: '%s' index is invalid (label: " \ + print("Warning: '%s' index is invalid (label: " "%s, value: %s)" % (selindex, label, value), file=STDERR) selindex = 0 field.setCurrentIndex(selindex) @@ -282,7 +287,7 @@ def setup(self): field = QtGui.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) - else : + else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, float): field = QtGui.QLineEdit(repr(value), self) @@ -364,7 +369,7 @@ def setup(self): widget.setup() def get(self): - return [ widget.get() for widget in self.widgetlist] + return [widget.get() for widget in self.widgetlist] class FormTabWidget(QtGui.QWidget): @@ -376,7 +381,7 @@ def __init__(self, datalist, comment="", parent=None): self.setLayout(layout) self.widgetlist = [] for data, title, comment in datalist: - if len(data[0])==3: + if len(data[0]) == 3: widget = FormComboWidget(data, comment=comment, parent=self) else: widget = FormWidget(data, comment=comment, parent=self) @@ -389,7 +394,7 @@ def setup(self): widget.setup() def get(self): - return [ widget.get() for widget in self.widgetlist] + return [widget.get() for widget in self.widgetlist] class FormDialog(QtGui.QDialog): @@ -404,7 +409,7 @@ def __init__(self, data, title="", comment="", if isinstance(data[0][0], (list, tuple)): self.formwidget = FormTabWidget(data, comment=comment, parent=self) - elif len(data[0])==3: + elif len(data[0]) == 3: self.formwidget = FormComboWidget(data, comment=comment, parent=self) else: @@ -418,7 +423,7 @@ def __init__(self, data, title="", comment="", # Button box self.bbox = bbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok - |QtGui.QDialogButtonBox.Cancel) + | QtGui.QDialogButtonBox.Cancel) self.connect(self.formwidget, QtCore.SIGNAL('update_buttons()'), self.update_buttons) if self.apply_callback is not None: @@ -502,7 +507,6 @@ def fedit(data, title="", comment="", icon=None, parent=None, apply=None): return dialog.get() - if __name__ == "__main__": def create_datalist_example(): @@ -529,6 +533,7 @@ def create_datagroup_example(): #--------- datalist example datalist = create_datalist_example() + def apply_test(data): print("data:", data) print("result:", fedit(datalist, title="Example", From b5add85e8c9c79eeb5bb4df68958ea0243b4179b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 4 Sep 2013 23:09:07 -0500 Subject: [PATCH 3/8] pep8 fixes --- lib/matplotlib/backends/backend_qt4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index f9916a363bad..6ba4a370c178 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -781,7 +781,7 @@ def __init__(self, targetfig, parent): layout.setAlignment(self.slidertop, QtCore.Qt.AlignHCenter) bottomlabel = QtGui.QLabel('bottom') # this might not ever be used - layout.addWidget(QtGui.QLabel('bottom'), 4, 2) + layout.addWidget(bottomlabel, 4, 2) layout.addWidget(self.sliderbottom, 3, 2) layout.setAlignment(self.sliderbottom, QtCore.Qt.AlignHCenter) From 7ddc5ee2cacaa48a77dbc21b6ef951644d004b26 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 4 Sep 2013 23:13:47 -0500 Subject: [PATCH 4/8] converted import-critical PyQt calls to new style so that it will not seg-fault when using PySide Addresses issue #2378 --- lib/matplotlib/backends/backend_qt4.py | 52 ++++++------------- .../backends/qt4_editor/formlayout.py | 28 +++++----- 2 files changed, 29 insertions(+), 51 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 6ba4a370c178..99e0276aabe5 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -82,9 +82,8 @@ def _create_qApp(): if display is None or not re.search(':\d', display): raise RuntimeError('Invalid DISPLAY variable') - qApp = QtGui.QApplication([" "]) - QtCore.QObject.connect(qApp, QtCore.SIGNAL("lastWindowClosed()"), - qApp, QtCore.SLOT("quit()")) + qApp = QtGui.QApplication([" "]) # probably fine, not used by QT to resolve anything + qApp.lastWindowClosed.connect(qApp.quit) else: qApp = app @@ -469,8 +468,7 @@ def __init__(self, canvas, num): self.toolbar = self._get_toolbar(self.canvas, self.window) if self.toolbar is not None: self.window.addToolBar(self.toolbar) - QtCore.QObject.connect(self.toolbar, QtCore.SIGNAL("message"), - self._show_message) + self.toolbar.message.connect(self._show_message) tbs_height = self.toolbar.sizeHint().height() else: tbs_height = 0 @@ -556,6 +554,8 @@ def set_window_title(self, title): class NavigationToolbar2QT(NavigationToolbar2, QtGui.QToolBar): + message = QtCore.Signal(str) + def __init__(self, canvas, parent, coordinates=True): """ coordinates: should we show the coordinates on the right? """ self.canvas = canvas @@ -656,7 +656,7 @@ def dynamic_update(self): self.canvas.draw() def set_message(self, s): - self.emit(QtCore.SIGNAL("message"), s) + self.message.emit(s) if self.coordinates: self.locLabel.setText(s.replace(', ', '\n')) @@ -746,18 +746,10 @@ def __init__(self, targetfig, parent): self.sliderhspace = QtGui.QSlider(QtCore.Qt.Vertical) # constraints - QtCore.QObject.connect(self.sliderleft, - QtCore.SIGNAL("valueChanged(int)"), - self.sliderright.setMinimum) - QtCore.QObject.connect(self.sliderright, - QtCore.SIGNAL("valueChanged(int)"), - self.sliderleft.setMaximum) - QtCore.QObject.connect(self.sliderbottom, - QtCore.SIGNAL("valueChanged(int)"), - self.slidertop.setMinimum) - QtCore.QObject.connect(self.slidertop, - QtCore.SIGNAL("valueChanged(int)"), - self.sliderbottom.setMaximum) + self.sliderleft.valueChanged.connect(self.sliderright.setMinimum) + self.sliderright.valueChanged.connect(self.sliderleft.setMaximum) + self.sliderbottom.valueChanged.connect(self.slidertop.setMinimum) + self.slidertop.valueChanged.connect(self.sliderbottom.setMaximum) sliders = (self.sliderleft, self.sliderbottom, self.sliderright, self.slidertop, self.sliderwspace, self.sliderhspace,) @@ -820,24 +812,12 @@ def __init__(self, targetfig, parent): self.sliderhspace.setSliderPosition( int(targetfig.subplotpars.hspace*1000)) - QtCore.QObject.connect(self.sliderleft, - QtCore.SIGNAL("valueChanged(int)"), - self.funcleft) - QtCore.QObject.connect(self.sliderbottom, - QtCore.SIGNAL("valueChanged(int)"), - self.funcbottom) - QtCore.QObject.connect(self.sliderright, - QtCore.SIGNAL("valueChanged(int)"), - self.funcright) - QtCore.QObject.connect(self.slidertop, - QtCore.SIGNAL("valueChanged(int)"), - self.functop) - QtCore.QObject.connect(self.sliderwspace, - QtCore.SIGNAL("valueChanged(int)"), - self.funcwspace) - QtCore.QObject.connect(self.sliderhspace, - QtCore.SIGNAL("valueChanged(int)"), - self.funchspace) + self.sliderleft.valueChanged.connect(self.funcleft) + self.sliderbottom.valueChanged.connect(self.funcbottom) + self.sliderright.valueChanged.connect(self.funcright) + self.slidertop.valueChanged.connect(self.functop) + self.sliderwspace.valueChanged.connect(self.funcwspace) + self.sliderhspace.valueChanged.connect(self.funchspace) def funcleft(self, val): if val == self.sliderright.value(): diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index 8aa4c7ac6d9e..cb57df3d39d5 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -70,33 +70,33 @@ class ColorButton(QtGui.QPushButton): """ Color choosing push button """ - __pyqtSignals__ = ("colorChanged(QColor)",) + colorChanged = QtCore.Signal(QtGui.QColor) def __init__(self, parent=None): QtGui.QPushButton.__init__(self, parent) self.setFixedSize(20, 20) self.setIconSize(QtCore.QSize(12, 12)) - self.connect(self, QtCore.SIGNAL("clicked()"), self.choose_color) + self.clicked.connect(self.choose_color) self._color = QtGui.QColor() def choose_color(self): - color = QtGui.QColorDialog.getColor(self._color,self.parentWidget(),'') + color = QtGui.QColorDialog.getColor(self._color, self.parentWidget(), '') if color.isValid(): self.set_color(color) def get_color(self): return self._color - @QtCore.Slot("QColor") + @QtCore.Slot(QtGui.QColor) def set_color(self, color): if color != self._color: self._color = color - self.emit(QtCore.SIGNAL("colorChanged(QColor)"), self._color) + self.colorChanged.emit(self._color) pixmap = QtGui.QPixmap(self.iconSize()) pixmap.fill(color) self.setIcon(QtGui.QIcon(pixmap)) - color = QtCore.Property("QColor", get_color, set_color) + color = QtCore.Property(QtGui.QColor, get_color, set_color) def to_qcolor(color): @@ -118,13 +118,11 @@ def __init__(self, color, parent=None): QtGui.QHBoxLayout.__init__(self) assert isinstance(color, QtGui.QColor) self.lineedit = QtGui.QLineEdit(color.name(), parent) - self.connect(self.lineedit, QtCore.SIGNAL("editingFinished()"), - self.update_color) + self.lineedit.editingFinished.connect(self.update_color) self.addWidget(self.lineedit) self.colorbtn = ColorButton(parent) self.colorbtn.color = color - self.connect(self.colorbtn, QtCore.SIGNAL("colorChanged(QColor)"), - self.update_text) + self.colorbtn.colorChanged.connect(self.update_text) self.addWidget(self.colorbtn) def update_color(self): @@ -354,8 +352,7 @@ def __init__(self, datalist, comment="", parent=None): self.stackwidget = QtGui.QStackedWidget(self) layout.addWidget(self.stackwidget) - self.connect(self.combobox, QtCore.SIGNAL("currentIndexChanged(int)"), - self.stackwidget, QtCore.SLOT("setCurrentIndex(int)")) + self.combobox.currentIndexChanged.connect(self.stackwidget.setCurrentIndex) self.widgetlist = [] for data, title, comment in datalist: @@ -428,9 +425,10 @@ def __init__(self, data, title="", comment="", self.update_buttons) if self.apply_callback is not None: apply_btn = bbox.addButton(QtGui.QDialogButtonBox.Apply) - self.connect(apply_btn, QtCore.SIGNAL("clicked()"), self.apply) - self.connect(bbox, QtCore.SIGNAL("accepted()"), QtCore.SLOT("accept()")) - self.connect(bbox, QtCore.SIGNAL("rejected()"), QtCore.SLOT("reject()")) + apply_btn.clicked.connect(self.apply) + + bbox.accepted.connect(self.accept) + bbox.rejected.connect(self.reject) layout.addWidget(bbox) self.setLayout(layout) From bf3b1b45b3714ebb29d72e6f8be94e7ee279e729 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 4 Sep 2013 23:20:29 -0500 Subject: [PATCH 5/8] pep8 fixes --- examples/user_interfaces/embedding_in_qt4.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/user_interfaces/embedding_in_qt4.py b/examples/user_interfaces/embedding_in_qt4.py index 6d9b5b5a0d08..5ce964d3ecec 100755 --- a/examples/user_interfaces/embedding_in_qt4.py +++ b/examples/user_interfaces/embedding_in_qt4.py @@ -10,7 +10,9 @@ # may be distributed without limitation. from __future__ import unicode_literals -import sys, os, random +import sys +import os +import random from matplotlib.backends import qt4_compat use_pyside = qt4_compat.QT_API == qt4_compat.QT_API_PYSIDE if use_pyside: @@ -62,18 +64,18 @@ class MyDynamicMplCanvas(MyMplCanvas): def __init__(self, *args, **kwargs): MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) - if use_pyside: + if use_pyside: timer.timeout.connect(self.update_figure) else: QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure) timer.start(1000) def compute_initial_figure(self): - self.axes.plot([0, 1, 2, 3], [1, 2, 0, 4], 'r') + self.axes.plot([0, 1, 2, 3], [1, 2, 0, 4], 'r') def update_figure(self): # Build a list of 4 random integers between 0 and 10 (both inclusive) - l = [ random.randint(0, 10) for i in range(4) ] + l = [random.randint(0, 10) for i in range(4)] self.axes.plot([0, 1, 2, 3], l, 'r') self.draw() From bcdf5f5c7708ef1e6e62dacca1ab09cf2589503d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 5 Sep 2013 00:14:06 -0500 Subject: [PATCH 6/8] second pass at catching the rest of the old-style signal/slot connections. --- lib/matplotlib/backends/backend_qt4.py | 20 +++++++++---------- .../backends/qt4_editor/formlayout.py | 11 ++++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 99e0276aabe5..6ae808359cae 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -133,8 +133,7 @@ def __init__(self, *args, **kwargs): # Create a new timer and connect the timeout() signal to the # _on_timer method. self._timer = QtCore.QTimer() - QtCore.QObject.connect(self._timer, QtCore.SIGNAL('timeout()'), - self._on_timer) + self._timer.timeout.connect(self._on_timer) self._timer_set_interval() def __del__(self): @@ -142,8 +141,7 @@ def __del__(self): # disconnect try: TimerBase.__del__(self) - QtCore.QObject.disconnect(self._timer, - QtCore.SIGNAL('timeout()'), self._on_timer) + self._timer.timeout.disconnect(self._on_timer) except RuntimeError: # Timer C++ object already deleted pass @@ -422,8 +420,10 @@ def idle_draw(*args): class MainWindow(QtGui.QMainWindow): + closing = QtCore.Signal() + def closeEvent(self, event): - self.emit(QtCore.SIGNAL('closing()')) + self.closing.emit() QtGui.QMainWindow.closeEvent(self, event) @@ -443,10 +443,8 @@ def __init__(self, canvas, num): FigureManagerBase.__init__(self, canvas, num) self.canvas = canvas self.window = MainWindow() - self.window.connect(self.window, QtCore.SIGNAL('closing()'), - canvas.close_event) - self.window.connect(self.window, QtCore.SIGNAL('closing()'), - self._widgetclosed) + self.window.closing.connect(canvas.close_event) + self.window.closing.connect(self._widgetclosed) self.window.setWindowTitle("Figure %d" % num) image = os.path.join(matplotlib.rcParams['datapath'], @@ -538,8 +536,8 @@ def destroy(self, *args): if self.window._destroying: return self.window._destroying = True - QtCore.QObject.disconnect(self.window, QtCore.SIGNAL('destroyed()'), - self._widgetclosed) + self.window.destroyed.connect(self._widgetclosed) + if self.toolbar: self.toolbar.destroy() if DEBUG: diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index cb57df3d39d5..f1fcd66670da 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -218,6 +218,7 @@ def is_edit_valid(edit): class FormWidget(QtGui.QWidget): + update_buttons = QtCore.Signal() def __init__(self, data, comment="", parent=None): QtGui.QWidget.__init__(self, parent) from copy import deepcopy @@ -292,8 +293,7 @@ def setup(self): field.setValidator(QtGui.QDoubleValidator(field)) dialog = self.get_dialog() dialog.register_float_field(field) - self.connect(field, QtCore.SIGNAL('textChanged(QString)'), - lambda text: dialog.update_buttons()) + field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, int): field = QtGui.QSpinBox(self) field.setRange(-1e9, 1e9) @@ -343,6 +343,8 @@ def get(self): class FormComboWidget(QtGui.QWidget): + update_buttons = QtCore.Signal() + def __init__(self, datalist, comment="", parent=None): QtGui.QWidget.__init__(self, parent) layout = QtGui.QVBoxLayout() @@ -370,6 +372,8 @@ def get(self): class FormTabWidget(QtGui.QWidget): + update_buttons = QtCore.Signal() + def __init__(self, datalist, comment="", parent=None): QtGui.QWidget.__init__(self, parent) layout = QtGui.QVBoxLayout() @@ -421,8 +425,7 @@ def __init__(self, data, title="", comment="", # Button box self.bbox = bbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) - self.connect(self.formwidget, QtCore.SIGNAL('update_buttons()'), - self.update_buttons) + self.formwidget.update_buttons.connect(self.update_buttons) if self.apply_callback is not None: apply_btn = bbox.addButton(QtGui.QDialogButtonBox.Apply) apply_btn.clicked.connect(self.apply) From 1c649f57893b40d394173f0b664da7f5fbaa2671 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 5 Sep 2013 15:32:25 -0500 Subject: [PATCH 7/8] change from mdboom --- lib/matplotlib/backends/backend_qt4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 6ae808359cae..788947900df1 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -82,7 +82,7 @@ def _create_qApp(): if display is None or not re.search(':\d', display): raise RuntimeError('Invalid DISPLAY variable') - qApp = QtGui.QApplication([" "]) # probably fine, not used by QT to resolve anything + qApp = QtGui.QApplication([str(" ")]) qApp.lastWindowClosed.connect(qApp.quit) else: qApp = app From df3d8829c99f4ee4108b654e1b06121efd3e987c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 7 Sep 2013 09:55:44 -0500 Subject: [PATCH 8/8] use new-style for PyQt as well as PySide --- examples/user_interfaces/embedding_in_qt4.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/user_interfaces/embedding_in_qt4.py b/examples/user_interfaces/embedding_in_qt4.py index 5ce964d3ecec..84b1fc372594 100755 --- a/examples/user_interfaces/embedding_in_qt4.py +++ b/examples/user_interfaces/embedding_in_qt4.py @@ -64,10 +64,7 @@ class MyDynamicMplCanvas(MyMplCanvas): def __init__(self, *args, **kwargs): MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) - if use_pyside: - timer.timeout.connect(self.update_figure) - else: - QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure) + timer.timeout.connect(self.update_figure) timer.start(1000) def compute_initial_figure(self):