Hi,
Funnily enough I was looking for a pcolormesh equivalent in pyqtgraph just
the other day, and searching didn't come up with much except this old
thread (which is not a suitable solution for me -- my pixel sizes are
dramatically different sizes).
The way matplotlib does the pcolormesh is by creating a large number of
rectangular patches, each rectangle is the width/height of the pixel size,
with a face color mapped to the z value. The hundreds (thousands?!) of
patches are then placed on the plot axes. You can see this when exporting
to a vector graphic (SVG, PDF) versus a raster (PNG) -- the vector graphic
is larger file size and horribly slow to render!
The quick and dirty workaround for this is to simply interpolate the
irregularly spaced data onto a regular grid. I was going to try this first,
as it's pretty easy. The issue is that with drastically different sized
pixels, we need to choose an interpolation grid size. If we choose the
smallest increment, then the resulting image may be enormous (large memory
usage, possibly slow to pan/render). If we choose a larger pixel size, then
we will lose detail when zooming in to the regions where the pixels were
small.
Anyway, if you wanted to try this, look at the 2D interpolation routines
from scipy. Something like:
import numpy as np
from scipy import interpolate
# Generate some test data on an irregular grid
irreg_xlabels = np.array([0,1,3,7])
irreg_ylabels = np.array([0,2,5,9])
irreg_data = np.outer(irreg_xlabels, irreg_ylabels)
# Choose the finest step size as our new pixel size
# Will give best detail, but large image size!
step_x = np.ediff1d(irreg_xlabels).min()
step_y = np.ediff1d(irreg_ylabels).min()
# Function to generate interpolated values from our irregular grid
f = interpolate.RectBivariateSpline(irreg_xlabels, irreg_ylabels,
irreg_data)
# Generate new data on the regular grid
xlabels = np.arange(irreg_xlabels[0], irreg_xlabels[-1] + step_x, step_x)
ylabels = np.arange(irreg_ylabels[0], irreg_ylabels[-1] + step_y, step_y)
data = f(xlabels, ylabels)
then set the ImageItem data and translations/scale using the new, regular
grid offset and step size.
If memory use and performance is acceptable, then that should do it. If
not, then it would be possible to dynamically generate the new interpolated
image data when the range of the view changes. Then only get interpolated
values between the view range and at a resolution that matches the viewport
size.
Patrick
Post by Luke CarrollHey, I've tried replicating the suggestions but cant seem to get anything
to appear, I wrote the script below and ran it from the windows command
prompt using Python. I'm using numpy 1.14, pyqt 5.9 and pyqtgraph 0.10.
When I just use the code suggested by Samuel Palato nothing gets displayed
either. I've also tried running this in a jupyter notebook but to no avail.
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
"""
Axis where pixels are mapped using a numpy array
"""
super(IndexedAxis, self).__init__(orientation, **kw)
self.mapping = mapping
self.fmt = "{:.02f}"
return super(IndexedAxis, self).tickStrings(values, scale,
spacing)
# count values smaller than 0
labels = []
idx = np.array(values, dtype=np.int)-1
left_pad = np.count_nonzero(idx < 0)
right_pad = np.count_nonzero(idx >= self.mapping.size)
idx = np.compress(np.logical_and(idx>=0, idx< self.mapping.size),
idx)
labels.extend([""]*left_pad)
labels.extend([self.fmt.format(v) for v in self.mapping[idx]])
labels.extend([""]*right_pad)
return labels
app = QtGui.QApplication([])
mw = QtGui.QMainWindow
view = pg.GraphicsLayoutWidget()
w1 = view.addPlot()
x_values = np.linspace(-100, 100)
mapped_axis = IndexedAxis('bottom', mapping=x_values)
plot_item = pg.PlotItem(axisItems={'bottom': mapped_axis})
image_item =pg.ImageItem()
plot_item.addItem(image_item)
w1.addItem(plot_item)
Post by Samuel PalatoHi,
I managed to do something similar.
My data has x and y axes with almost constant spacing, so I'm ok with
even sized pixels on display. However, the x and y axes display custom
values, looked up from the corresponding arrays. This is a bit closer to
the behavior of `matplotlib.imshow` with the `extent` keyword.
The trick is to subclass `AxisItem` in order to display custom tick
https://bitbucket.org/snippets/spalato/X6nL4/indexed-axis#file-IndexedAxis.py
You then need to create the axis items and pass them to the PlotItem your
x_values = np.linspace(-100, 100, n=51)
mapped_axis = IndexedAxis('bottom', mapping=x_values)
plot_item = pg.PlotItem(axisItems={'bottom': mapped_axis})
image_item =pg.ImageItem()
plot_item.addItem(image_item)
Or something similar.
To update the axis values, you need to update the axis' `mapping`
attribute to the new values.
So far, this works, but I get an extra set of axes in the top right
corner. (which brought me here...)
If constant pixels are unacceptable, you could try creating a display
image using nearest interpolation, and plotting the resulting image using
the technique described above.
Hope this helps,
Samuel Palato
Post by Nicola CreatiHello,
I'm trying to move from Matplotlib to PyQtGraph but I need something
equivalent to the Matplotlib pcolormesh/pcolor command that accepts X, Y
and C as input. *X* and *Y *specify the (*x*, *y*) coordinates of the
colored quadrilaterals and C is the array of values. Can I get the same
with PyQtGraph, please?
Thanks.
Nicola
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/3117568c-fb25-4c31-9ca0-26629cd871ad%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.