130

I am trying to set the format to two decimal numbers in a matplotlib subplot environment. Unfortunately, I do not have any idea how to solve this task.

To prevent using scientific notation on the y-axis I used ScalarFormatter(useOffset=False) as you can see in my snippet below. I think my task should be solved by passing further options/arguments to the used formatter. However, I could not find any hint in matplotlib's documentation.

How can I set two decimal digits or none (both cases are needed)? I am not able to provide sample data, unfortunately.


-- SNIPPET --

f, axarr = plt.subplots(3, sharex=True)

data = conv_air
x = range(0, len(data))

axarr[0].scatter(x, data)
axarr[0].set_ylabel('$T_\mathrm{air,2,2}$', size=FONT_SIZE)
axarr[0].yaxis.set_major_locator(MaxNLocator(5))
axarr[0].yaxis.set_major_formatter(ScalarFormatter(useOffset=False))
axarr[0].tick_params(direction='out', labelsize=FONT_SIZE)
axarr[0].grid(which='major', alpha=0.5)
axarr[0].grid(which='minor', alpha=0.2)

data = conv_dryer
x = range(0, len(data))

axarr[1].scatter(x, data)
axarr[1].set_ylabel('$T_\mathrm{dryer,2,2}$', size=FONT_SIZE)
axarr[1].yaxis.set_major_locator(MaxNLocator(5))
axarr[1].yaxis.set_major_formatter(ScalarFormatter(useOffset=False))
axarr[1].tick_params(direction='out', labelsize=FONT_SIZE)
axarr[1].grid(which='major', alpha=0.5)
axarr[1].grid(which='minor', alpha=0.2)

data = conv_lambda
x = range(0, len(data))

axarr[2].scatter(x, data)
axarr[2].set_xlabel('Iterationsschritte', size=FONT_SIZE)
axarr[2].xaxis.set_major_locator(MaxNLocator(integer=True))
axarr[2].set_ylabel('$\lambda$', size=FONT_SIZE)
axarr[2].yaxis.set_major_formatter(ScalarFormatter(useOffset=False))
axarr[2].yaxis.set_major_locator(MaxNLocator(5))
axarr[2].tick_params(direction='out', labelsize=FONT_SIZE)
axarr[2].grid(which='major', alpha=0.5)
axarr[2].grid(which='minor', alpha=0.2)
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
albert
  • 8,027
  • 10
  • 48
  • 84

5 Answers5

206

See the relevant documentation in general and specifically

from matplotlib.ticker import FormatStrFormatter

fig, ax = plt.subplots()

ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))

