Search code examples
pythonmatplotlibaxis-labels

Change offset in scientific axis label format


I am using the following tick label formatting:

ax.ticklabel_format(axis="y", style="sci", useOffset=True, scilimits=(0,0))

My problem is that the labels are floats. So the lowest values might be something like 0.5 (times the offset) and the highest might be 2.0 (times the offset). In this case I would like the respective labels to be 5 and 20 and change the offset by a factor of 10.

Do I have to set the ticklabels and the offset text manually or is there an simple command that does exactly that? I can't imagine that customizing the tick labels like this is not built in but I could not find anything in my searches so far.


Solution

  • Credit for the solution to ImportanceOfBeingErnest. The solution is based on this:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import matplotlib
    from matplotlib import pyplot as plt
    from matplotlib.ticker import ScalarFormatter
    import numpy as np
    
    
    
    
    class ModifiedFormatter(ScalarFormatter):
        def __init__(self, order, fformat="%.0f", offset=True, mathText=True):
            self.oom = order
            self.fformat = fformat
            ScalarFormatter.__init__(self,useOffset=offset,useMathText=mathText)
    
        def _set_orderOfMagnitude(self, nothing):
            self.orderOfMagnitude = self.oom
    
        def _set_format(self, vmin, vmax):
            self.format = self.fformat
            if self.useMathText:
                self.format = "$%s$" % matplotlib.ticker._mathdefault(self.format)
    
    
    
    
    
    
    def test():
    
        fig, ax = plt.subplots(nrows=1,ncols=1,figsize=(15,8))
    
        xv = np.random.normal(0,1,100000)
    
        xmin, xmax = -3, 3
        nbins = 100
    
        ax.hist(xv, bins=nbins, range=(xmin,xmax), histtype="step", color="blue")
    
    
    
        # determine the new order of major formatter
        # since I want 2 digits accuracy, new_order = old_order - 1
        ymin, ymax = ax.get_ylim()
        order = int("{:1.8e}".format(ymax).split("e")[1])-1
        ax.yaxis.set_major_formatter(ModifiedFormatter(order))
        ax.ticklabel_format(axis="y", style="sci", useOffset=True, scilimits=(0,0))
    
        ax.tick_params(axis="both", labelsize=20)
        ax.yaxis.get_offset_text().set_fontsize(18) 
    
    
        ax.set_xlabel("x axis label", fontsize=20)
        ax.set_ylabel("y axis label", fontsize=20)
    
    
    
        plt.subplots_adjust(top=0.9,bottom=0.1,left=0.065,right=0.99,hspace=0.2,wspace=0.2)
    
        plt.show()
    
    
    
    if __name__ == '__main__':
        test()
    

    Before: Before

    After: After