ColorMap: keep RGBA values as uint8, clean up docstrings (#1722)

* keep RGBA values as uint8, clean up docstrings

* ColorMap docstring correction

* enum mapping fix 2
This commit is contained in:
Nils Nemitz 2021-04-20 15:03:44 +09:00 committed by GitHub
parent c62e51f4d8
commit a6f9a2be12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 48 deletions

View File

@ -1,9 +1,9 @@
import numpy as np import numpy as np
from .Qt import QtGui, QtCore from .Qt import QtGui, QtCore
from .python2_3 import basestring
from .functions import mkColor, eq from .functions import mkColor, eq
from os import path, listdir from os import path, listdir
from collections.abc import Callable, Sequence from collections.abc import Callable, Sequence
import warnings
_mapCache = {} _mapCache = {}
@ -193,16 +193,11 @@ class ColorMap(object):
| 1.0 -> white | 1.0 -> white
The colors for intermediate values are determined by interpolating between The colors for intermediate values are determined by interpolating between
the two nearest colors in either RGB or HSV color space. the two nearest colors in RGB color space.
To provide user-defined color mappings, see :class:`GradientWidget <pyqtgraph.GradientWidget>`. To provide user-defined color mappings, see :class:`GradientWidget <pyqtgraph.GradientWidget>`.
""" """
## color interpolation modes
RGB = 1
HSV_POS = 2
HSV_NEG = 3
## mapping modes ## mapping modes
CLIP = 1 CLIP = 1
REPEAT = 2 REPEAT = 2
@ -215,59 +210,52 @@ class ColorMap(object):
QCOLOR = 3 QCOLOR = 3
enumMap = { enumMap = {
'rgb': RGB, 'clip': CLIP,
# 'hsv+': HSV_POS, 'repeat': REPEAT,
# 'hsv-': HSV_NEG, 'mirror': MIRROR,
# 'clip': CLIP, 'diverging': DIVERGING,
# 'repeat': REPEAT,
'byte': BYTE, 'byte': BYTE,
'float': FLOAT, 'float': FLOAT,
'qcolor': QCOLOR, 'qcolor': QCOLOR,
} }
def __init__(self, pos, color, mode=None, mapping=None): #, names=None): def __init__(self, pos, color, mapping=CLIP, mode=None): #, names=None):
""" """
=============== ================================================================= =============== =======================================================================
**Arguments:** **Arguments:**
pos Array of positions where each color is defined pos Array of positions where each color is defined
color Array of colors. color Array of colors.
Values are interpreted via Values are interpreted via
:func:`mkColor() <pyqtgraph.mkColor>`. :func:`mkColor() <pyqtgraph.mkColor>`.
mode Array of color modes (ColorMap.RGB, HSV_POS, or HSV_NEG) mapping Mapping mode (ColorMap.CLIP, REPEAT, MIRROR or DIVERGING)
indicating the color space that should be used when controlling mapping of relative index to color. String representations
interpolating between stops. Note that the last mode value is 'clip', 'repeat', 'mirror' or 'diverging' are also accepted.
ignored. By default, the mode is entirely RGB. CLIP maps colors to [0.0;1.0] and is the default.
mapping Mapping mode (ColorMap.CLIP, REPEAT, MIRROR, or DIVERGING)
controlling mapping of relative index to color.
CLIP maps colors to [0.0;1.0]
REPEAT maps colors to repeating intervals [0.0;1.0];[1.0-2.0],... REPEAT maps colors to repeating intervals [0.0;1.0];[1.0-2.0],...
MIRROR maps colors to [0.0;-1.0] and [0.0;+1.0] identically MIRROR maps colors to [0.0;-1.0] and [0.0;+1.0] identically
DIVERGING maps colors to [-1.0;+1.0] DIVERGING maps colors to [-1.0;+1.0]
=============== ================================================================= =============== =======================================================================
""" """
if mode is not None:
warnings.warn(
"'mode' argument is deprecated and does nothing.",
DeprecationWarning, stacklevel=2
)
if isinstance(mapping, str):
mapping = self.enumMap[mapping.lower()]
self.pos = np.array(pos) self.pos = np.array(pos)
order = np.argsort(self.pos) order = np.argsort(self.pos)
self.pos = self.pos[order] self.pos = self.pos[order]
self.color = np.apply_along_axis( self.color = np.apply_along_axis(
func1d = lambda x: mkColor(x).getRgb(), func1d = lambda x: np.uint8( mkColor(x).getRgb() ), # cast RGB integer values to uint8
axis = -1, axis = -1,
arr = color, arr = color,
)[order] )[order]
if mode is None:
mode = np.ones(len(pos))
self.mode = mode
if mapping is None:
self.mapping_mode = self.CLIP
elif mapping == self.REPEAT:
self.mapping_mode = self.REPEAT
elif mapping == self.DIVERGING:
self.mapping_mode = self.DIVERGING
elif mapping == self.MIRROR:
self.mapping_mode = self.MIRROR
else:
self.mapping_mode = self.CLIP
self.mapping_mode = self.CLIP # default to CLIP mode
if mapping in [self.CLIP, self.REPEAT, self.DIVERGING, self.MIRROR]:
self.mapping_mode = mapping # only allow defined values
self.stopsCache = {} self.stopsCache = {}
def __getitem__(self, key): def __getitem__(self, key):
@ -281,7 +269,7 @@ class ColorMap(object):
except ValueError: pass except ValueError: pass
return None return None
def map(self, data, mode='byte'): def map(self, data, mode=BYTE):
""" """
Return an array of colors corresponding to the values in *data*. Return an array of colors corresponding to the values in *data*.
Data must be either a scalar position or an array (any shape) of positions. Data must be either a scalar position or an array (any shape) of positions.
@ -294,7 +282,7 @@ class ColorMap(object):
qcolor Values are returned as an array of QColor objects. qcolor Values are returned as an array of QColor objects.
=========== =============================================================== =========== ===============================================================
""" """
if isinstance(mode, basestring): if isinstance(mode, str):
mode = self.enumMap[mode.lower()] mode = self.enumMap[mode.lower()]
if mode == self.QCOLOR: if mode == self.QCOLOR:
@ -302,9 +290,6 @@ class ColorMap(object):
else: else:
pos, color = self.getStops(mode) pos, color = self.getStops(mode)
# Interpolate
# TODO: is griddata faster?
# interp = scipy.interpolate.griddata(pos, color, data)
if np.isscalar(data): if np.isscalar(data):
interp = np.empty((color.shape[1],), dtype=color.dtype) interp = np.empty((color.shape[1],), dtype=color.dtype)
else: else:
@ -364,7 +349,7 @@ class ColorMap(object):
def getColors(self, mode=None): def getColors(self, mode=None):
"""Return list of all color stops converted to the specified mode. """Return list of all color stops converted to the specified mode.
If mode is None, then no conversion is done.""" If mode is None, then no conversion is done."""
if isinstance(mode, basestring): if isinstance(mode, str):
mode = self.enumMap[mode.lower()] mode = self.enumMap[mode.lower()]
color = self.color color = self.color
@ -386,8 +371,6 @@ class ColorMap(object):
color = (color*255).astype(np.ubyte) color = (color*255).astype(np.ubyte)
elif mode == self.FLOAT and color.dtype.kind != 'f': elif mode == self.FLOAT and color.dtype.kind != 'f':
color = color.astype(float) / 255. color = color.astype(float) / 255.
## to support HSV mode, we need to do a little more work..
self.stopsCache[mode] = (self.pos, color) self.stopsCache[mode] = (self.pos, color)
return self.stopsCache[mode] return self.stopsCache[mode]
@ -406,7 +389,7 @@ class ColorMap(object):
See :func:`map() <pyqtgraph.ColorMap.map>`. See :func:`map() <pyqtgraph.ColorMap.map>`.
=============== ============================================================================= =============== =============================================================================
""" """
if isinstance(mode, basestring): if isinstance(mode, str):
mode = self.enumMap[mode.lower()] mode = self.enumMap[mode.lower()]
if alpha is None: if alpha is None:

View File

@ -93,7 +93,7 @@ def test_NonUniformImage_colormap():
image = NonUniformImage(x, y, Z, border=fn.mkPen('g')) image = NonUniformImage(x, y, Z, border=fn.mkPen('g'))
cmap = ColorMap(pos=[0.0, 1.0], color=[(0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0)], mode='rgb') cmap = ColorMap(pos=[0.0, 1.0], color=[(0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0)])
image.setColorMap(cmap) image.setColorMap(cmap)
viewbox.addItem(image) viewbox.addItem(image)