在多个地方嵌入matplotlib小部件
我有一个用matplotlib画的图表,我想在两个不同的窗口里都显示这个图表,使用的是PyQt4。我尝试把这个图表的组件放到两个窗口的布局里,但这样的话,第一个窗口里的图表就消失了。有没有其他方法可以做到这一点,而不是创建两个一模一样的图表并保持它们同步?
2 个回答
0
虽然这不是一个完美的解决方案,但matplotlib有一种内置的方法,可以让两个不同的图的范围、刻度等保持一致。
比如:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 4 * np.pi, 100)
y = np.cos(x)
figures = [plt.figure() for _ in range(3)]
ax1 = figures[0].add_subplot(111)
axes = [ax1] + [fig.add_subplot(111, sharex=ax1, sharey=ax1) for fig in figures[1:]]
for ax in axes:
ax.plot(x, y, 'go-')
ax1.set_xlabel('test')
plt.show()
注意,当你放大、移动等操作时,这三个图会保持同步。
不过,可能还有更好的方法来实现这个功能。
2
问题在于,你不能把同一个Qt控件添加到两个不同的父控件中,因为在添加控件的过程中,Qt会进行一个重新归属的操作,这就是你看到的情况:
... 这个控件会从第一个窗口消失...
所以解决办法是创建两个画布,它们共享同一个图形。下面是一个示例代码,这段代码会显示两个主窗口,每个窗口里有两个画布,这四个图表会保持同步:
import sys
from PyQt4 import QtGui
import numpy as np
import numpy.random as rd
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.main_widget = QtGui.QWidget(self)
vbl = QtGui.QVBoxLayout(self.main_widget)
self._fig = Figure()
self.ax = self._fig.add_subplot(111)
#note the same fig for two canvas
self.fc1 = FigureCanvas(self._fig) #canvas #1
self.fc2 = FigureCanvas(self._fig) #canvas #1
self.but = QtGui.QPushButton(self.main_widget)
self.but.setText("Update") #for testing the sync
vbl.addWidget(self.fc1)
vbl.addWidget(self.fc2)
vbl.addWidget(self.but)
self.setCentralWidget(self.main_widget)
@property
def fig(self):
return self._fig
@fig.setter
def fig(self, value):
self._fig = value
#keep the same fig in both canvas
self.fc1.figure = value
self.fc2.figure = value
def redraw_plot(self):
self.fc1.draw()
self.fc2.draw()
qApp = QtGui.QApplication(sys.argv)
aw1 = ApplicationWindow() #window #1
aw2 = ApplicationWindow() #window #2
aw1.fig = aw2.fig #THE SAME FIG FOR THE TWO WINDOWS!
def update_plot():
'''Just a random plot for test the sync!'''
#note that the update is only in the first window
ax = aw1.fig.gca()
ax.clear()
ax.plot(range(10),rd.random(10))
#calls to redraw the canvas
aw1.redraw_plot()
aw2.redraw_plot()
#just for testing the update
aw1.but.clicked.connect(update_plot)
aw2.but.clicked.connect(update_plot)
aw1.show()
aw2.show()
sys.exit(qApp.exec_())