0

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.

Lxndr
  • 191
  • 1
  • 4
  • 13
  • It's not built in. I'm also not sure about the desired algrithm. Would you mind to set the exponent manually (say it should be 10^5, putting in 5 manually), or would you also need to have the exponent be calculated, based on the data range? – ImportanceOfBeingErnest Jul 27 '19 at 19:53
  • If I have to set the labels and the offset text manually anyway, calculating the right exponent is not an issue. I just thought that scaling all labels and the offset text by a constant factor would be simpler. – Lxndr Jul 27 '19 at 19:59
  • If you want to put in the exponent manually, [here](https://stackoverflow.com/questions/42656139/set-scientific-notation-with-fixed-exponent-and-significant-digits-for-multiple/42658124#42658124) would be a solution. – ImportanceOfBeingErnest Jul 27 '19 at 20:02
  • That looks promising. I will post an update once I have it working (or not ;-)). In any case, thanks for your help so far. – Lxndr Jul 27 '19 at 20:10

1 Answers1

0

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

Lxndr
  • 191
  • 1
  • 4
  • 13