Skip to content

Commit 6ceac0d

Browse files
authored
Merge pull request #10234 from aparamon/PowerNorm-offset-fix
PowerNorm: do not clip negative values
2 parents 85f0dd6 + 8fe256e commit 6ceac0d

File tree

2 files changed

+13
-20
lines changed

2 files changed

+13
-20
lines changed

lib/matplotlib/colors.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
from collections import Sized
4848
import itertools
4949
import re
50-
import warnings
5150

5251
import numpy as np
5352
import matplotlib.cbook as cbook
@@ -1170,8 +1169,8 @@ def autoscale_None(self, A):
11701169

11711170
class PowerNorm(Normalize):
11721171
"""
1173-
Normalize a given value to the ``[0, 1]`` interval with a power-law
1174-
scaling. This will clip any negative data points to 0.
1172+
Linearly map a given value to the 0-1 range and then apply
1173+
a power-law normalization over that range.
11751174
"""
11761175
def __init__(self, gamma, vmin=None, vmax=None, clip=False):
11771176
Normalize.__init__(self, vmin, vmax, clip)
@@ -1191,18 +1190,17 @@ def __call__(self, value, clip=None):
11911190
elif vmin == vmax:
11921191
result.fill(0)
11931192
else:
1194-
res_mask = result.data < 0
11951193
if clip:
11961194
mask = np.ma.getmask(result)
11971195
result = np.ma.array(np.clip(result.filled(vmax), vmin, vmax),
11981196
mask=mask)
11991197
resdat = result.data
12001198
resdat -= vmin
1199+
resdat[resdat < 0] = 0
12011200
np.power(resdat, gamma, resdat)
12021201
resdat /= (vmax - vmin) ** gamma
12031202

12041203
result = np.ma.array(resdat, mask=result.mask, copy=False)
1205-
result[res_mask] = 0
12061204
if is_scalar:
12071205
result = result[0]
12081206
return result
@@ -1224,21 +1222,13 @@ def autoscale(self, A):
12241222
Set *vmin*, *vmax* to min, max of *A*.
12251223
"""
12261224
self.vmin = np.ma.min(A)
1227-
if self.vmin < 0:
1228-
self.vmin = 0
1229-
warnings.warn("Power-law scaling on negative values is "
1230-
"ill-defined, clamping to 0.")
12311225
self.vmax = np.ma.max(A)
12321226

12331227
def autoscale_None(self, A):
12341228
"""autoscale only None-valued vmin or vmax."""
12351229
A = np.asanyarray(A)
12361230
if self.vmin is None and A.size:
12371231
self.vmin = A.min()
1238-
if self.vmin < 0:
1239-
self.vmin = 0
1240-
warnings.warn("Power-law scaling on negative values is "
1241-
"ill-defined, clamping to 0.")
12421232
if self.vmax is None and A.size:
12431233
self.vmax = A.max()
12441234

lib/matplotlib/tests/test_colors.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ def test_PowerNorm():
186186
assert pnorm(a[-1], clip=True) == expected[-1]
187187

188188

189+
def test_PowerNorm_translation_invariance():
190+
a = np.array([0, 1/2, 1], dtype=float)
191+
expected = [0, 1/8, 1]
192+
pnorm = mcolors.PowerNorm(vmin=0, vmax=1, gamma=3)
193+
assert_array_almost_equal(pnorm(a), expected)
194+
pnorm = mcolors.PowerNorm(vmin=-2, vmax=-1, gamma=3)
195+
assert_array_almost_equal(pnorm(a - 2), expected)
196+
197+
189198
def test_Normalize():
190199
norm = mcolors.Normalize()
191200
vals = np.arange(-10, 10, 1, dtype=float)
@@ -697,13 +706,7 @@ def __add__(self, other):
697706
fig, ax = plt.subplots()
698707
ax.imshow(mydata, norm=norm)
699708
fig.canvas.draw()
700-
if isinstance(norm, mcolors.PowerNorm):
701-
assert len(recwarn) == 1
702-
warn = recwarn.pop(UserWarning)
703-
assert ('Power-law scaling on negative values is ill-defined'
704-
in str(warn.message))
705-
else:
706-
assert len(recwarn) == 0
709+
assert len(recwarn) == 0
707710
recwarn.clear()
708711

709712

0 commit comments

Comments
 (0)