Skip to content

Navigation Menu

Sign in
Appearance settings

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

Commit 27723ff

Browse filesBrowse files
committed
Further simplify colormap reversal.
Instead of implementing reversal of colormaps in the various formats in `_cm` and `_cm_listed`, we can just rely on Colormap.reversed() to do the job... `revcmap` was a public helper to a private function (`_reverse_cmap_spec`) so I'm not too worried with deprecating it. The private `_reverser` gets deprecated rather than deleted because `revcmap` depends on it. The `cmapname` toplevel variable used to leak out of the loop; I deleted it without deprecation or notice and moved cmap generation to a private function to avoid such leakage. The `datad` global now no longer contains "unconverted" entries for reversed cmaps (as not generating them is the whole point of the PR...); I'm not even sure it's worth an API note...
1 parent f51bf2b commit 27723ff
Copy full SHA for 27723ff

File tree

Expand file treeCollapse file tree

3 files changed

+33
-56
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+33
-56
lines changed
+7Lines 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

Copy file name to clipboardExpand all lines: lib/matplotlib/cm.py
+17-49Lines changed: 17 additions & 49 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,12 @@
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-
30+
@cbook.deprecated("3.2")
3931
def _reverser(f, x): # Toplevel helper for revcmap ensuring cmap picklability.
4032
return f(1 - x)
4133

4234

35+
@cbook.deprecated("3.2", alternative="Colormap.reversed()")
4336
def revcmap(data):
4437
"""Can only handle specification *data* in dictionary format."""
4538
data_r = {}
@@ -54,51 +47,26 @@ def revcmap(data):
5447
return data_r
5548

5649

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-
8850
LUTSIZE = mpl.rcParams['image.lut']
8951

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()})
9452

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)
53+
def _gen_cmap_d():
54+
cmap_d = {**cmaps_listed}
55+
for name, spec in datad.items():
56+
cmap_d[name] = ( # Precache the cmaps at a fixed lutsize..
57+
colors.LinearSegmentedColormap(name, spec, LUTSIZE)
58+
if 'red' in spec else
59+
colors.ListedColormap(spec['listed'], name)
60+
if 'listed' in spec else
61+
colors.LinearSegmentedColormap.from_list(name, spec, LUTSIZE))
62+
# Generate reversed cmaps.
63+
for cmap in list(cmap_d.values()):
64+
rmap = cmap.reversed()
65+
cmap_d[rmap.name] = rmap
66+
return cmap_d
9967

100-
cmap_d.update(cmaps_listed)
10168

69+
cmap_d = _gen_cmap_d()
10270
locals().update(cmap_d)
10371

10472

‎lib/matplotlib/colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/colors.py
+9-7Lines 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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.