pythonmatplotliboffsetcolorbarmantissa

How to change the number of colorbar digits of the mantissa using offset notation


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?

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.


Solution

  • 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