Matplotlib pcolor/pcolormesh equivalent

643 views
Skip to first unread message

Nicola Creati

unread,
Mar 17, 2016, 9:37:17 AM3/17/16
to pyqtgraph
Hello,
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 specify the (xy) coordinates of the colored quadrilaterals and C is the array of values. Can I get the same with PyQtGraph, please?
Thanks.

Nicola

Samuel Palato

unread,
Apr 19, 2016, 1:50:05 PM4/19/16
to pyqtgraph
Hi,

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 labels. See: 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 ImageItem is going to reside in:
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

Luke Carroll

unread,
Aug 15, 2018, 4:47:08 PM8/15/18
to pyqtgraph
Hey, 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


class IndexedAxis(pg.AxisItem):
    """
    Axis where pixels are mapped using a numpy array
    """
    def __init__(self, orientation, mapping=None, **kw):
        super(IndexedAxis, self).__init__(orientation, **kw)
        self.mapping = mapping
        self.fmt = "{:.02f}"

    def tickStrings(self, values, scale, spacing):
        if self.mapping is None:
            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)

Patrick

unread,
Aug 15, 2018, 10:56:07 PM8/15/18
to pyqtgraph
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
Reply all
Reply to author
Forward
Message has been deleted
0 new messages