@@ -999,6 +999,121 @@ def autoscale_None(self, A):
999999 self .vmin = ma .min (A )
10001000 if self .vmax is None :
10011001 self .vmax = ma .max (A )
1002+
1003+
1004+ class SymLogNorm (Normalize ):
1005+ """
1006+ The symmetrical logarithmic scale is logarithmic in both the
1007+ positive and negative directions from the origin.
1008+
1009+ Since the values close to zero tend toward infinity, there is a
1010+ need to have a range around zero that is linear. The parameter
1011+ *linthresh* allows the user to specify the size of this range
1012+ (-*linthresh*, *linthresh*).
1013+ """
1014+ def __init__ (self , linthresh , linscale = 1.0 ,
1015+ vmin = None , vmax = None , clip = False ):
1016+ """
1017+ *linthresh*:
1018+ The range within which the plot is linear (to
1019+ avoid having the plot go to infinity around zero).
1020+
1021+ *linscale*:
1022+ This allows the linear range (-*linthresh* to *linthresh*)
1023+ to be stretched relative to the logarithmic range. Its
1024+ value is the number of decades to use for each half of the
1025+ linear range. For example, when *linscale* == 1.0 (the
1026+ default), the space used for the positive and negative
1027+ halves of the linear range will be equal to one decade in
1028+ the logarithmic range. Defaults to 1.
1029+ """
1030+ Normalize .__init__ (self , vmin , vmax , clip )
1031+ self .linthresh = linthresh
1032+ self ._linscale_adj = (linscale / (1.0 - np .e ** - 1 ))
1033+
1034+ def __call__ (self , value , clip = None ):
1035+ if clip is None :
1036+ clip = self .clip
1037+
1038+ result , is_scalar = self .process_value (value )
1039+ self .autoscale_None (result )
1040+ vmin , vmax = self .vmin , self .vmax
1041+
1042+ if vmin > vmax :
1043+ raise ValueError ("minvalue must be less than or equal to maxvalue" )
1044+ elif vmin == vmax :
1045+ result .fill (0 )
1046+ else :
1047+ if clip :
1048+ mask = ma .getmask (result )
1049+ result = ma .array (np .clip (result .filled (vmax ), vmin , vmax ),
1050+ mask = mask )
1051+ # in-place equivalent of above can be much faster
1052+ resdat = self ._transform (result .data )
1053+ resdat -= self ._lower
1054+ resdat /= (self ._upper - self ._lower )
1055+
1056+ if is_scalar :
1057+ result = result [0 ]
1058+ return result
1059+
1060+ def _transform (self , a ):
1061+ """
1062+ Inplace transformation.
1063+ """
1064+ masked = np .abs (a ) > self .linthresh
1065+ sign = np .sign (a [masked ])
1066+ log = (self ._linscale_adj + np .log (np .abs (a [masked ]) / self .linthresh ))
1067+ log *= sign * self .linthresh
1068+ a [masked ] = log
1069+ a [~ masked ] *= self ._linscale_adj
1070+ return a
1071+
1072+ def _inv_transform (self , a ):
1073+ """
1074+ Inverse inplace Transformation.
1075+ """
1076+ masked = np .abs (a ) > (self .linthresh * self ._linscale_adj )
1077+ sign = np .sign (a [masked ])
1078+ exp = np .exp (sign * a [masked ] / self .linthresh - self ._linscale_adj )
1079+ exp *= sign * self .linthresh
1080+ a [masked ] = exp
1081+ a [~ masked ] /= self ._linscale_adj
1082+ return a
1083+
1084+ def _transform_vmin_vmax (self ):
1085+ """
1086+ Calculates vmin and vmax in the transformed system.
1087+ """
1088+ vmin , vmax = self .vmin , self .vmax
1089+ arr = np .array ([vmax , vmin ])
1090+ self ._upper , self ._lower = self ._transform (arr )
1091+
1092+
1093+ def inverse (self , value ):
1094+ if not self .scaled ():
1095+ raise ValueError ("Not invertible until scaled" )
1096+ val = ma .asarray (value )
1097+ val = val * (self ._upper - self ._lower ) + self ._lower
1098+ return self ._inv_transform (val )
1099+
1100+ def autoscale (self , A ):
1101+ """
1102+ Set *vmin*, *vmax* to min, max of *A*.
1103+ """
1104+ self .vmin = ma .min (A )
1105+ self .vmax = ma .max (A )
1106+ self ._transform_vmin_vmax ()
1107+
1108+ def autoscale_None (self , A ):
1109+ """ autoscale only None-valued vmin or vmax """
1110+ if self .vmin is not None and self .vmax is not None :
1111+ pass
1112+ if self .vmin is None :
1113+ self .vmin = ma .min (A )
1114+ if self .vmax is None :
1115+ self .vmax = ma .max (A )
1116+ self ._transform_vmin_vmax ()
10021117
10031118
10041119class BoundaryNorm (Normalize ):
0 commit comments