Skip to content

Commit 915bfad

Browse files
committed
Label log minor ticks if only one log major tick is drawn.
In general, avoiding axis with a single labeled tick seems to be a good idea. Previously, a log axis spanning from 4 to 60 would have its minor ticks unlabeled, LogFormatter making that choice based on the fact that the axis spans more than one decade (60/4>10). Instead, change the interpretation of the first item in `minor_thresholds` to label the minor ticks (by default) if there is only one (or zero) major tick drawn (as is the case for the above axis limits).
1 parent 202a277 commit 915bfad

File tree

3 files changed

+54
-28
lines changed

3 files changed

+54
-28
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Minor log tick labels are set depending on number of major log ticks, not on number of decades spanned
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
Previously, by default, on a log-scaled axis, the minor ticks would be
4+
unlabeled if the axis limits spanned more than one decade. The meaning of the
5+
``minor_thresholds`` parameter to `.LogFormatter` has been altered so that the
6+
decision of whether to label the minor ticks is now based on the number of
7+
major ticks drawn within the axis limits.
8+
9+
For example, for an axis spanning from 4 to 60 (with thus a single major log
10+
tick, at 10), minor ticks are now labeled, even though the axis spans more than
11+
one decade.

lib/matplotlib/tests/test_ticker.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1235,11 +1235,16 @@ def test_sublabel(self):
12351235
ax.set_xlim(1, 80)
12361236
self._sub_labels(ax.xaxis, subs=[])
12371237

1238-
# axis range at 0.4 to 1 decades, label subs 2, 3, 4, 6
1238+
# axis range slightly more than 1 decade, but spanning a single major
1239+
# tick, label subs 2, 3, 4, 6
1240+
ax.set_xlim(.8, 9)
1241+
self._sub_labels(ax.xaxis, subs=[2, 3, 4, 6])
1242+
1243+
# axis range at 0.4 to 1 decade, label subs 2, 3, 4, 6
12391244
ax.set_xlim(1, 8)
12401245
self._sub_labels(ax.xaxis, subs=[2, 3, 4, 6])
12411246

1242-
# axis range at 0 to 0.4 decades, label all
1247+
# axis range at 0 to 0.4 decade, label all
12431248
ax.set_xlim(0.5, 0.9)
12441249
self._sub_labels(ax.xaxis, subs=np.arange(2, 10, dtype=int))
12451250

lib/matplotlib/ticker.py

+36-26
Original file line numberDiff line numberDiff line change
@@ -847,20 +847,23 @@ class LogFormatter(Formatter):
847847
848848
labelOnlyBase : bool, default: False
849849
If True, label ticks only at integer powers of base.
850-
This is normally True for major ticks and False for
851-
minor ticks.
850+
This is normally True for major ticks and False for minor ticks.
852851
853852
minor_thresholds : (subset, all), default: (1, 0.4)
854853
If labelOnlyBase is False, these two numbers control
855854
the labeling of ticks that are not at integer powers of
856-
base; normally these are the minor ticks. The controlling
857-
parameter is the log of the axis data range. In the typical
858-
case where base is 10 it is the number of decades spanned
859-
by the axis, so we can call it 'numdec'. If ``numdec <= all``,
860-
all minor ticks will be labeled. If ``all < numdec <= subset``,
861-
then only a subset of minor ticks will be labeled, so as to
862-
avoid crowding. If ``numdec > subset`` then no minor ticks will
863-
be labeled.
855+
base; normally these are the minor ticks.
856+
857+
The first number (*subset*) is the largest number of major ticks for
858+
which minor ticks are labeled; e.g., the default, 1, means that minor
859+
ticks are labeled as long as there is no more than 1 major tick. (It
860+
is assumed that major ticks are at integer powers of *base*.)
861+
862+
The second number (*all*) is a threshold, in log-units of the axis
863+
limit range, over which only a subset of the minor ticks are labeled,
864+
so as to avoid crowding; e.g., with the default value (0.4) and the
865+
usual ``base=10``, all minor ticks are shown only if the axis limit
866+
range spans less than 0.4 decades.
864867
865868
linthresh : None or float, default: None
866869
If a symmetric log scale is in use, its ``linthresh``
@@ -884,12 +887,9 @@ class LogFormatter(Formatter):
884887
885888
Examples
886889
--------
887-
To label a subset of minor ticks when the view limits span up
888-
to 2 decades, and all of the ticks when zoomed in to 0.5 decades
889-
or less, use ``minor_thresholds=(2, 0.5)``.
890-
891-
To label all minor ticks when the view limits span up to 1.5
892-
decades, use ``minor_thresholds=(1.5, 1.5)``.
890+
To label a subset of minor ticks when there are up to 2 major ticks,
891+
and all of the ticks when zoomed in to 0.5 decades or less, use
892+
``minor_thresholds=(2, 0.5)``.
893893
"""
894894

895895
def __init__(self, base=10.0, labelOnlyBase=False,
@@ -957,22 +957,32 @@ def set_locs(self, locs=None):
957957
return
958958

959959
b = self._base
960+
960961
if linthresh is not None: # symlog
961-
# Only compute the number of decades in the logarithmic part of the
962-
# axis
963-
numdec = 0
962+
# Only count ticks and decades in the logarithmic part of the axis.
963+
numdec = numticks = 0
964964
if vmin < -linthresh:
965965
rhs = min(vmax, -linthresh)
966-
numdec += math.log(vmin / rhs) / math.log(b)
966+
numticks += (
967+
math.floor(math.log(abs(rhs), b))
968+
- math.floor(math.nextafter(math.log(abs(vmin), b), -math.inf)))
969+
numdec += math.log(vmin / rhs, b)
967970
if vmax > linthresh:
968971
lhs = max(vmin, linthresh)
969-
numdec += math.log(vmax / lhs) / math.log(b)
972+
numticks += (
973+
math.floor(math.log(vmax, b))
974+
- math.floor(math.nextafter(math.log(lhs, b), -math.inf)))
975+
numdec += math.log(vmax / lhs, b)
970976
else:
971-
vmin = math.log(vmin) / math.log(b)
972-
vmax = math.log(vmax) / math.log(b)
973-
numdec = abs(vmax - vmin)
974-
975-
if numdec > self.minor_thresholds[0]:
977+
lmin = math.log(vmin, b)
978+
lmax = math.log(vmax, b)
979+
# The nextafter call handles the case where vmin is exactly at a
980+
# decade (e.g. there's one major tick between 1 and 5).
981+
numticks = (math.floor(lmax)
982+
- math.floor(math.nextafter(lmin, -math.inf)))
983+
numdec = abs(lmax - lmin)
984+
985+
if numticks > self.minor_thresholds[0]:
976986
# Label only bases
977987
self._sublabels = {1}
978988
elif numdec > self.minor_thresholds[1]:

0 commit comments

Comments
 (0)