@@ -798,32 +798,58 @@ def _formatSciNotation(self, s):
798
798
799
799
class LogFormatter (Formatter ):
800
800
"""
801
- Format values for log axis.
801
+ Base class for formatting ticks on a log or symlog scale.
802
+
803
+ It may be instantiated directly, or subclassed.
804
+
805
+ Parameters
806
+ ----------
807
+ base : float, optional, default: 10.
808
+ Base of the logarithm used in all calculations.
809
+
810
+ labelOnlyBase : bool, optional, default: False
811
+ If True, label ticks only at integer powers of base.
812
+ This is normally True for major ticks and False for
813
+ minor ticks.
814
+
815
+ minor_thresholds : (subset, all), optional, default: (1, 0.4)
816
+ If labelOnlyBase is False, these two numbers control
817
+ the labeling of ticks that are not at integer powers of
818
+ base; normally these are the minor ticks. The controlling
819
+ parameter is the log of the axis data range. In the typical
820
+ case where base is 10 it is the number of decades spanned
821
+ by the axis, so we can call it 'numdec'. If ``numdec <= all``,
822
+ all minor ticks will be labeled. If ``all < numdec <= subset``,
823
+ then only a subset of minor ticks will be labeled, so as to
824
+ avoid crowding. If ``numdec > subset`` then no minor ticks will
825
+ be labeled.
826
+
827
+ Notes
828
+ -----
829
+ The `set_locs` method must be called to enable the subsetting
830
+ logic controlled by the ``minor_thresholds`` parameter.
831
+
832
+ In some cases such as the colorbar, there is no distinction between
833
+ major and minor ticks; the tick locations might be set manually,
834
+ or by a locator that puts ticks at integer powers of base and
835
+ at intermediate locations. For this situation, disable the
836
+ minor_thresholds logic by using ``minor_thresholds=(np.inf, np.inf)``.
837
+
838
+ Examples
839
+ --------
840
+ To label a subset of minor ticks when the view limits span up
841
+ to 2 decades, and all of the ticks when zoomed in to 0.5 decades
842
+ or less, use ``minor_thresholds=(2, 0.5)``.
843
+
844
+ To label all minor ticks when the view limits span up to 1.5
845
+ decades, use ``minor_thresholds=(1.5, 1.5)``.
846
+
847
+
802
848
"""
803
849
def __init__ (self , base = 10.0 , labelOnlyBase = False ,
804
850
minor_thresholds = (1 , 0.4 )):
805
- """
806
- `base` is used to locate the decade tick, which will be the only
807
- one to be labeled if `labelOnlyBase` is ``True``.
808
851
809
- Parameters
810
- ----------
811
- base : float, optional, default: 10.
812
- base of the logarithm.
813
-
814
- labelOnlyBase : bool, optional, default: False
815
- whether label ticks only at integer multiples of base.
816
- This is normally True for major ticks and False for
817
- minor ticks.
818
-
819
- minor_thresholds : (subset, all), optional, default: (1, 0.4)
820
- Thresholds applied to the data range measured in powers
821
- of the base (numbers of "decades", or 'numdec'), and
822
- effective only when labelOnlyBase is False. Then a
823
- subset of minor ticks will be labeled if `numdec <= subset`,
824
- and all will be labeled if `numdec <= all`.
825
- """
826
- self ._base = base + 0.0
852
+ self ._base = float (base )
827
853
self .labelOnlyBase = labelOnlyBase
828
854
self .minor_thresholds = minor_thresholds
829
855
self ._sublabels = None
@@ -850,17 +876,24 @@ def label_minor(self, labelOnlyBase):
850
876
"""
851
877
self .labelOnlyBase = labelOnlyBase
852
878
853
- def set_locs (self , locs ):
879
+ def set_locs (self , locs = None ):
880
+ """
881
+ Use axis view limits to control which ticks are labeled.
882
+
883
+ The ``locs`` parameter is ignored in the present algorithm.
884
+
885
+ """
886
+ if np .isinf (self .minor_thresholds [0 ]):
887
+ self ._sublabels = None
888
+ return
889
+
854
890
b = self ._base
855
891
856
892
vmin , vmax = self .axis .get_view_interval ()
857
893
self .d = abs (vmax - vmin )
858
894
859
- if not hasattr (self .axis , 'get_transform' ):
860
- # This might be a colorbar dummy axis, do not attempt to get
861
- # transform
862
- numdec = 10
863
- elif hasattr (self .axis .get_transform (), 'linthresh' ):
895
+ if (hasattr (self .axis , 'get_transform' ) and
896
+ hasattr (self .axis .get_transform (), 'linthresh' )):
864
897
t = self .axis .get_transform ()
865
898
linthresh = t .linthresh
866
899
# Only compute the number of decades in the logarithmic part of the
@@ -882,11 +915,13 @@ def set_locs(self, locs):
882
915
# Label only bases
883
916
self ._sublabels = set ((1 ,))
884
917
elif numdec > self .minor_thresholds [1 ]:
885
- # Add labels between bases at log-spaced coefficients
886
- c = np .logspace (0 , 1 , b // 2 + 1 , base = b )[1 :- 1 ]
918
+ # Add labels between bases at log-spaced coefficients;
919
+ # include base powers in case the locations include
920
+ # "major" and "minor" points, as in colorbar.
921
+ c = np .logspace (0 , 1 , b // 2 + 1 , base = b )
887
922
self ._sublabels = set (np .round (c ))
888
923
else :
889
- self ._sublabels = set (np .linspace (2 , b - 1 , b - 2 ))
924
+ self ._sublabels = set (np .linspace (1 , b , b - 2 ))
890
925
891
926
def __call__ (self , x , pos = None ):
892
927
"""
@@ -1809,7 +1844,22 @@ class LogLocator(Locator):
1809
1844
1810
1845
def __init__ (self , base = 10.0 , subs = (1.0 ,), numdecs = 4 , numticks = None ):
1811
1846
"""
1812
- place ticks on the location= base**i*subs[j]
1847
+ Place ticks on the locations : subs[j] * base**i
1848
+
1849
+ Parameters
1850
+ ----------
1851
+ subs : None, string, or sequence of float, optional, default (1.0,)
1852
+ Gives the multiples of integer powers of the base at which
1853
+ to place ticks. The default places ticks only at
1854
+ integer powers of the base.
1855
+ The permitted string values are ``'auto'`` and ``'all'``,
1856
+ both of which use an algorithm based on the axis view
1857
+ limits to determine whether and how to put ticks between
1858
+ integer powers of the base. With ``'auto'``, ticks are
1859
+ placed only between integer powers; with ``'all'``, the
1860
+ integer powers are included. A value of None is
1861
+ equivalent to ``'auto'``.
1862
+
1813
1863
"""
1814
1864
if numticks is None :
1815
1865
if rcParams ['_internal.classic_mode' ]:
@@ -1832,6 +1882,9 @@ def set_params(self, base=None, subs=None, numdecs=None, numticks=None):
1832
1882
if numticks is not None :
1833
1883
self .numticks = numticks
1834
1884
1885
+ # FIXME: these base and subs functions are contrary to our
1886
+ # usual and desired API.
1887
+
1835
1888
def base (self , base ):
1836
1889
"""
1837
1890
set the base of the log scaling (major tick every base**i, i integer)
@@ -1842,8 +1895,11 @@ def subs(self, subs):
1842
1895
"""
1843
1896
set the minor ticks for the log scaling every base**i*subs[j]
1844
1897
"""
1845
- if subs is None :
1846
- self ._subs = None # autosub
1898
+ if subs is None : # consistency with previous bad API
1899
+ self ._subs = 'auto'
1900
+ elif cbook .is_string_like (subs ):
1901
+ # TODO: validation ('all', 'auto')
1902
+ self ._subs = subs
1847
1903
else :
1848
1904
self ._subs = np .asarray (subs , dtype = float )
1849
1905
@@ -1887,13 +1943,17 @@ def tick_values(self, vmin, vmax):
1887
1943
1888
1944
numdec = math .floor (vmax ) - math .ceil (vmin )
1889
1945
1890
- if self ._subs is None : # autosub for minor ticks
1946
+ if cbook .is_string_like (self ._subs ):
1947
+ _first = 2.0 if self ._subs == 'auto' else 1.0
1891
1948
if numdec > 10 or b < 3 :
1892
- return np .array ([]) # no minor ticks
1949
+ if self ._subs == 'auto' :
1950
+ return np .array ([]) # no minor or major ticks
1951
+ else :
1952
+ subs = np .array ([1.0 ]) # major ticks
1893
1953
elif numdec > 5 and b >= 6 :
1894
- subs = np .arange (2.0 , b , 2.0 )
1954
+ subs = np .arange (_first , b , 2.0 )
1895
1955
else :
1896
- subs = np .arange (2.0 , b )
1956
+ subs = np .arange (_first , b )
1897
1957
else :
1898
1958
subs = self ._subs
1899
1959
0 commit comments