@@ -902,10 +902,6 @@ def set_locs(self, locs=None):
902
902
self ._sublabels = None
903
903
return
904
904
905
- b = self ._base
906
-
907
- vmin , vmax = self .axis .get_view_interval ()
908
-
909
905
# Handle symlog case:
910
906
linthresh = self ._linthresh
911
907
if linthresh is None :
@@ -914,6 +910,18 @@ def set_locs(self, locs=None):
914
910
except AttributeError :
915
911
pass
916
912
913
+ vmin , vmax = self .axis .get_view_interval ()
914
+ if vmin > vmax :
915
+ vmin , vmax = vmax , vmin
916
+
917
+ if linthresh is None and vmin <= 0 :
918
+ # It's probably a colorbar with
919
+ # a format kwarg setting a LogFormatter in the manner
920
+ # that worked with 1.5.x, but that doesn't work now.
921
+ self ._sublabels = set ((1 ,)) # label powers of base
922
+ return
923
+
924
+ b = self ._base
917
925
if linthresh is not None : # symlog
918
926
# Only compute the number of decades in the logarithmic part of the
919
927
# axis
@@ -943,37 +951,38 @@ def set_locs(self, locs=None):
943
951
# Label all integer multiples of base**n.
944
952
self ._sublabels = set (np .arange (1 , b + 1 ))
945
953
954
+ def _num_to_string (self , x , vmin , vmax ):
955
+ if x > 10000 :
956
+ s = '%1.0e' % x
957
+ elif x < 1 :
958
+ s = '%1.0e' % x
959
+ else :
960
+ s = self .pprint_val (x , vmax - vmin )
961
+
946
962
def __call__ (self , x , pos = None ):
947
963
"""
948
964
Return the format for tick val `x`.
949
965
"""
950
- vmin , vmax = self .axis .get_view_interval ()
951
- vmin , vmax = mtransforms .nonsingular (vmin , vmax , expander = 0.05 )
952
- d = abs (vmax - vmin )
953
- b = self ._base
954
- if x == 0.0 :
966
+ if x == 0.0 : # Symlog
955
967
return '0'
968
+
956
969
sign = np .sign (x )
957
970
x = abs (x )
971
+ b = self ._base
958
972
# only label the decades
959
973
fx = math .log (x ) / math .log (b )
960
974
is_x_decade = is_close_to_int (fx )
961
975
exponent = np .round (fx ) if is_x_decade else np .floor (fx )
962
976
coeff = np .round (x / b ** exponent )
977
+
963
978
if self .labelOnlyBase and not is_x_decade :
964
979
return ''
965
980
if self ._sublabels is not None and coeff not in self ._sublabels :
966
981
return ''
967
982
968
- if x > 10000 :
969
- s = '%1.0e' % x
970
- elif x < 1 :
971
- s = '%1.0e' % x
972
- else :
973
- s = self .pprint_val (x , d )
974
- if sign == - 1 :
975
- s = '-%s' % s
976
-
983
+ vmin , vmax = self .axis .get_view_interval ()
984
+ vmin , vmax = mtransforms .nonsingular (vmin , vmax , expander = 0.05 )
985
+ s = self ._num_to_string (x , vmin , vmax )
977
986
return self .fix_minus (s )
978
987
979
988
def format_data (self , value ):
@@ -1026,41 +1035,16 @@ class LogFormatterExponent(LogFormatter):
1026
1035
"""
1027
1036
Format values for log axis using ``exponent = log_base(value)``.
1028
1037
"""
1029
- def __call__ (self , x , pos = None ):
1030
- """
1031
- Return the format for tick value `x`.
1032
- """
1033
- vmin , vmax = self .axis .get_view_interval ()
1034
- vmin , vmax = mtransforms .nonsingular (vmin , vmax , expander = 0.05 )
1035
- d = abs (vmax - vmin )
1036
- b = self ._base
1037
- if x == 0 :
1038
- return '0'
1039
- sign = np .sign (x )
1040
- x = abs (x )
1041
- # only label the decades
1042
- fx = math .log (x ) / math .log (b )
1043
-
1044
- is_x_decade = is_close_to_int (fx )
1045
- exponent = np .round (fx ) if is_x_decade else np .floor (fx )
1046
- coeff = np .round (x / b ** exponent )
1047
-
1048
- if self .labelOnlyBase and not is_x_decade :
1049
- return ''
1050
- if self ._sublabels is not None and coeff not in self ._sublabels :
1051
- return ''
1052
-
1038
+ def _num_to_string (self , x , vmin , vmax ):
1039
+ fx = math .log (x ) / math .log (self ._base )
1053
1040
if abs (fx ) > 10000 :
1054
1041
s = '%1.0g' % fx
1055
1042
elif abs (fx ) < 1 :
1056
1043
s = '%1.0g' % fx
1057
1044
else :
1058
- fd = math .log (abs ( d )) / math .log (b )
1045
+ fd = math .log (vmax - vmin ) / math .log (self . _base )
1059
1046
s = self .pprint_val (fx , fd )
1060
- if sign == - 1 :
1061
- s = '-%s' % s
1062
-
1063
- return self .fix_minus (s )
1047
+ return s
1064
1048
1065
1049
1066
1050
class LogFormatterMathtext (LogFormatter ):
@@ -1082,35 +1066,34 @@ def __call__(self, x, pos=None):
1082
1066
1083
1067
The position `pos` is ignored.
1084
1068
"""
1085
- b = self ._base
1086
1069
usetex = rcParams ['text.usetex' ]
1087
-
1088
- # only label the decades
1089
- if x == 0 :
1070
+ if x == 0 : # Symlog
1090
1071
if usetex :
1091
1072
return '$0$'
1092
1073
else :
1093
1074
return '$%s$' % _mathdefault ('0' )
1094
1075
1095
1076
sign_string = '-' if x < 0 else ''
1096
1077
x = abs (x )
1078
+ b = self ._base
1097
1079
1080
+ # only label the decades
1098
1081
fx = math .log (x ) / math .log (b )
1099
1082
is_x_decade = is_close_to_int (fx )
1100
1083
exponent = np .round (fx ) if is_x_decade else np .floor (fx )
1101
1084
coeff = np .round (x / b ** exponent )
1102
1085
1086
+ if self .labelOnlyBase and not is_x_decade :
1087
+ return ''
1088
+ if self ._sublabels is not None and coeff not in self ._sublabels :
1089
+ return ''
1090
+
1103
1091
# use string formatting of the base if it is not an integer
1104
1092
if b % 1 == 0.0 :
1105
1093
base = '%d' % b
1106
1094
else :
1107
1095
base = '%s' % b
1108
1096
1109
- if self .labelOnlyBase and not is_x_decade :
1110
- return ''
1111
- if self ._sublabels is not None and coeff not in self ._sublabels :
1112
- return ''
1113
-
1114
1097
if not is_x_decade :
1115
1098
return self ._non_decade_format (sign_string , base , fx , usetex )
1116
1099
else :
@@ -2032,36 +2015,41 @@ def view_limits(self, vmin, vmax):
2032
2015
'Try to choose the view limits intelligently'
2033
2016
b = self ._base
2034
2017
2035
- if vmax < vmin :
2036
- vmin , vmax = vmax , vmin
2018
+ vmin , vmax = self .nonsingular (vmin , vmax )
2037
2019
2038
2020
if self .axis .axes .name == 'polar' :
2039
2021
vmax = math .ceil (math .log (vmax ) / math .log (b ))
2040
2022
vmin = b ** (vmax - self .numdecs )
2041
- return vmin , vmax
2042
-
2043
- minpos = self .axis .get_minpos ()
2044
-
2045
- if minpos <= 0 or not np .isfinite (minpos ):
2046
- raise ValueError (
2047
- "Data has no positive values, and therefore can not be "
2048
- "log-scaled." )
2049
-
2050
- if vmin <= 0 :
2051
- vmin = minpos
2052
2023
2053
2024
if rcParams ['axes.autolimit_mode' ] == 'round_numbers' :
2054
2025
if not is_decade (vmin , self ._base ):
2055
2026
vmin = decade_down (vmin , self ._base )
2056
2027
if not is_decade (vmax , self ._base ):
2057
2028
vmax = decade_up (vmax , self ._base )
2058
2029
2059
- if vmin == vmax :
2060
- vmin = decade_down (vmin , self ._base )
2061
- vmax = decade_up (vmax , self ._base )
2030
+ return vmin , vmax
2062
2031
2063
- result = mtransforms .nonsingular (vmin , vmax )
2064
- return result
2032
+ def nonsingular (self , vmin , vmax ):
2033
+ if not np .isfinite (vmin ) or not np .isfinite (vmax ):
2034
+ return 1 , 10 # initial range, no data plotted yet
2035
+
2036
+ if vmin > vmax :
2037
+ vmin , vmax = vmax , vmin
2038
+ if vmax <= 0 :
2039
+ warnings .warn (
2040
+ "Data has no positive values, and therefore cannot be "
2041
+ "log-scaled." )
2042
+ return 1 , 10
2043
+
2044
+ minpos = self .axis .get_minpos ()
2045
+ if not np .isfinite (minpos ):
2046
+ minpos = 1e-300 # This should never take effect.
2047
+ if vmin <= 0 :
2048
+ vmin = minpos
2049
+ if vmin == vmax :
2050
+ vmin = decade_down (vmin , self ._base )
2051
+ vmax = decade_up (vmax , self ._base )
2052
+ return vmin , vmax
2065
2053
2066
2054
2067
2055
class SymmetricalLogLocator (Locator ):
@@ -2260,32 +2248,7 @@ def tick_values(self, vmin, vmax):
2260
2248
if hasattr (self .axis , 'axes' ) and self .axis .axes .name == 'polar' :
2261
2249
raise NotImplementedError ('Polar axis cannot be logit scaled yet' )
2262
2250
2263
- # what to do if a window beyond ]0, 1[ is chosen
2264
- if vmin <= 0.0 :
2265
- if self .axis is not None :
2266
- vmin = self .axis .get_minpos ()
2267
-
2268
- if (vmin <= 0.0 ) or (not np .isfinite (vmin )):
2269
- raise ValueError (
2270
- "Data has no values in ]0, 1[ and therefore can not be "
2271
- "logit-scaled." )
2272
-
2273
- # NOTE: for vmax, we should query a property similar to get_minpos, but
2274
- # related to the maximal, less-than-one data point. Unfortunately,
2275
- # get_minpos is defined very deep in the BBox and updated with data,
2276
- # so for now we use the trick below.
2277
- if vmax >= 1.0 :
2278
- if self .axis is not None :
2279
- vmax = 1 - self .axis .get_minpos ()
2280
-
2281
- if (vmax >= 1.0 ) or (not np .isfinite (vmax )):
2282
- raise ValueError (
2283
- "Data has no values in ]0, 1[ and therefore can not be "
2284
- "logit-scaled." )
2285
-
2286
- if vmax < vmin :
2287
- vmin , vmax = vmax , vmin
2288
-
2251
+ vmin , vmax = self .nonsingular (vmin , vmax )
2289
2252
vmin = np .log10 (vmin / (1 - vmin ))
2290
2253
vmax = np .log10 (vmax / (1 - vmax ))
2291
2254
@@ -2320,6 +2283,36 @@ def tick_values(self, vmin, vmax):
2320
2283
2321
2284
return self .raise_if_exceeds (np .array (ticklocs ))
2322
2285
2286
+ def nonsingular (self , vmin , vmax ):
2287
+ initial_range = (1e-7 , 1 - 1e-7 )
2288
+ if not np .isfinite (vmin ) or not np .isfinite (vmax ):
2289
+ return initial_range # no data plotted yet
2290
+
2291
+ if vmin > vmax :
2292
+ vmin , vmax = vmax , vmin
2293
+
2294
+ # what to do if a window beyond ]0, 1[ is chosen
2295
+ if self .axis is not None :
2296
+ minpos = self .axis .get_minpos ()
2297
+ if not np .isfinite (minpos ):
2298
+ return initial_range # again, no data plotted
2299
+ else :
2300
+ minpos = 1e-7 # should not occur in normal use
2301
+
2302
+ # NOTE: for vmax, we should query a property similar to get_minpos, but
2303
+ # related to the maximal, less-than-one data point. Unfortunately,
2304
+ # Bbox._minpos is defined very deep in the BBox and updated with data,
2305
+ # so for now we use 1 - minpos as a substitute.
2306
+
2307
+ if vmin <= 0 :
2308
+ vmin = minpos
2309
+ if vmax >= 1 :
2310
+ vmax = 1 - minpos
2311
+ if vmin == vmax :
2312
+ return 0.1 * vmin , 1 - 0.1 * vmin
2313
+
2314
+ return vmin , vmax
2315
+
2323
2316
2324
2317
class AutoLocator (MaxNLocator ):
2325
2318
def __init__ (self ):
0 commit comments