pyqtgraph: align the ticks of the x-axes in different plots - python

This is a follow up to this question.
The question is how to adapt the x-axis scaling of multiple pyqtgraphs when one of the graphs is rescaled. My desired result is that the ticks of all graphs align perfectly, so that you can directly compare the content of both graphs.
The given answer archives that task, of rescaling the graphs on changes but when the content of the graphs differs the y-Axis description tends to be of different size which somehow messes everything up.
For example in the image below I adjusted the bottom plot to roughly cover the 0-100 range. Strangely the upper plot is showing a bigger interval.
Any ideas how to align the ticks while rescaling?
Source code of the 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")
w1.plot(np.random.normal(size=100)*1e12)
w1.plotItem.showGrid(x=True,y=True,alpha=1)
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
w2.plotItem.showGrid(x=True,y=True,alpha=1)
d2.addWidget(w2)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
win.show()
sys.exit(app.exec_())

I just found the answer in this question.
Instead of connecting to the sigRangeChanged event we can directly link the axes scales by w2.setXLink(w1). Of course we have to remove the connections to sigRangeChanged or the scales will shoot to the sky. Here is the example code:
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
import sys
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")
w1.plot(np.random.normal(size=100)*1e12)
w1.plotItem.showGrid(x=True,y=True,alpha=1)
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
w2.plotItem.showGrid(x=True,y=True,alpha=1)
w2.setXLink(w1)
d2.addWidget(w2)
win.show()
sys.exit(app.exec_())

Related

How to create a floating window of selection tools for highlighting regions of a pyqtgraph?

I would like to add some selection tools to a pyqtgraph. The idea is that I would have a floating window on the graph that has for instance a rectangle or a circle tool. Then the user could place the shape on the graph and it would give me the coordinates of the area covered by the shape. Is this possible using pyqtgraph?
To get us started here is a minimal example of how to create a pyqtgraph.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import pyqtgraph as pg
import numpy as np
class Main():
x = np.arange(1000)
y = np.random.normal(size=(3, 1000))
plotWidget = pg.plot(title="Three plot curves")
r = pg.CircleROI((0.5, 0.5), (1, 1), radius=5)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
sys.exit(app.exec())

How to fix BarGraphItem height of a plot using PyQtgraph

How to fix BarGraphItem height when zoom in or zoom out pyqtgraph plot, it should be similar with axis font, the font size is in pixel, please someone helps, thank you very much, basic code as below:
import numpy as np
import pyqtgraph as pg
pg.setConfigOption('leftButtonPan', False)
win = pg.plot()
win.setWindowTitle('pyqtgraph example: BarGraphItem')
x = np.arange(10)
bg1 = pg.BarGraphItem(x=x, height=5, width=1,brush='r')
win.addItem(bg1)
win.setYRange(0,110)
win.setLimits(yMin=0,yMax=110,xMin=-0.5,xMax=11)
if name == 'main':
pg.exec()

Polar coordinate system in pyqtgraph

I need to implement two graphs in Cartesian and polar coordinates. Everything is clear with Cartesian, but is it possible to make a polar coordinate system in pyqtgraph?
pyqtgraph does not provide by default the ability to make polar plots, I have requested the feature through the issue #452, in that discussion it is indicated that you can create that type plot easily by giving an example here.
The example is as follows:
import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
plot = pg.plot()
plot.setAspectLocked()
# Add polar grid lines
plot.addLine(x=0, pen=0.2)
plot.addLine(y=0, pen=0.2)
for r in range(2, 20, 2):
circle = pg.QtGui.QGraphicsEllipseItem(-r, -r, r * 2, r * 2)
circle.setPen(pg.mkPen(0.2))
plot.addItem(circle)
# make polar data
theta = np.linspace(0, 2 * np.pi, 100)
radius = np.random.normal(loc=10, size=100)
# Transform to cartesian and plot
x = radius * np.cos(theta)
y = radius * np.sin(theta)
plot.plot(x, y)
if __name__ == "__main__":
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"):
QtGui.QApplication.instance().exec_()
Probably in future release pyqtgraph will offer that feature.
I can offer you to use the QPolarChart from PyQt5.QtChart. It's really easy. For example:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtChart import QPolarChart, QChartView, QValueAxis, QScatterSeries
self.polar = QPolarChart()
chartView = QChartView(self.polar)
layout = QVBoxLayout()
layout.addWidget(chartView)
#Let's create container widget for our chart, for example QFrame
#Instead the MainWindow you should to substitute your own Widget or Main Form
self.MyFrame = QtWidgets.QFrame(MainWindow)
self.MyFrame.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.MyFrame.setLayout(layout)
#setting axis
axisy = QValueAxis()
axisx = QValueAxis()
axisy.setRange(0,500)
axisy.setTickCount(4)
self.polar.setAxisY(axisy)
axisx.setRange(0,360)
axisx.setTickCount(5)
self.polar.setAxisX(axisx)
#Let's draw scatter series
self.polar_series = QScatterSeries()
self.polar_series.setMarkerSize(5.0)
self.polar_series.append(0, 0);
self.polar_series.append(360, 500);
#Why not draw archimedes spiral
for i in range(0,360,10):
self.polar_series.append(i, i)
self.polar.addSeries(self.polar_series)

