Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

VectorMappable with data type objects #28428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
Loading
from
4 changes: 4 additions & 0 deletions 4 lib/matplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
"interactive",
"is_interactive",
"colormaps",
"multivar_colormaps",
"bivar_colormaps",
"color_sequences",
]

Expand Down Expand Up @@ -1513,4 +1515,6 @@ def inner(ax, *args, data=None, **kwargs):
# workaround: we must defer colormaps import to after loading rcParams, because
# colormap creation depends on rcParams
from matplotlib.cm import _colormaps as colormaps # noqa: E402
from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402
from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402
from matplotlib.colors import _color_sequences as color_sequences # noqa: E402
2 changes: 2 additions & 0 deletions 2 lib/matplotlib/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,6 @@ def _preprocess_data(
) -> Callable: ...

from matplotlib.cm import _colormaps as colormaps # noqa: E402
from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402
from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402
from matplotlib.colors import _color_sequences as color_sequences # noqa: E402
1,312 changes: 1,312 additions & 0 deletions 1,312 lib/matplotlib/_cm_bivar.py

Large diffs are not rendered by default.

166 changes: 166 additions & 0 deletions 166 lib/matplotlib/_cm_multivar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# auto-genreated by https://github.com/trygvrad/multivariate_colormaps
# date: 2024-05-28

from .colors import LinearSegmentedColormap, MultivarColormap
import matplotlib as mpl
_LUTSIZE = mpl.rcParams['image.lut']

_2VarAddA0_data = [[0.000, 0.000, 0.000],
[0.020, 0.026, 0.031],
[0.049, 0.068, 0.085],
[0.075, 0.107, 0.135],
[0.097, 0.144, 0.183],
[0.116, 0.178, 0.231],
[0.133, 0.212, 0.279],
[0.148, 0.244, 0.326],
[0.161, 0.276, 0.374],
[0.173, 0.308, 0.422],
[0.182, 0.339, 0.471],
[0.190, 0.370, 0.521],
[0.197, 0.400, 0.572],
[0.201, 0.431, 0.623],
[0.204, 0.461, 0.675],
[0.204, 0.491, 0.728],
[0.202, 0.520, 0.783],
[0.197, 0.549, 0.838],
[0.187, 0.577, 0.895]]

_2VarAddA1_data = [[0.000, 0.000, 0.000],
[0.030, 0.023, 0.018],
[0.079, 0.060, 0.043],
[0.125, 0.093, 0.065],
[0.170, 0.123, 0.083],
[0.213, 0.151, 0.098],
[0.255, 0.177, 0.110],
[0.298, 0.202, 0.120],
[0.341, 0.226, 0.128],
[0.384, 0.249, 0.134],
[0.427, 0.271, 0.138],
[0.472, 0.292, 0.141],
[0.517, 0.313, 0.142],
[0.563, 0.333, 0.141],
[0.610, 0.353, 0.139],
[0.658, 0.372, 0.134],
[0.708, 0.390, 0.127],
[0.759, 0.407, 0.118],
[0.813, 0.423, 0.105]]

_2VarSubA0_data = [[1.000, 1.000, 1.000],
[0.959, 0.973, 0.986],
[0.916, 0.948, 0.974],
[0.874, 0.923, 0.965],
[0.832, 0.899, 0.956],
[0.790, 0.875, 0.948],
[0.748, 0.852, 0.940],
[0.707, 0.829, 0.934],
[0.665, 0.806, 0.927],
[0.624, 0.784, 0.921],
[0.583, 0.762, 0.916],
[0.541, 0.740, 0.910],
[0.500, 0.718, 0.905],
[0.457, 0.697, 0.901],
[0.414, 0.675, 0.896],
[0.369, 0.652, 0.892],
[0.320, 0.629, 0.888],
[0.266, 0.604, 0.884],
[0.199, 0.574, 0.881]]

_2VarSubA1_data = [[1.000, 1.000, 1.000],
[0.982, 0.967, 0.955],
[0.966, 0.935, 0.908],
[0.951, 0.902, 0.860],
[0.937, 0.870, 0.813],
[0.923, 0.838, 0.765],
[0.910, 0.807, 0.718],
[0.898, 0.776, 0.671],
[0.886, 0.745, 0.624],
[0.874, 0.714, 0.577],
[0.862, 0.683, 0.530],
[0.851, 0.653, 0.483],
[0.841, 0.622, 0.435],
[0.831, 0.592, 0.388],
[0.822, 0.561, 0.340],
[0.813, 0.530, 0.290],
[0.806, 0.498, 0.239],
[0.802, 0.464, 0.184],
[0.801, 0.426, 0.119]]

