pyqtgraph: synchronize scaling of axes in different plots

谁说我不能喝 提交于 2019-12-12 05:39:55

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!