Pyqtgraph interactivity and axis scale

Hi I am having trouble working out which functions I need to use with Pyqtgraph.
Pyqtgraph automatically computes the axis and rescales upon zooming, and this is fine. However I have two axes, frequency and hour. Frequency can take any value between 0-100 and hour can take any value between 0-39. How can I limit the axis to these upper/lower bounds so that when the user zooms or pans they cannot go outside of these values?
I wish to add functionality such that the user can draw a rectangle over a selection of lines and the graph will refresh such that the lines within the rectangle keep their respective colour and any lines outside turn grey?
How can I add another graph to the same window which shows a zoomed in view of the region selected by the rectangle in 2. ?
My code is as follows, and currently zooms on the drawing of a user defined rectangle over the lines, (for 3 lines, my actual code will plot a lot more):
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
from random import randint
class CustomViewBox(pg.ViewBox):
def __init__(self, *args, **kwds):
pg.ViewBox.__init__(self, *args, **kwds)
self.setMouseMode(self.RectMode)
## reimplement right-click to zoom out
def mouseClickEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
#self.autoRange()
self.setXRange(0,5)
self.setYRange(0,10)
def mouseDragEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
ev.ignore()
else:
pg.ViewBox.mouseDragEvent(self, ev)
app = pg.mkQApp()
vb = CustomViewBox()
graph = pg.PlotWidget(viewBox=vb, enableMenu=False)
colour = []
for i in range(0,3):
colourvalue = [randint(0,255), randint(0,255), randint(0,255)]
tuple(colourvalue)
colour.append(colourvalue)
y_data = [
[['a',0],['b',1],['c',None],['d',6],['e',7]],
[['a',5],['b',2],['c',1],['d',None],['e',1]],
[['a',3],['b',None],['c',4],['d',9],['e',None]],
]
x_data = [0, 1, 2, 3, 4]
for i in range(3):
xv = []
yv = []
for j, v in enumerate(row[i][1] for row in y_data):
if v is not None:
xv.append(int(j))
yv.append(float(v))
graph.plot(xv, yv, pen = colour[i], name=y_data[0][i][0])
graph.show()
graph.setWindowTitle('Hourly Frequency Graph')
graph.setXRange(0,5)
graph.setYRange(0,10)
graph.setLabel('left', "Frequency", units='%')
graph.setLabel('bottom', "Hour")
graph.showGrid(x=True, y=True)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Thanks in advance for any help and advice!
I would also like to know why this code always give a segmentation fault: 11 when I close the window.

pyqtgraph: add legend for lines in a plot

I'm using pyqtgraph and I'd like to add an item in the legend for InfiniteLines.
I've adapted the example code to demonstrate:
# -*- coding: utf-8 -*-
"""
Demonstrates basic use of LegendItem
"""
import initExample ## Add path to library (just for examples; you do not need this)
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
plt = pg.plot()
plt.setWindowTitle('pyqtgraph example: Legend')
plt.addLegend()
c1 = plt.plot([1,3,2,4], pen='r', name='red plot')
c2 = plt.plot([2,1,4,3], pen='g', fillLevel=0, fillBrush=(255,255,255,30), name='green plot')
c3 = plt.addLine(y=4, pen='y')
# TODO: add legend item indicating "maximum value"
## 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 I get as a result is:
How do I add an appropriate legend item?
pyqtgraph automatically adds an item to the legend if it is created with the "name" parameter. The only adjustment needed in the above code would be as follows:
c3 = plt.plot (y=4, pen='y', name="maximum value")
as soon as you provide pyqtgraph with a name for the curve it will create the according legend item by itself.
It is important though to call plt.addLegend() BEFORE you create the curves.
For this example, you can create an empty PlotDataItem with the correct color and add it to the legend like this:
style = pg.PlotDataItem(pen='y')
plt.plotItem.legend.addItem(l, "maximum value")

Categories

Resources