问题
I want to synchronize the X-Axis of several pyqtgraph plots. When the user rescales the X-Axis with mouse interactions (e.g. scroll-wheel while mouse on x-Axis) I want to assign the same changes to all the other plots. So how do I do this?
I derived a minimized code from a basic example below.
Do I have to overwrite the viewRangeChanged()
functions of w1
and w2
?
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.console
import numpy as np
from pyqtgraph.dockarea import *
win = QtGui.QMainWindow()
area = DockArea()
win.setCentralWidget(area)
win.resize(1000,500)
win.setWindowTitle('pyqtgraph example: dockarea')
d1 = Dock("Dock1")
d2 = Dock("Dock2")
area.addDock(d1, 'bottom')
area.addDock(d2, 'bottom', d1)
w1 = pg.PlotWidget(title="Dock 1 plot")
w1.plot(np.random.normal(size=100))
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
d2.addWidget(w2)
win.show()
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
This question has a follow up here with another answer to this question.
回答1:
We need to use the sigRangeChanged signal and connect it to a slot, the problem is that the change of the range another item would generate the signal sigRangeChanged and so on generating an infinite loop, to solve this you must disconnect those signals before making the modifications and reconnect them to the final.
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
def onSigRangeChanged(r):
w1.sigRangeChanged.disconnect(onSigRangeChanged)
w2.sigRangeChanged.disconnect(onSigRangeChanged)
if w1 == r:
w2.setRange(xRange=r.getAxis('bottom').range)
elif w2 == r:
w1.setRange(xRange=r.getAxis('bottom').range)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
Example:
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
import sys
def onSigRangeChanged(r):
w1.sigRangeChanged.disconnect(onSigRangeChanged)
w2.sigRangeChanged.disconnect(onSigRangeChanged)
if w1==r:
w2.setRange(xRange=r.getAxis('bottom').range)
elif w2 == r:
w1.setRange(xRange=r.getAxis('bottom').range)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
app = QtGui.QApplication(sys.argv)
win = QtGui.QMainWindow()
area = DockArea()
win.setCentralWidget(area)
win.resize(1000,500)
win.setWindowTitle('pyqtgraph example: dockarea')
d1 = Dock("Dock1")
d2 = Dock("Dock2")
area.addDock(d1, 'bottom')
area.addDock(d2, 'bottom', d1)
w1 = pg.PlotWidget(title="Dock 1 plot")
it=w1.plot(np.random.normal(size=100))
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
d2.addWidget(w2)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
win.show()
sys.exit(app.exec_())
回答2:
Better yet,
Instead of disconnecting then reconnecting signals, it is possible to use blockSignals.
here is a generic way to synchronize any number of plots :
syncedPlots = [w1, w2, w3] # put as many plots as you wish
def onSigRangeChanged(r):
for g in syncedPlots:
if g !=r :
g.blockSignals(True)
g.setRange(xRange=r.getAxis('bottom').range)
g.blockSignals(False)
for g in syncedPlots:
g.sigRangeChanged.connect(onSigRangeChanged)
来源:https://stackoverflow.com/questions/44576435/pyqtgraph-synchronize-scaling-of-axes-in-different-plots