@@ -1255,12 +1255,12 @@ def __call__(self, value, clip=None):
12551255 return result
12561256
12571257
1258- class SymNorm (Normalize ):
1259- def __init__ (self , vcenter = 0 , vmax = None , clip = False ):
1258+ class CenteredNorm (Normalize ):
1259+ def __init__ (self , vcenter = 0 , halfrange = None , clip = False ):
12601260 """
12611261 Normalize symmetrical data around a center (0 by default).
12621262
1263- Unlike `TwoSlopeNorm`, `SymNorm ` applies an equal rate of change
1263+ Unlike `TwoSlopeNorm`, `CenteredNorm ` applies an equal rate of change
12641264 around the center.
12651265
12661266 Useful when mapping symmetrical data around a conceptual center
@@ -1271,43 +1271,44 @@ def __init__(self, vcenter=0, vmax=None, clip=False):
12711271 ----------
12721272 vcenter : float, default: 0
12731273 The data value that defines ``0.5`` in the normalization.
1274- vmax : float, optional
1275- The data value that defines ``1.0 `` in the normalization.
1276- Defaults to the sum of *vcenter* plus the largest absolute
1277- difference to *vcenter* for the values in the dataset .
1278- If vmax is less than *vcenter*, it is automatically mirrored
1279- over the center .
1274+ halfrange : float, optional
1275+ The range of data values that defines a range of ``0.5 `` in the
1276+ normalization, so that *vcenter* - *halfrange* is ``0.0`` and
1277+ *vcenter* + *halfrange* is ``1.0`` in the normalization .
1278+ Defaults to the largest absolute difference to *vcenter* for
1279+ the values in the dataset .
12801280
12811281 Examples
12821282 --------
12831283 This maps data values -2 to 0.25, 0 to 0.5, and 4 to 1.0
12841284 (assuming equal rates of change above and below 0.0):
12851285
12861286 >>> import matplotlib.colors as mcolors
1287- >>> norm = mcolors.SymNorm(vmax =4.0)
1287+ >>> norm = mcolors.CenteredNorm(halfrange =4.0)
12881288 >>> data = [-2., 0., 4.]
12891289 >>> norm(data)
12901290 array([0.25, 0.5 , 1. ])
12911291 """
1292-
12931292 self ._vcenter = vcenter
1294- if vmax is None :
1295- self .vmin = None
1296- self .vmax = None
1297- else :
1298- self .vmax = vcenter + abs (vmax - vcenter )
1299- self .vmin = vcenter - vmax
1293+ self .halfrange = halfrange
13001294 self .clip = clip
13011295
1296+ def _set_vmin_vmax (self ):
1297+ """
1298+ Set *vmin* and *vmax* based on *vcenter* and *halfrange*.
1299+ """
1300+ self .vmax = self ._vcenter + self .halfrange
1301+ self .vmin = self ._vcenter - self .halfrange
1302+
13021303 def autoscale (self , A ):
13031304 """
1304- Set *vmax * to *vcenter* + max(abs(*A*-*vcenter*)),
1305- then set *vmin* by mirroring *vmax* at *vcenter *.
1305+ Set *halfrange * to max(abs(*A*-*vcenter*)),
1306+ then set *vmin* and *vmax*.
13061307 """
13071308 A = np .asanyarray (A )
1308- self .vmax = self . _vcenter + max (self ._vcenter - A .min (),
1309- A .max ()- self ._vcenter )
1310- self .vmin = 2 * self . _vcenter - self . vmax
1309+ self ._halfrange = max (self ._vcenter - A .min (),
1310+ A .max ()- self ._vcenter )
1311+ self ._set_vmin_vmax ()
13111312
13121313 def autoscale_None (self , A ):
13131314 """Set *vmin* and *vmax*."""
@@ -1323,16 +1324,29 @@ def vcenter(self):
13231324 def vcenter (self , vcenter ):
13241325 self ._vcenter = vcenter
13251326 if self .vmax is not None :
1326- # recompute vmax and vmin,assuming they represent
1327+ # recompute halfrange assuming vmin and vmax represent
13271328 # min and max of data
1328- self .vmax = self ._vcenter + max (self ._vcenter - self .vmin ,
1329- self .vmax - self ._vcenter )
1330- self .vmin = 2 * self ._vcenter - self .vmax
1329+ self ._halfrange = max (self ._vcenter - self .vmin ,
1330+ self .vmax - self ._vcenter )
1331+ self ._set_vmin_vmax ()
1332+
1333+ @property
1334+ def halfrange (self ):
1335+ return self ._halfrange
1336+
1337+ @halfrange .setter
1338+ def halfrange (self , halfrange ):
1339+ if halfrange is None :
1340+ self .vmin = None
1341+ self .vmax = None
1342+ else :
1343+ self .halfrange = abs (halfrange )
1344+ self ._set_vmin_vmax ()
13311345
13321346 def __call__ (self , value , clip = None ):
1333- if self .vmax is not None :
1334- # enforce symmetry, undo changes to vmin
1335- self .vmin = 2 * self . _vcenter - self . vmax
1347+ if self ._halfrange is not None :
1348+ # enforce symmetry, reset vmin and vmax
1349+ self ._set_vmin_vmax ()
13361350 return super ().__call__ (value , clip = clip )
13371351
13381352
0 commit comments