Home > front end >  How to force labels in scientific notation in matplotlib?
How to force labels in scientific notation in matplotlib?

Time:11-12

I would like to plot the following data and I cannot seem to get matplotlib to show more axis labels.

import matplotlib.pyplot as plt
from matplotlib.ticker import LogLocator, LogFormatterMathtext
fig, ax = plt.subplots()
ax.set_yscale("log")
ax.get_yaxis().set_major_locator(LogLocator(subs=(1,2,3,4,5,6,7,8,9,)))
ax.get_yaxis().set_major_formatter(LogFormatterMathtext(base=10))
ax.plot([1,2,3,4,5], [4500, 4000, 1000, 500, 450])
plt.show()

The result:

Only one label is shown

The expected result would have labels such as 2 × 10³, 3 × 10³ etc. without an offset.

CodePudding user response:

So first thing, you don't obviously want LogFormatterMathtext. That would produce this kind of images if you had your way with "one label per tick" (we'll come to that in one moment).

enter image description here

The one you want is LogFormatterSciNotation. (LogFormatter alone would label "500", "600", "700", "800", "900", "1000", "2000", "3000", etc. ; LogFormatterExponent: 2.7, 2.78, 2.85, 2.9, 2.95, 3, 3.3, 3.48, ... ; the one you've chosen, same thing, but with 10ˣ : 10²·⁷, 10²·⁷⁸, 10²·⁸⁵, ... ; LogFormatterSciNotation is the one that would label 5×10², 6×10², 7×10²,8×10²,9×10², 10³, 2×10³, ...)

Secondly, you have to distinguish creating ticks (you did that with LogLocator), and deciding where are the labels. Ticks are not all labelled. Even major ticks. That depends on the formatter. Most formatters has default settings that makes them display more label for major ticks than for minor ticks. Yet, it is not "all" and "nothing". Especially for LogFormatter*

So, one parameter of LogFormatter* is labelOnlyBase. You want this to False. Otherwise, only power of 10 are labelled. So only "10³" in your case.

And that is not enough. Because even if the LogFormatter has nothing against labelling non 10 power, it also has some criteria about how many ticks has to be labelled, to avoid to much label density. So, that does not depends only on formatter, but also on the range of your y-axis. This is minor_thresholds parameter. To which you give a pair of thresholds. Quite complicated to understand. But the higher they are, the more ticks are labelled (not exactly so. To be more accurate, but still say it roughly, one of the thresholds is the one under which everything is labelled: "if you have less ticks than a then, label them all. Another, is the one under which only a subset (controlled by other parameters) of the ticks are labelled. Over both, only power of the base are labelled).

So, all together

import matplotlib.pyplot as plt
from matplotlib.ticker import LogLocator, LogFormatterSciNotation
fig, ax = plt.subplots()
ax.set_yscale("log")
ax.get_yaxis().set_major_locator(LogLocator(subs=(1,2,3,4,5,6,7,8,9,)))
ax.get_yaxis().set_major_formatter(LogFormatterSciNotation(base=10, minor_thresholds=(1000,1000), labelOnlyBase=False))
ax.plot([1,2,3,4,5], [4500, 4000, 1000, 500, 450])
plt.show()

(1000,1000) here is a "don't try to understand and just put insanely high values" parameters :D. I would have used (np.inf, np.inf) if numpy was imported. But that would be 1 line more.

Result:

enter image description here

  • Related