_3VarAddA0_data = [[0.000, 0.000, 0.000],
[0.018, 0.023, 0.028],
[0.040, 0.056, 0.071],
[0.059, 0.087, 0.110],
[0.074, 0.114, 0.147],
[0.086, 0.139, 0.183],
[0.095, 0.163, 0.219],
[0.101, 0.187, 0.255],
[0.105, 0.209, 0.290],
[0.107, 0.230, 0.326],
[0.105, 0.251, 0.362],
[0.101, 0.271, 0.398],
[0.091, 0.291, 0.434],
[0.075, 0.309, 0.471],
[0.046, 0.325, 0.507],
[0.021, 0.341, 0.546],
[0.021, 0.363, 0.584],
[0.022, 0.385, 0.622],
[0.023, 0.408, 0.661]]

_3VarAddA1_data = [[0.000, 0.000, 0.000],
[0.020, 0.024, 0.016],
[0.047, 0.058, 0.034],
[0.072, 0.088, 0.048],
[0.093, 0.116, 0.059],
[0.113, 0.142, 0.067],
[0.131, 0.167, 0.071],
[0.149, 0.190, 0.074],
[0.166, 0.213, 0.074],
[0.182, 0.235, 0.072],
[0.198, 0.256, 0.068],
[0.215, 0.276, 0.061],
[0.232, 0.296, 0.051],
[0.249, 0.314, 0.037],
[0.270, 0.330, 0.018],
[0.288, 0.347, 0.000],
[0.302, 0.369, 0.000],
[0.315, 0.391, 0.000],
[0.328, 0.414, 0.000]]

_3VarAddA2_data = [[0.000, 0.000, 0.000],
[0.029, 0.020, 0.023],
[0.072, 0.045, 0.055],
[0.111, 0.067, 0.084],
[0.148, 0.085, 0.109],
[0.184, 0.101, 0.133],
[0.219, 0.115, 0.155],
[0.254, 0.127, 0.176],
[0.289, 0.138, 0.195],
[0.323, 0.147, 0.214],
[0.358, 0.155, 0.232],
[0.393, 0.161, 0.250],
[0.429, 0.166, 0.267],
[0.467, 0.169, 0.283],
[0.507, 0.168, 0.298],
[0.546, 0.168, 0.313],
[0.580, 0.172, 0.328],
[0.615, 0.175, 0.341],
[0.649, 0.178, 0.355]]

cmaps = {
name: LinearSegmentedColormap.from_list(name, data, _LUTSIZE) for name, data in [
('2VarAddA0', _2VarAddA0_data),
('2VarAddA1', _2VarAddA1_data),
('2VarSubA0', _2VarSubA0_data),
('2VarSubA1', _2VarSubA1_data),
('3VarAddA0', _3VarAddA0_data),
('3VarAddA1', _3VarAddA1_data),
('3VarAddA2', _3VarAddA2_data),
]}

cmap_families = {
'2VarAddA': MultivarColormap([cmaps['2VarAddA' + str(i)] for i in range(2)],
'sRGB_add', name='2VarAddA'),
'2VarSubA': MultivarColormap([cmaps['2VarSubA' + str(i)] for i in range(2)],
'sRGB_sub', name='2VarSubA'),
'3VarAddA': MultivarColormap([cmaps['3VarAddA' + str(i)] for i in range(3)],
'sRGB_add', name='3VarAddA'),
}
157 changes: 129 additions & 28 deletions 157 lib/matplotlib/artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
import numpy as np