enter image description here

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • 2
    Note: if you prefer to use new `.format()` style specifiers you can use the `StrMethodFormatter` mentioned on the [linked page](http://matplotlib.org/api/ticker_api.html#matplotlib.ticker.StrMethodFormatter) – mangecoeur Apr 03 '17 at 09:39
  • 1
    I'm plotting with `imshow` and this doesn't work for me. I've also tried `plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.g'))` from [this answer](https://stackoverflow.com/questions/42929550/ticks-format-of-an-axis-in-matplotlib) but to no avail. Any ideas? – airdas Aug 08 '17 at 16:44
  • 1
    @airdas If you encounter a problem, please ask a new question about it, providing all the details and a [mcve] of the issue. – ImportanceOfBeingErnest Aug 22 '17 at 11:41
  • Is it possible to use 2 different formats for ticks in the same axis? I'm inserting some extra tick and I'd like it as `.2f` but the original ticks I'd like `.1f`. – Sigur Dec 18 '17 at 18:57
  • You're using `subplots` without argument. Does that mean it's additional to the `subplots(3)` that the questioner has? I'm guessing not, but if I insert a plot count in your code I get "AttributeError: 'numpy.ndarray' object has no attribute 'yaxis'" – Victor Eijkhout Sep 13 '18 at 16:57
  • @VictorEijkhout See https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html?highlight=subplots#matplotlib.pyplot.subplots – tacaswell Sep 17 '18 at 23:38
  • 4
    Even works without importing `FormatStrFormatter` separately. Its locates under `pyplot` `import matplotlib.pyplot as plt;` `ax.yaxis.set_major_formatter(plt.FormatStrFormatter('%.2f'))` –  Mar 15 '20 at 14:46
  • 1
    I had to use: ax.get_yaxis().set_major_formatter(FormatStrFormatter('%.2f')) but it worked perfectly. – Darcey BM Aug 10 '20 at 10:26
  • This is not a great way to do it because tick labels might repeat. – Björn Lindqvist May 07 '21 at 01:37
  • Since matplotlib 3.3 this also works with a format str: `ax.yaxis.set_major_formatter('{x:.2f}')`. As mentioned in the [docs](https://matplotlib.org/stable/api/_as_gen/matplotlib.axis.Axis.set_major_formatter.html), the value must be labeled as `x`. – Javier TG Mar 07 '23 at 08:59
55

If you are directly working with matplotlib's pyplot (plt) and if you are more familiar with the new-style format string, you can try this:

from matplotlib.ticker import StrMethodFormatter
plt.gca().yaxis.set_major_formatter(StrMethodFormatter('{x:,.0f}')) # No decimal places
plt.gca().yaxis.set_major_formatter(StrMethodFormatter('{x:,.2f}')) # 2 decimal places

From the documentation:

class matplotlib.ticker.StrMethodFormatter(fmt)

Use a new-style format string (as used by str.format()) to format the tick.

The field used for the value must be labeled x and the field used for the position must be labeled pos.

CodeWarrior
  • 1,239
  • 1
  • 14
  • 19
32

The answer above is probably the correct way to do it, but didn't work for me.

The hacky way that solved it for me was the following:

ax = <whatever your plot is> 
# get the current labels 
labels = [item.get_text() for item in ax.get_xticklabels()]
# Beat them into submission and set them back again
ax.set_xticklabels([str(round(float(label), 2)) for label in labels])
# Show the plot, and go home to family 
plt.show()
sapo_cosmico
  • 6,274
  • 12
  • 45
  • 58
  • 3
    You should rather put it `[str(round(float(label), 2)) for label in labels if label!='']` or you are going to have trouble with empty labels. –  Feb 20 '19 at 12:13
  • 1
    I've also found that PyPlot responds best to beatings. Generally not worth asking nicely because experience has taught me that it's just going to mess around – Ryan Jan 19 '23 at 21:08
10

format labels using lambda function

enter image description here 3x the same plot with differnt y-labeling

Minimal example

import numpy as np
import matplotlib as mpl
import matplotlib.pylab as plt
from matplotlib.ticker import FormatStrFormatter

fig, axs = mpl.pylab.subplots(1, 3)

xs = np.arange(10)
ys = 1 + xs ** 2 * 1e-3

axs[0].set_title('default y-labeling')
axs[0].scatter(xs, ys)
axs[1].set_title('custom y-labeling')
axs[1].scatter(xs, ys)
axs[2].set_title('x, pos arguments')
axs[2].scatter(xs, ys)


fmt = lambda x, pos: '1+ {:.0f}e-3'.format((x-1)*1e3, pos)
axs[1].yaxis.set_major_formatter(mpl.ticker.FuncFormatter(fmt))

fmt = lambda x, pos: 'x={:f}\npos={:f}'.format(x, pos)
axs[2].yaxis.set_major_formatter(mpl.ticker.FuncFormatter(fmt))

You can also use 'real'-functions instead of lambdas, of course. https://matplotlib.org/3.1.1/gallery/ticks_and_spines/tick-formatters.html

Markus Dutschke
  • 9,341
  • 4
  • 63
  • 58
6

In matplotlib 3.1, you can also use ticklabel_format. To prevents scientific notation without offsets:

plt.gca().ticklabel_format(axis='both', style='plain', useOffset=False)
foxpal
  • 586
  • 4
  • 14