How can I align an pyqtgraph IsocurveItem instance to empty plot axes (rather than an ImageItem)?


How can I align an pyqtgraph IsocurveItem instance to empty plot axes (rather than an ImageItem)?



The Problem



The pyqtgraph documentation for IsocurveItem helpfully suggests that contours drawn with this class can be aligned to an ImageItem instance by isocurve.setParentItem(image). But if I don't want to show image data, how can I scale the contour output to properly align with the axes given X,Y data?


ImageItem


isocurve.setParentItem(image)



Example setup



Using this code sample to draw:


from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
import sys

# Setup
app = QtGui.QApplication()
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')

win = pg.PlotWidget()
layout = pg.GraphicsLayout()
win.setCentralItem(layout)
ax = pg.PlotItem()
layout.addItem(ax)

# Generate data
x = np.linspace(0, 6.28, 30)
y = x[:]
xx, yy = np.meshgrid(x, y)
z = np.sin(xx) + np.cos(yy)

# Add data
ax.setXRange(x.min(), x.max())
ax.setYRange(y.min(), y.max())
c = pg.IsocurveItem(data=z, level=0.5, pen='r')
# c.setParentItem(ax) # This doesn't work
ax.addItem(c)

# Finish up
win.show()
sys.exit(app.exec_())



Which outputs this:



enter image description here



Or, without the setXRange and setYRange part, it looks like this:



enter image description here



I want the drawing from the second plot to be stretched to fit on the axes of the first one.
So, I think I just need to tell IsocurveItem how to squeeze and align itself given X, Y, Z data instead of just Z. How can I do that?



P.S. The equivalent* matplotlib contour call would be contour(x, y, z, levels=[0.5], colors='r').


contour(x, y, z, levels=[0.5], colors='r')



*Have to deal with axis order / row-major vs. col-major; no big deal.



Failed solutions



Add an ImageItem and scale it, then make it invisible later. Try to make the IsocurveItem scale as well by setting its parent to the ImageItem:


ImageItem


IsocurveItem


ImageItem


img = pg.ImageItem(z, axisOrder='row-major')
img.scale((x.max() - x.min()) / img.width(), (y.max() - y.min()) / img.height())
ax.addItem(img)
c.setParentItem(img)



The ImageItem scales, but the IsocurveItem doesn't come along for the ride.


ImageItem


IsocurveItem




1 Answer
1



IsocurveItem inherited .scale() and .translate() methods through GraphicsObject, of which it is a subclass. So, just add these lines to the example after defining c:


IsocurveItem


.scale()


.translate()


GraphicsObject


c


c.translate(x.min(), y.min())
c.scale((x.max() - x.min()) / np.shape(z)[0], (y.max() - y.min()) / np.shape(z)[1])



To make the test more rigorous, I also changed x so it doesn't start at 0:


x


x = np.linspace(10, 16.28, 30)



The output is now
enter image description here



It may be a little easier to visualize with an ImageItem in the mix (also translated and scaled):
enter image description here


ImageItem






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Export result set on Dbeaver to CSV

Opening a url is failing in Swift