8000 Merge pull request #14679 from anntzer/revcmap · matplotlib/matplotlib@8c587e5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8c587e5

Browse files
authored
Merge pull request #14679 from anntzer/revcmap
Further simplify colormap reversal.
2 parents 8d82733 + c2032ab commit 8c587e5

File tree

3 files changed

+40
-60
lines changed

3 files changed

+40
-60
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Deprecations
2+
````````````
3+
4+
``cm.revcmap`` is deprecated. Use `.Colormap.reversed` to reverse a colormap.
5+
6+
``cm.datad`` no longer contains entries for reversed colormaps in their
7+
"unconverted" form.

lib/matplotlib/cm.py

Lines changed: 24 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
1414
:doc:`/tutorials/colors/colormapnorms` for more details about data
1515
normalization.
16-
17-
1816
"""
1917

2018
import functools
@@ -29,17 +27,11 @@
2927
from matplotlib._cm_listed import cmaps as cmaps_listed
3028

3129

32-
cmap_d = {}
33-
34-
35-
# reverse all the colormaps.
36-
# reversed colormaps have '_r' appended to the name.
37-
38-
39-
def _reverser(f, x): # Toplevel helper for revcmap ensuring cmap picklability.
40-
return f(1 - x)
30+
def _reverser(f, x): # Deprecated, remove this at the same time as revcmap.
31+
return f(1 - x) # Toplevel helper for revcmap ensuring cmap picklability.
4132

4233

34+
@cbook.deprecated("3.2", alternative="Colormap.reversed()")
4335
def revcmap(data):
4436
"""Can only handle specification *data* in dictionary format."""
4537
data_r = {}
@@ -54,51 +46,30 @@ def revcmap(data):
5446
return data_r
5547

5648

57-
def _reverse_cmap_spec(spec):
58-
"""Reverses cmap specification *spec*, can handle both dict and tuple
59-
type specs."""
60-
61-
if 'listed' in spec:
62-
return {'listed': spec['listed'][::-1]}
63-
64-
if 'red' in spec:
65-
return revcmap(spec)
66-
else:
67-
revspec = list(reversed(spec))
68-
if len(revspec[0]) == 2: # e.g., (1, (1.0, 0.0, 1.0))
69-
revspec = [(1.0 - a, b) for a, b in revspec]
70-
return revspec
71-
72-
73-
def _generate_cmap(name, lutsize):
74-
"""Generates the requested cmap from its *name*. The lut size is
75-
*lutsize*."""
76-
77-
spec = datad[name]
78-
79-
# Generate the colormap object.
80-
if 'red' in spec:
81-
return colors.LinearSegmentedColormap(name, spec, lutsize)
82-
elif 'listed' in spec:
83-
return colors.ListedColormap(spec['listed'], name)
84-
else:
85-
return colors.LinearSegmentedColormap.from_list(name, spec, lutsize)
86-
87-
8849
LUTSIZE = mpl.rcParams['image.lut']
8950

90-
# Generate the reversed specifications (all at once, to avoid
91-
# modify-when-iterating).
92-
datad.update({cmapname + '_r': _reverse_cmap_spec(spec)
93-
for cmapname, spec in datad.items()})
94-
95-
# Precache the cmaps with ``lutsize = LUTSIZE``.
96-
# Also add the reversed ones added in the section above:
97-
for cmapname in datad:
98-
cmap_d[cmapname] = _generate_cmap(cmapname, LUTSIZE)
99-
100-
cmap_d.update(cmaps_listed)
10151

52+
def _gen_cmap_d():
53+
"""
54+
Generate a dict mapping standard colormap names to standard colormaps, as
55+
well as the reversed colormaps.
56+
"""
57+
cmap_d = {**cmaps_listed}
58+
for name, spec in datad.items():
59+
cmap_d[name] = ( # Precache the cmaps at a fixed lutsize..
60+
colors.LinearSegmentedColormap(name, spec, LUTSIZE)
61+
if 'red' in spec else
62+
colors.ListedColormap(spec['listed'], name)
63+
if 'listed' in spec else
64+
colors.LinearSegmentedColormap.from_list(name, spec, LUTSIZE))
65+
# Generate reversed cmaps.
66+
for cmap in list(cmap_d.values()):
67+
rmap = cmap.reversed()
68+
cmap_d[rmap.name] = rmap
69+
return cmap_d
70+
71+
72+
cmap_d = _gen_cmap_d()
10273
locals().update(cmap_d)
10374

10475

lib/matplotlib/colors.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"""
6161

6262
from collections.abc import Sized
63+
import functools
6364
import itertools
6465
import re
6566

@@ -795,6 +796,11 @@ def _resample(self, lutsize):
795796
"""
796797
return LinearSegmentedColormap(self.name, self._segmentdata, lutsize)
797798

799+
# Helper ensuring picklability of the reversed cmap.
800+
@staticmethod
801+
def _reverser(func, x):
802+
return func(1 - x)
803+
798804
def reversed(self, name=None):
799805
"""
800806
Make a reversed instance of the Colormap.
@@ -813,13 +819,9 @@ def reversed(self, name=None):
813819
if name is None:
814820
name = self.name + "_r"
815821

816-
# Function factory needed to deal with 'late binding' issue.
817-
def factory(dat):
818-
def func_r(x):
819-
return dat(1.0 - x)
820-
return func_r
821-
822-
data_r = {key: (factory(data) if callable(data) else
822+
# Using a partial object keeps the cmap picklable.
823+
data_r = {key: (functools.partial(self._reverser, data)
824+
if callable(data) else
823825
[(1.0 - x, y1, y0) for x, y0, y1 in reversed(data)])
824826
for key, data in self._segmentdata.items()}
825827

0 commit comments

Comments
 (0)
0