3

I have a contour plot in matplotlib using a colorbar which is created by

from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(axe) #adjust colorbar to fig height
cax = divider.append_axes("right", size=size, pad=pad)
cbar = f.colorbar(cf,cax=cax)
cbar.ax.yaxis.set_offset_position('left')
cbar.ax.tick_params(labelsize=17)#28
t = cbar.ax.yaxis.get_offset_text()
t.set_size(15)

Colorbar with offset

How can I change the colorbar ticklabels (mantissa of exponent) showing up with only 2 digits after the '.' instead of 3 (keeping the off set notation)? Is there a possibility or do I have to set the ticks manually? Thanks

I have tried to use the str formatter

cbar.ax.yaxis.set_major_formatter(FormatStrFormatter('%.2g'))

so far but this doesn't give me the desired result.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Dukaaza
  • 47
  • 1
  • 8

2 Answers2

3
import matplotlib.ticker as tkr
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(2023)
z = (np.random.random((10,10))*0.35+0.735)*1.e-7

fig, ax = plt.subplots(figsize=(10, 7))

p1 = ax.contourf(z, levels=np.linspace(0.735e-7, 1.145e-7, 10))

# compare the formats of the two colorbars
cb1 = fig.colorbar(p1, format=tkr.FormatStrFormatter('%.9f'))
cb1.set_label('%.9f', labelpad=-40, y=1.05, rotation=0)

cb2 = fig.colorbar(p1, format=tkr.FormatStrFormatter('%.2g'))
cb2.set_label('%.2g', labelpad=-40, y=1.05, rotation=0)

enter image description here

  • The colorbar can also be formatted after creation.
cb1 = fig.colorbar(p1)
cb1.ax.yaxis.set_major_formatter(tkr.FormatStrFormatter('%.9f'))
cb1.set_label('%.2g', labelpad=-40, y=1.05, rotation=0)
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Ramendra
  • 31
  • 1
2

The problem is that while the FormatStrFormatter allows to set the format precisely, it is not capable of handling offsets like the 1e-7 in the case from the question.

On the other hand the default ScalarFormatter automatically selects its own format, without letting the user change it. While this is mostly desireable, in this case, we want to specify the format ourself.

A solution is to subclass the ScalarFormatter and reimplement its ._set_format() method, similar to this answer.

Note that you would want "%.2f" instead of "%.2g" to always show 2 digits after the decimal point.

import numpy as np; np.random.seed(0)
import matplotlib.pyplot as plt
import matplotlib.ticker

class FormatScalarFormatter(matplotlib.ticker.ScalarFormatter):
    def __init__(self, fformat="%1.1f", offset=True, mathText=True):
        self.fformat = fformat
        matplotlib.ticker.ScalarFormatter.__init__(self,useOffset=offset,
                                                        useMathText=mathText)
    def _set_format(self, vmin, vmax):
        self.format = self.fformat
        if self._useMathText:
            self.format = '$%s$' % matplotlib.ticker._mathdefault(self.format)

z = (np.random.random((10,10))*0.35+0.735)*1.e-7

fig, ax = plt.subplots()
plot = ax.contourf(z, levels=np.linspace(0.735e-7,1.145e-7,10))

fmt = FormatScalarFormatter("%.2f")

cbar = fig.colorbar(plot,format=fmt)

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thank very much. I tried to built a minimal example but it showed always 2 digits as you said. This is exactly I was looking for, very nice. – Dukaaza Aug 22 '17 at 12:47
  • 2
    This fails in a current version of matplotlib with `_set_format() missing 2 required positional arguments: 'vmin' and 'vmax'` – Felix Oct 06 '21 at 13:58
  • Additionally, `._mathdefault` no longer exists. This answer is no longer a viable solution. – Trenton McKinney Aug 25 '23 at 20:55