Hi everyone!
I have a question regarding plotting two x axes in one PlotWidget. I've seen a few examples regarding multiple axes in one plot but to no avail.
What I try to accomplish is the following:
I have a single line that I want plot in a PlotWidget and visualize that line using two differently scaled x axes. E.g. Let's say the bottom x axis to be in units of "Frames/Pictures taken" and the upper x axis to be in units of "Seconds". Hence, the mapping from one axis to the other should be strict and maintained when I zoom or pan the curve. In the "MultiplePlotAxes.py" example this is not the case since different datasets are plotted; zooming in only changes on y axis in that example. However, I need the two axes to zoom synchronized while maintaining the relationship between both x scales. Here is the code I pieced together not knowing what I'm really doing...:
# -*- coding: utf-8 -*-
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
pg.mkQApp()
MainPlot = pg.PlotWidget()
MainPlot.show()
MainPlot.setWindowTitle('Dual x axis example, synchronized zoom on different axes')
AuxPlot = pg.ViewBox()
#AuxPlot.setXLink(MainPlot) #this line will cause the two x axes to display the same range which is not wanted in this example
AuxPlot.setYLink(MainPlot) #this will synchronize zooming along the y axis
MainPlot.showAxis('top')
MainPlot.scene().addItem(AuxPlot)
AuxPlot.setGeometry(MainPlot.getPlotItem().vb.sceneBoundingRect())
MainPlot.getAxis('top').linkToView(AuxPlot)
##plot data
MainPlot.plot([0,1,2,3],[0,1,2,3], pen="w")
AuxPlot.addItem(pg.PlotCurveItem([-1,0,1,2],[0,1,2,3], pen="b")) #this data is scaled differently along the x axis while y is the same as in MainPlot
## This commented section was taken from another user's example but
##only one x axis zooms while the other is unaffected
def updateViews():
## view has resized; update auxiliary views to match
global MainPlot, AuxPlot
AuxPlot.setGeometry(MainPlot.getPlotItem().vb.sceneBoundingRect())
## need to re-update linked axes since this was called
## incorrectly while views had different shapes.
## (probably this should be handled in ViewBox.resizeEvent)
AuxPlot.linkedViewChanged(MainPlot.getPlotItem().vb, AuxPlot.YAxis)
updateViews()
MainPlot.getPlotItem().sigRangeChanged.connect(updateViews)
##end of other user's example
## 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_()
I included a snippet from another user (See post here:
https://groups.google.com/forum/#!topic/pyqtgraph/7wQeFe2iVUw) but I don't understand what it is really doing (especially the line
AuxPlot.linkedViewChanged(MainPlot.getPlotItem().vb, AuxPlot.YAxis)
I then tried to manually set the viewed range by calculating the upper x axis range from the currently displayed lower x axis. This gives me synchronized zooming/panning but now there is a small offset between the two x axes (I think because there are in principle two datasets being displayed). Here is that code using manual setting the range of the upper x axis:
# -*- coding: utf-8 -*-
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
pg.mkQApp()
MainPlot = pg.PlotWidget()
MainPlot.show()
MainPlot.setWindowTitle('Dual x axis example, synchronized zoom on different axes')
AuxPlot = pg.ViewBox()
Shift = 1
#AuxPlot.setXLink(MainPlot) #this line will cause the two x axes to display the same range which is not wanted in this example
AuxPlot.setYLink(MainPlot) #this will synchronize zooming along the y axis
MainPlot.showAxis('top')
MainPlot.scene().addItem(AuxPlot)
AuxPlot.setGeometry(MainPlot.getPlotItem().vb.sceneBoundingRect())
MainPlot.getAxis('top').linkToView(AuxPlot)
##plot data
MainPlot.plot([0,1,2,3],[0,1,2,3], pen="w")
AuxPlot.addItem(pg.PlotCurveItem([-1,0,1,2],[0,1,2,3], pen="b")) #this data is scaled differently along the x axis while y is the same as in MainPlot
## This commented section was taken from another user's example but
##only one x axis zooms while the other is unaffected; modified to
##manually set XRange; doesnt work as both x axes are not aligned correctly
def updateViews():
## view has resized; update auxiliary views to match
global MainPlot, AuxPlot
AuxPlot.setGeometry(MainPlot.getPlotItem().vb.sceneBoundingRect())
## need to re-update linked axes since this was called
## incorrectly while views had different shapes.
## (probably this should be handled in ViewBox.resizeEvent)
AuxPlot.linkedViewChanged(MainPlot.getPlotItem().vb, AuxPlot.YAxis)
MainPlotXMin, MainPlotXMax = MainPlot.viewRange()[0]
AuxPlotXMin = (MainPlotXMin)-Shift
AuxPlotXMax = (MainPlotXMax)-Shift
AuxPlot.setRange(xRange=[AuxPlotXMin,AuxPlotXMax])
print("MainPlotXMin: ",MainPlotXMin)
print("(MainPlotXMin)-Shift: ",(MainPlotXMin)-Shift)
updateViews()
MainPlot.getPlotItem().sigRangeChanged.connect(updateViews)
##end of other user's example (modified)
## 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_()
What is the correct way of displaying two x axes which represent the same single curve in two different "units" in one plot? I am new to this and can't get my head around all the different objects (PlotItem, ViewBox etc...). Is there a simple way like telling pyqtgraph to plot one dataset and then give it scaling factors describing the mapping to the second x axis?
Thanks for your help and time, Chris