I'm trying to create GUI-app with real-time data visualization.
The solution I came up with is to use well-known trick with partial redrawing:
fig, axes = plt.subplots(nrows=2, ncols=1)
axes[0].set_{labels, limits}
axes[1].set_{labels, limits}
fig.show()
fig.canvas.draw()
N = 2
graph_0 = axes[0].scatter([] * N, [] * N, s=[np.pi*5**2] * N, animated=True)
graph_1 = axes[1].scatter([] * N, [] * N, s=[np.pi*5**2] * N, animated=True)
bg_0 = fig.canvas.copy_from_bbox(axes[0].bbox)
bg_1 = fig.canvas.copy_from_bbox(axes[1].bbox)
while True:
# Acquire new data
tmp = [1, 2] # *For example*
# Clear plots
fig.canvas.restore_region(bg_0)
fig.canvas.restore_region(bg_1)
# Set data to be visualized
graph_0.set_offsets([(i+1, d) for i, d in enumerate(tmp)])
graph_1.set_offsets([(i+1, d) for i, d in enumerate(tmp)])
# Redraw
axes[0].draw_artist(graph_0)
axes[1].draw_artist(graph_1)
fig.canvas.blit(axes[0].bbox)
fig.canvas.blit(axes[1].bbox)
This solution is OK and everything works fine.
After that I tried to implement the same approach but using PyQt backend (to add also some control elements).
Here is the code:
import sys
from PyQt4 import QtGui
from PyQt4.uic import loadUiType
import numpy as np
import matplotlib
import matplotlib.style
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas)
Ui_MainWindow, QMainWindow = loadUiType('dialog.ui')
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, ):
super(Main, self).__init__()
self.setupUi(self)
self.layout_mpl = QtGui.QVBoxLayout()
self.widget_mpl.setLayout(self.layout_mpl)
# Assign callbacks
self.button.clicked.connect(self.update_figure)
self.prepare_figure()
def prepare_figure(self):
self.fig, self.axes = plt.subplots(nrows=2, ncols=1)
self.canvas = FigureCanvas(self.fig)
self.layout_mpl.addWidget(self.canvas)
# self.canvas.draw()
self.axes[0].set_{labels, limits}
self.axes[1].set_{labels, limits}
self.graph = [None] * 2
N = 5
self.graph[0] = self.axes[0].scatter(
[] * N, [] * N, s=[np.pi*5**2] * N, animated=True)
self.graph[1] = self.axes[1].scatter(
[] * N, [] * N, s=[np.pi*5**2] * N, animated=True)
self.canvas.draw()
self.bg = self.canvas.copy_from_bbox(self.fig.bbox)
# self.bg = [None] * 2
# self.bg[0] = self.canvas.copy_from_bbox(self.fig.axes[0].bbox)
# self.bg[1] = self.canvas.copy_from_bbox(self.fig.axes[1].bbox)
def update_figure(self):
# self.canvas.restore_region(self.bg[0])
# self.canvas.restore_region(self.bg[1])
self.canvas.restore_region(self.bg)
# Set data to be visualized
self.graph[0].set_offsets([(i+1, d) for i, d in
enumerate(np.random.rand(5)*100+100)])
self.graph[1].set_offsets([(i+1, d) for i, d in
enumerate(np.random.rand(5)*100+100)])
# Redraw
self.axes[0].draw_artist(self.graph[0])
self.axes[1].draw_artist(self.graph[1])
self.canvas.blit(self.axes[0].bbox)
self.canvas.blit(self.axes[1].bbox)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
You might see different combinations of calls I used under commented lines.
So, I expect on every click of button
the plots to be updated. It actually works, except one blocking issue:
a) Application just started
b) Button has been clicked once
c) Switched focus to another window and back (this plot is the one with offset, but the points are placed in old coordinates)
Could someone give any directions, please?
Thanks in advance!
Versions used: Python 3.4.3, matplotlib 1.4.3, PyQt 4.10.4 .
The solution is to constanly check and update axes.bbox
sizes:
http://matplotlib.org/1.3.1/examples/old_animation/animation_blit_qt4.html