Matplotlib's ticklabel_format(style='plain') is ignored or fails for logarithmic axis but works for linear axis [duplicate]
Asked Answered
L

1

1

I would like to use ticklabel_format(style='plain') to suppress scientific notation on a logarithmic axis, but it is either ignored (first plot) or throws an exception (third plot, error shown below) depending on the order of the lines. It works however for a linear axis (second plot).

This happens both in versions 1.5.1 and 2.2.2 of Matplotlib.

Question: Why it it either ignored or fails for logarithmic axis and yet works fine for linear axis?


Traceback (most recent call last):
File "test.py", line 25, in <module>
ax3.ticklabel_format(style='plain', axis='x')
File "/Users/david/anaconda2/lib/python2.7/site-packages/matplotlib/axes/_base.py", line 2805, in ticklabel_format
"This method only works with the ScalarFormatter.")
AttributeError: This method only works with the ScalarFormatter.

Here is the plot:

plot

import numpy as np
import matplotlib.pyplot as plt

x = np.logspace(-3, 3, 19)
y = np.log10(x)

fig = plt.figure()

ax1 = fig.add_subplot(3, 1, 1)
ax1.plot(x, y)
ax1.set_title("style='plain' is ignored", fontsize=16)
ax1.ticklabel_format(style='plain', axis='x')
ax1.set_xscale('log')

ax2 = fig.add_subplot(3, 1, 2)
ax2.plot(x, y)
ax2.set_title("style='plain' works", fontsize=16)
ax2.ticklabel_format(style='plain', axis='x')

if True:
    ax3 = fig.add_subplot(3, 1, 3)
    ax3.plot(x, y)
    ax3.set_title('THIS FAILS', fontsize=16)
    ax3.set_xscale('log')
    ax3.ticklabel_format(style='plain', axis='x')

plt.show()
Lacefield answered 24/4, 2019 at 9:35 Comment(10)
Have you tried using the ScalarFormatter try hereGerianne
@Gerianne notice that it does work in the second case. It is only the compatability with log scale that is the problem. I will have a look now.Lacefield
@Leal I can get the plot to work, but my question is more than that. I've left a partial answer below, but the linked answer does not explain the the selective behavior of logarithmic versus linear scale. I've added the bold Question: section to make this clearer. I don't feel this is a duplicate, would you reconsider?Lacefield
@uhoh: Ok, retracted the voteLeal
The answer to the question is simlpy that using a log scale sets the formatter to a LogFormatter. This LogFormatter does not have a style='plain' argument. The solution is, as shown in the duplicate, to use a ScalarFormatter instead.Jar
Ok I made that linked answer more explicit on the fact that a log axis uses a different formatter. (The fact that plain is not supported by the formatter in use is clear enough from the error message,I would think.)Jar
@Jar To me, logarithms are scalars, at least in mathematics. It's not obvious to someone who isn't knee-deep in matplotlib that scalar means "linear, not logarithmic". At least that's how it looks from my perspective and probably a lot of people who have used matplotlib for years without knowing that formatters even existed, much less what each name implies.Lacefield
@Jar anyway, thank you for the help. I'll go off and do my formatter homework now ;-)Lacefield
Yes, that is why you can use a ScalarFormatter without problem on a log axis, as everything is scalar. The name may be a bit confusing, it most probably comes from the fact that a number is a scalar, whereas on a log axis you use several values for formatting, i.e. the basis (like 10), the mantissa (mostly 1, but not always) and the exponent. This being said, even if it was named FooBarFormatter, would it change anything? Can the error message be made more clear? Where does a google search for ScalarFormatter lead, and is this documentation sufficient enough? If not, what can we change?Jar
@Jar I was only addressing "...is clear enough from the error message, I would think." and explaining that it wouldn't be clear enough to someone who wasn't already familliar with the way formatters work. Yes everything is googlable, and SO is usually coming up first, by design, but it will still be necessary for me to do my "formatter homework now" before I start recognizing formatters, be they scalars or Foos.Lacefield
L
2

I do not understand why the scientific notation is turned off for the linear axis and why it is either ignored or throws an exception only for the logarithmic axis, but based on this answer I can at least stop the bad behavior.

I still await an answer for why the three cases in the question produce different behavior.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

x = np.logspace(-3, 3, 19)
y = np.log10(x)

fig = plt.figure()

ax1 = fig.add_subplot(3, 1, 1)
ax1.plot(x, y)
ax1.set_title("style='plain' is ignored", fontsize=16)
ax1.ticklabel_format(style='plain', axis='x')
ax1.set_xscale('log')

ax2 = fig.add_subplot(3, 1, 2)
ax2.plot(x, y)
ax2.set_title("style='plain' works", fontsize=16)
ax2.ticklabel_format(style='plain', axis='x')

if True:
    ax3 = fig.add_subplot(3, 1, 3)
    ax3.plot(x, y)
    ax3.set_title('This now works!', fontsize=16)
    ax3.set_xscale('log')
    formatter = FuncFormatter(lambda y, _: '{:.16g}'.format(y)) # https://mcmap.net/q/265895/-matplotlib-log-scale-tick-label-number-formatting
    ax3.xaxis.set_major_formatter(formatter)

plt.show()

it works!

Lacefield answered 24/4, 2019 at 10:5 Comment(2)
ax2.ticklabel_format(style='plain', axis='x') seems to have no effect. You can just comment it out and re-run your code and you will see the middle plot is unchangedLeal
@Leal ah, then plot 2 is a moot demonstration. Yes I see now, thanks.Lacefield

© 2022 - 2024 — McMap. All rights reserved.