False colour image without colour interpolation (i.e., discrete instead continuous)?

25 views
Skip to first unread message

Edward Baudrez

unread,
Apr 10, 2023, 6:06:56 AM4/10/23
to pyqtgraph
Hello,

Is it possible to apply a colour map to an image without interpolation between the colours? Sort of a discrete colour map?


Kind regards
Edward

Patrick

unread,
Apr 11, 2023, 5:27:09 AM4/11/23
to pyqtgraph
Hi,

I think the colormaps are always interpolated. If you run the pyqtgraph Color Maps example you'll see even the discrete maps imported from matplotlib get interpolated.
It might be possible to define your own colormap with two stops at the same location. It might break, but it might also work...
I've hard coded in my own colormaps before using something like:

#...
self.cbar = pg.HistogramLUTItem(self.overview_composite_image)
self.cbar.gradient.restoreState({"mode": "rgb",
    "ticks": [(0.00, (0, 0, 0)),
              (0.25, (0, 0, 128)),
              (0.50, (144, 0 , 0)),
              (0.85, (224, 224, 0)),
              (1.00, (255, 255, 255))]})
#...

So you could try putting two stops for each colour something like:

self.cbar.gradient.restoreState({"mode": "rgb",
    "ticks": [(0.00, (0, 0, 0)),
              (0.25, (0, 0, 0)),
              (0.25, (0, 0, 128)),
              (0.50, (0, 0, 128)),
              (0.50, (144, 0 , 0)),
              (0.85, (144, 0, 0)),
              (0.85, (255, 255, 255)),
              (1.00, (255, 255, 255))]})
#...

It's possible you may need to make the next range start at 0.25000001 etc if things break because of divide-by-zero errors.

The "proper" way to do it would be to write a ColorMap subclass DiscreteColorMap or similar that handles the functionality.

Patrick

Edward Baudrez

unread,
Apr 12, 2023, 6:11:42 AM4/12/23
to pyqtgraph
Hello Patrick, fantastic tip, thank you!
I went to work with your suggestion and came up with the following (in case it's useful for anyone). I admit it's kind of a workaround, but for now it does what I want :)

import numpy as np
import pyqtgraph as pg

def interp0(x, xp, yp):
    """Zeroth-order hold interpolation with same (base) signature as numpy.interp."""
    def f(x0):
        if x0 <= xp[0]: return yp[0]
        if x0 >= xp[-1]: return yp[-1]
        k = 0
        while x0 > xp[k]: k += 1
        return yp[k - 1]
    return np.asarray([f(x) for x in x])

class DiscreteColorMap(pg.ColorMap):
    def map(self, data, mode = pg.ColorMap.BYTE):
        data = interp0(data, self.pos, self.pos)
        return super().map(data, mode)

I'm taking my first steps with Python, though, so suggestions for improvements welcome!

Kind regards
Edward
Reply all
Reply to author
Forward
0 new messages