import matplotlib as mpl
from . import _api, cbook
from .colors import BoundaryNorm
from . import _api, cbook, cm
from .cm import ScalarMappable
from .path import Path
from .transforms import (BboxBase, Bbox, IdentityTransform, Transform, TransformedBbox,
Expand Down Expand Up @@ -1346,35 +1345,16 @@ def format_cursor_data(self, data):
--------
get_cursor_data
"""
if np.ndim(data) == 0 and isinstance(self, ScalarMappable):
if isinstance(self, ScalarMappable):
# Internal classes no longer inherit from ScalarMappable, and this
# block should never be executed by the internal API

# This block logically belongs to ScalarMappable, but can't be
# implemented in it because most ScalarMappable subclasses inherit
# from Artist first and from ScalarMappable second, so
# implemented in it in case custom ScalarMappable subclasses
# inherit from Artist first and from ScalarMappable second, so
# Artist.format_cursor_data would always have precedence over
# ScalarMappable.format_cursor_data.
n = self.cmap.N
if np.ma.getmask(data):
return "[]"
normed = self.norm(data)
if np.isfinite(normed):
if isinstance(self.norm, BoundaryNorm):
# not an invertible normalization mapping
cur_idx = np.argmin(np.abs(self.norm.boundaries - data))
neigh_idx = max(0, cur_idx - 1)
# use max diff to prevent delta == 0
delta = np.diff(
self.norm.boundaries[neigh_idx:cur_idx + 2]
).max()

else:
# Midpoints of neighboring color intervals.
neighbors = self.norm.inverse(
(int(normed * n) + np.array([0, 1])) / n)
delta = abs(neighbors - data).max()
g_sig_digits = cbook._g_sig_digits(data, delta)
else:
g_sig_digits = 3 # Consistent with default below.
return f"[{data:-#.{g_sig_digits}g}]"
return self.colorizer._format_cursor_data(data)
else:
try:
data[0]
Expand Down Expand Up @@ -1417,6 +1397,127 @@ def set_mouseover(self, mouseover):
mouseover = property(get_mouseover, set_mouseover) # backcompat.


class ColorizingArtist(Artist):
def __init__(self, norm=None, cmap=None):
"""
Parameters
----------
norm : `.Normalize` (or subclass thereof) or str or None
The normalizing object which scales data, typically into the
interval ``[0, 1]``.
If a `str`, a `.Normalize` subclass is dynamically generated based
on the scale with the corresponding name.
If *None*, *norm* defaults to a *colors.Normalize* object which
initializes its scaling based on the first data processed.
cmap : str or `~matplotlib.colors.Colormap`
The colormap used to map normalized data values to RGBA colors.
"""

Artist.__init__(self)

self._A = None
if isinstance(norm, cm.Colorizer):
self._colorizer = norm
else:
self._colorizer = cm.Colorizer(cmap, norm)

# self._id_colorizer = self.colorizer.callbacks.connect('changed', self.changed)
# self.callbacks = cbook.CallbackRegistry(signals=["changed"])

def set_array(self, A):
"""
Set the value array from array-like *A*.

Parameters
----------
A : array-like or None
The values that are mapped to colors.

The base class `.VectorMappable` does not make any assumptions on
the dimensionality and shape of the value array *A*.
"""
if A is None:
self._A = None
return
A = cm._ensure_multivariate_data(self.colorizer.cmap.n_variates, A)

A = cbook.safe_masked_invalid(A, copy=True)
if not np.can_cast(A.dtype, float, "same_kind"):
if A.dtype.fields is None:
raise TypeError(f"Image data of dtype {A.dtype} cannot be "
f"converted to float")
else:
for key in A.dtype.fields:
if not np.can_cast(A[key].dtype, float, "same_kind"):
raise TypeError(f"Image data of dtype {A.dtype} cannot be "
f"converted to a sequence of floats")
self._A = A
self.colorizer.autoscale_None(A)

def get_array(self):
"""
Return the array of values, that are mapped to colors.

The base class `.VectorMappable` does not make any assumptions on
the dimensionality and shape of the array.
"""
return self._A

@property
def colorizer(self):
return self._colorizer

@colorizer.setter
def colorizer(self, colorizer):
self._set_colorizer(colorizer)

def _set_colorizer(self, colorizer):
if isinstance(colorizer, cm.Colorizer):
if self._A is not None:
if not colorizer.cmap.n_variates == self.colorizer.cmap.n_variates:
raise ValueError('The new Colorizer object must have the same'
' number of variates as the existing data.')
else:
# self.colorizer.callbacks.disconnect(self._id_colorizer)
self._colorizer = colorizer
# self._id_colorizer = colorizer.callbacks.connect('changed',
# self.changed)
# self.changed()
else:
raise ValueError('Only a Colorizer object can be set to colorizer.')

def _get_colorizer(self):
"""
Function to get the colorizer.
Useful in edge cases where you want a standalone variable with the colorizer,
but also want the colorizer to update if the colorizer on the artist changes.

used in `contour.ContourLabeler.label_colorizer`
"""
return self._colorizer

'''
def changed(self):
"""
Call this whenever the mappable is changed to notify all the
callbackSM listeners to the 'changed' signal.
"""
self.callbacks.process('changed')
self.stale = True
'''
def format_cursor_data(self, data):
"""
Return a string representation of *data*.

Uses the colorbar's formatter to format the data.

See Also
--------
get_cursor_data
"""
return self.colorizer._format_cursor_data(data)


def _get_tightbbox_for_layout_only(obj, *args, **kwargs):
"""
Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.