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 a3bfa93

Browse filesBrowse files
committed
ENH: Add func norm
1 parent 491e2a7 commit a3bfa93
Copy full SHA for a3bfa93

File tree

Expand file treeCollapse file tree

5 files changed

+89
-2
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+89
-2
lines changed

‎doc/api/colors_api.rst

Copy file name to clipboardExpand all lines: doc/api/colors_api.rst
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Classes
3030
PowerNorm
3131
SymLogNorm
3232
TwoSlopeNorm
33+
FuncNorm
3334

3435
Functions
3536
---------

‎examples/userdemo/colormap_normalizations.py

Copy file name to clipboardExpand all lines: examples/userdemo/colormap_normalizations.py
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
shading='nearest')
7878
fig.colorbar(pcm, ax=ax[1], extend='both')
7979

80-
8180
###############################################################################
8281
# Custom Norm: An example with a customized normalization. This one
8382
# uses the example above, and normalizes the negative data differently

‎lib/matplotlib/colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/colors.py
+33Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,39 @@ def inverse(self, value):
14671467
return Norm
14681468

14691469

1470+
@_make_norm_from_scale(
1471+
scale.FuncScale,
1472+
init=lambda functions, vmin=None, vmax=None, clip=False: None)
1473+
class FuncNorm(Normalize):
1474+
"""
1475+
Arbitrary normalization using functions for the forward and inverse.
1476+
1477+
Parameters
1478+
----------
1479+
functions : (callable, callable)
1480+
two-tuple of the forward and inverse functions for the normalization.
1481+
The forward function must be monotonic.
1482+
1483+
Both functions must have the signature ::
1484+
1485+
def forward(values: array-like) -> array-like
1486+
1487+
vmin, vmax : float or None
1488+
If *vmin* and/or *vmax* is not given, they are initialized from the
1489+
minimum and maximum value, respectively, of the first input
1490+
processed; i.e., ``__call__(A)`` calls ``autoscale_None(A)``.
1491+
1492+
clip : bool, default: False
1493+
If ``True`` values falling outside the range ``[vmin, vmax]``,
1494+
are mapped to 0 or 1, whichever is closer, and masked values are
1495+
set to 1. If ``False`` masked values remain masked.
1496+
1497+
Clipping silently defeats the purpose of setting the over, under,
1498+
and masked colors in a colormap, so it is likely to lead to
1499+
surprises; therefore the default is ``clip=False``.
1500+
"""
1501+
1502+
14701503
@_make_norm_from_scale(functools.partial(scale.LogScale, nonpositive="mask"))
14711504
class LogNorm(Normalize):
14721505
"""Normalize a given value to the 0-1 range on a log scale."""

‎lib/matplotlib/tests/test_colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_colors.py
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,29 @@ def test_Normalize():
537537
assert 0 < norm(1 + 50 * eps) < 1
538538

539539

540+
def test_FuncNorm():
541+
def forward(x):
542+
return (x**2)
543+
def inverse(x):
544+
return np.sqrt(x)
545+
546+
norm = mcolors.FuncNorm((forward, inverse), vmin=0, vmax=10)
547+
expected = np.array([0, 0.25, 1])
548+
input = np.array([0, 5, 10])
549+
assert_array_almost_equal(norm(input), expected)
550+
assert_array_almost_equal(norm.inverse(expected), input)
551+
552+
def forward(x):
553+
return np.log10(x)
554+
def inverse(x):
555+
return 10**x
556+
norm = mcolors.FuncNorm((forward, inverse), vmin=0.1, vmax=10)
557+
lognorm = mcolors.LogNorm(vmin=0.1, vmax=10)
558+
assert_array_almost_equal(norm([0.2, 5, 10]), lognorm([0.2, 5, 10]))
559+
assert_array_almost_equal(norm.inverse([0.2, 5, 10]),
560+
lognorm.inverse([0.2, 5, 10]))
561+
562+
540563
def test_TwoSlopeNorm_autoscale():
541564
norm = mcolors.TwoSlopeNorm(vcenter=20)
542565
norm.autoscale([10, 20, 30, 40])

‎tutorials/colors/colormapnorms.py

Copy file name to clipboardExpand all lines: tutorials/colors/colormapnorms.py
+32-1Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,16 @@
169169
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
170170
Z1 = (1 + np.sin(Y * 10.)) * X**2
171171

172-
fig, ax = plt.subplots(2, 1)
172+
fig, ax = plt.subplots(2, 1, constrained_layout=True)
173173

174174
pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=0.5),
175175
cmap='PuBu_r', shading='auto')
176176
fig.colorbar(pcm, ax=ax[0], extend='max')
177+
ax[0].set_title('PowerNorm()')
177178

178179
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r', shading='auto')
179180
fig.colorbar(pcm, ax=ax[1], extend='max')
181+
ax[1].set_title('Normalize()')
180182
plt.show()
181183

182184
###############################################################################
@@ -274,17 +276,45 @@
274276
# Simple geographic plot, set aspect ratio beecause distance between lines of
275277
# longitude depends on latitude.
276278
ax.set_aspect(1 / np.cos(np.deg2rad(49)))
279+
ax.set_title('TwoSlopeNorm(x)')
277280
fig.colorbar(pcm, shrink=0.6)
278281
plt.show()
279282

280283

284+
###############################################################################
285+
# FuncNorm: Arbitrary function normalization
286+
# ------------------------------------------
287+
#
288+
# If the above norms do not provide the normalization you want, you can use
289+
# `~.colors.FuncNorm` to define your own. Note that this example is the same
290+
# as `~.colors.PowerNorm` with a power of 0.5:
291+
292+
def _forward(x):
293+
return np.sqrt(x)
294+
295+
296+
def _inverse(x):
297+
return x**2
298+
299+
N = 100
300+
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
301+
Z1 = (1 + np.sin(Y * 10.)) * X**2
302+
fig, ax = plt.subplots()
303+
304+
norm = colors.FuncNorm((_forward, _inverse), vmin=0, vmax=20)
305+
pcm = ax.pcolormesh(X, Y, Z1, norm=norm, cmap='PuBu_r', shading='auto')
306+
ax.set_title('FuncNorm(x)')
307+
fig.colorbar(pcm, shrink=0.6)
308+
plt.show()
309+
281310
###############################################################################
282311
# Custom normalization: Manually implement two linear ranges
283312
# ----------------------------------------------------------
284313
#
285314
# The `.TwoSlopeNorm` described above makes a useful example for
286315
# defining your own norm.
287316

317+
288318
class MidpointNormalize(colors.Normalize):
289319
def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False):
290320
self.vcenter = vcenter
@@ -303,5 +333,6 @@ def __call__(self, value, clip=None):
303333
pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=midnorm,
304334
cmap=terrain_map, shading='auto')
305335
ax.set_aspect(1 / np.cos(np.deg2rad(49)))
336+
ax.set_title('Custom norm')
306337
fig.colorbar(pcm, shrink=0.6, extend='both')
307338
plt.show()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.