Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 37ff5a5

Browse files
committed
WIP: Add offset norm
1 parent df3530d commit 37ff5a5

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

lib/matplotlib/colors.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,80 @@ def scaled(self):
969969
return (self.vmin is not None and self.vmax is not None)
970970

971971

972+
class OffsetNorm(Normalize):
973+
def __init__(self, vmin=None, vcenter=None, vmax=None, clip=False):
974+
self.vmin = vmin
975+
self.vcenter = vcenter
976+
self.vmax = vmax
977+
self.clip = clip
978+
979+
def __call__(self, value, clip=False):
980+
if clip is None:
981+
clip = self.clip
982+
983+
result, is_scalar = self.process_value(value)
984+
985+
self.autoscale_None(result)
986+
vmin, vcenter, vmax = self.vmin, self.vcenter, self.vmax
987+
if vmin == vmax == vcenter:
988+
result.fill(0)
989+
elif not vmin <= vcenter <= vmax:
990+
raise ValueError("minvalue must be less than or equal to "
991+
"centervalue which must be less than or "
992+
"equal to maxvalue")
993+
else:
994+
vmin = float(vmin)
995+
vcenter = float(vcenter)
996+
vmax = float(vmax)
997+
if clip:
998+
mask = ma.getmask(result)
999+
result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
1000+
mask=mask)
1001+
1002+
resdat = result.data
1003+
lower = resdat[resdat < vcenter]
1004+
upper = resdat[resdat >= vcenter]
1005+
1006+
lower -= vmin
1007+
lower /= ((vcenter-vmin) * 2)
1008+
1009+
upper -= vcenter
1010+
upper /= ((vmax-vcenter) * 2)
1011+
upper += 0.5
1012+
1013+
resdat = np.hstack([lower, upper])
1014+
1015+
result = np.ma.array(resdat, mask=result.mask, copy=False)
1016+
1017+
if is_scalar:
1018+
result = result[0]
1019+
1020+
return result
1021+
1022+
def inverse(self, value):
1023+
midpoint = 0.5
1024+
if not self.scaled():
1025+
raise ValueError("Not invertible until scaled")
1026+
1027+
vmin = float(self.vmin)
1028+
vcenter = float(self.vcenter)
1029+
vmax = float(self.vmax)
1030+
1031+
if cbook.iterable(value):
1032+
val = ma.asarray(value)
1033+
else:
1034+
val = ma.asarray([value])
1035+
1036+
lower = vmin + val[val <= midpoint] * (2 * (vcenter - vmin))
1037+
upper = vcenter + val[val > midpoint] * (2 * (vmax - vcenter)) - vmax
1038+
1039+
inverted = np.hstack([lower, upper])
1040+
if cbook.iterable(value):
1041+
return inverted
1042+
else:
1043+
return inverted[0]
1044+
1045+
9721046
class LogNorm(Normalize):
9731047
"""
9741048
Normalize a given value to the 0-1 range on a log scale

lib/matplotlib/tests/test_colors.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,34 @@ def test_Normalize():
8080
_mask_tester(norm, vals)
8181

8282

83+
class _base_NormMixin(object):
84+
def test_call(self):
85+
normed_vals = self.norm(self.vals)
86+
assert_array_almost_equal(normed_vals, self.expected)
87+
88+
def test_inverse(self):
89+
_inverse_tester(self.norm, self.vals)
90+
91+
def test_scalar(self):
92+
_scalar_tester(self.norm, self.vals)
93+
94+
def test_mask(self):
95+
_mask_tester(self.norm, self.vals)
96+
97+
98+
class test_OffsetNorm_Even(_base_NormMixin):
99+
def setup(self):
100+
self.norm = mcolors.OffsetNorm(vmin=-1, vcenter=0, vmax=4)
101+
self.vals = np.array([-1, -0.5, 0.0, 1.0, 2.0, 3.0, 4.0])
102+
self.expected = np.array([0.0, 0.25, 0.5, 0.625, 0.75, 0.875, 1.0])
103+
104+
class test_OffsetNorm_Even(_base_NormMixin):
105+
def setup(self):
106+
self.norm = mcolors.OffsetNorm(vmin=-2, vcenter=0, vmax=5)
107+
self.vals = np.array([-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
108+
self.expected = np.array([0.0, 0.25, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
109+
110+
83111
def test_SymLogNorm():
84112
"""
85113
Test SymLogNorm behavior

0 commit comments

Comments
 (0)