Reputation: 2449
This is my data frame I'm trying to plot:
my_dic = {'stats': {'apr': 23083904, 'may': 16786816, 'june': 26197936}}
my_df = pd.DataFrame(my_dic)
This is how I plot it:
ax = my_df['stats'].plot(kind='bar', legend=False)
ax.set_xlabel("Month", fontsize=12)
ax.set_ylabel("Stats", fontsize=12)
ax.ticklabel_format(useOffset=False) #AttributeError: This method only works with the ScalarFormatter.
plt.show()
The plot:
I'd like to control the scientific notation. I tried to suppress it by this line as was suggested in other questions plt.ticklabel_format(useOffset=False)
but I get this error back -
AttributeError: This method only works with the ScalarFormatter
Ideally, I'd like to show my data in (mln).
Upvotes: 23
Views: 37330
Reputation: 23391
If you're here wondering why you got the error,
AttributeError: This method only works with the ScalarFormatter
then you got the error because as the error says, ticklabel_format
only works with ScalarFormatter
(which formats tick values as numbers), but some tick labels of your plot are not numbers.
A common way this error might occur is when you want to format the ticklabels of a plot with two levels of ticks (major and minor) where the major ticks are not scalars. A common way this happens is when a bar plot is plotted with log scale. The easiest way to solve the error is to ditch ticklabel_format
and use ScalarFormatter
on both levels of ticks instead.
plt.bar([1,2], [1000, 2000], log=True)
plt.ticklabel_format(axis='y', style='plain') # <---- error
from matplotlib.ticker import ScalarFormatter
plt.gca().yaxis.set_major_formatter(ScalarFormatter())
plt.gca().yaxis.set_minor_formatter(ScalarFormatter()); # <---- OK
Another way is when one axis tick labels are not scalars (as in the OP). In the OP, x-axis tick labels are not numbers so the error was raised (by default both axes are flagged). Specifying axis='y'
in ticklabel_format
solves the error.
ax = my_df['stats'].plot(kind='bar', legend=False, xlabel='Month', ylabel='Stats', rot=0)
ax.ticklabel_format(axis='y', scilimits=(0,10)) # <--- no error
ax.ticklabel_format(axis='x', scilimits=(0,10)) # <--- error because ticklabels are strings
Also if the y-ticklabels need a thousands separator comma, then set_yticks()
could be used to change it as such.
ax = my_df['stats'].plot(kind='bar', legend=False, xlabel='Month', ylabel='Stats', rot=0)
ax.set_yticks(ax.get_yticks()[:-1], [f"{int(x):,}" for x in ax.get_yticks()[:-1]]);
Upvotes: 3
Reputation: 2449
Adding this line helps to get numbers in a plain format but with ',' which looks much nicer:
ax.get_yaxis().set_major_formatter(
matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
And then I can use int(x)/
to convert to million or thousand as I wish:
Upvotes: 25