@@ -1255,6 +1255,82 @@ def __call__(self, value, clip=None):
12551255 return result
12561256
12571257
1258+ class SymNorm (Normalize ):
1259+ def __init__ (self , vcenter = 0.0 , vmax = None , clip = False ):
1260+ """
1261+ Normalize symmetrical data around a center (0 by default).
1262+
1263+ Unlike `TwoSlopeNorm`, `SymNorm` applies an equal rate of change
1264+ around the center.
1265+
1266+ Useful when mapping symmetrical data around a conceptual center
1267+ e.g., data that range from -2 to 4, with 0 as the midpoint, and
1268+ with equal rates of change around that midpoint.
1269+
1270+ Parameters
1271+ ----------
1272+ vcenter : float, optional
1273+ The data value that defines ``0.5`` in the normalization.
1274+ Defaults to ``0.0``.
1275+ vmax : float, optional
1276+ The data value that defines ``1.0`` in the normalization.
1277+ Defaults to the sum of *vcenter* plus the largest absolute
1278+ difference to *vcenter* for the values in the dataset.
1279+ If vmax is less than *vcenter*, it is automatically mirrored
1280+ over the center.
1281+
1282+ Examples
1283+ --------
1284+ This maps data values -2 to 0.25, 0 to 0.5, and 4 to 1.0
1285+ (assuming equal rates of change above and below 0.0):
1286+
1287+ >>> import matplotlib.colors as mcolors
1288+ >>> norm = mcolors.SymNorm(vmax=4.0)
1289+ >>> data = [-2., 0., 4.]
1290+ >>> norm(data)
1291+ array([[0.25, 0.5 , 1. ])
1292+ """
1293+
1294+ self ._vcenter = vcenter
1295+ if vmax is None :
1296+ self .vmin = None
1297+ self .vmax = None
1298+ else :
1299+ self .vmax = vcenter + abs (vmax - vcenter )
1300+ self .vmin = vcenter - vmax
1301+ self .clip = clip
1302+
1303+ def autoscale (self , A ):
1304+ """
1305+ Set *vmax* to *vcenter* + max(abs(*A*-*vcenter*)),
1306+ then mirror *vmax* around *vcenter* to set *vmin*.
1307+ """
1308+ A = np .asanyarray (A )
1309+ self .vmax = self ._vcenter + max (self ._vcenter - A .min (),
1310+ A .max ()- self ._vcenter )
1311+ self .vmin = 2 * self ._vcenter - self .vmax
1312+
1313+ def autoscale_None (self , A ):
1314+ """Set *vmin* and *vmax*."""
1315+ A = np .asanyarray (A )
1316+ if self .vmax is None and A .size :
1317+ self .autoscale (A )
1318+
1319+ @property
1320+ def vcenter (self ):
1321+ return self ._vcenter
1322+
1323+ @vcenter .setter
1324+ def vcenter (self , vcenter ):
1325+ self ._vcenter = vcenter
1326+ if self .vmax is not None :
1327+ # recompute vmax and vmin,assuming they represent
1328+ # min and max of data
1329+ self .vmax = self ._vcenter + max (self ._vcenter - self .vmin ,
1330+ self .vmax - self ._vcenter )
1331+ self .vmin = 2 * self ._vcenter - self .vmax
1332+
1333+
12581334def _make_norm_from_scale (scale_cls , base_norm_cls = None , * , init = None ):
12591335 """
12601336 Decorator for building a `.Normalize` subclass from a `.Scale` subclass.
0 commit comments