@@ -999,6 +999,121 @@ def autoscale_None(self, A):
999
999
self .vmin = ma .min (A )
1000
1000
if self .vmax is None :
1001
1001
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 ()
1002
1117
1003
1118
1004
1119
class BoundaryNorm (Normalize ):
0 commit comments