pythonmatplotlibxticks

Matplotlib logit scale tick number formatting


When using the log scale with matplotlib, we can set globally with (see this answer)

import matplotlib.pyplot as plt
plt.rcParams['axes.formatter.min_exponent'] = 3

that ticks on logarithmic axes are in exponential form only for x<1.e-3 and x>1.e3, but in between are just 0.001, 0.01, 0.1, 1, 10, 100, and 1000.

How can I obtain the equivalent behavior with the logit scale of matplotlib?, such that the labels become 0.001, 0.01, 0.1, 0.5, 0.9, 0.99, 0.999?


Solution

  • To do this you can define your own tick formatter, in particular, you can subclass the LogitFormatter to do what you want. Following the logit_demo example, you could do:

    import math
    from matplotlib.ticker import LogitFormatter
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    # create a formatter class based on the LogitFormatter
    class NonScientificLogitFormatter(LogitFormatter):
        def __init__(self, *args, **kwargs):
            # set the default range within which it will not use scientific notation
            self.form_range = kwargs.get("normal_format_range", 1e-3)
            
            super().__init__(*args, **kwargs)
    
        def __call__(self, x, pos=None):
            # if within that range just output the tick location value as a string
            if x >= self.form_range and x <= 1 - self.form_range:
                return str(x)
            else:
                return super().__call__(x, pos=pos)
    
    
    xmax = 10
    x = np.linspace(-xmax, xmax, 10000)
    cdf_norm = [math.erf(w / np.sqrt(2)) / 2 + 1 / 2 for w in x]
    cdf_laplacian = np.where(x < 0, 1 / 2 * np.exp(x), 1 - 1 / 2 * np.exp(-x))
    cdf_cauchy = np.arctan(x) / np.pi + 1 / 2
    
    fig, ax = plt.subplots()
    
    # Common part, for the example, we will do the same plots on all graphs
    ax.plot(x, cdf_norm, label=r"$\mathcal{N}$")
    ax.plot(x, cdf_laplacian, label=r"$\mathcal{L}$")
    ax.plot(x, cdf_cauchy, label="Cauchy")
    ax.legend()
    ax.grid()
    
    # First line, logitscale, with standard notation
    ax.set(title="logit scale")
    ax.set_yscale("logit")
    ax.set_ylim(1e-5, 1 - 1e-5)
    
    maj_form = ax.yaxis.get_major_formatter()
    
    # set the y-axis formatter to the one we defined
    ax.yaxis.set_major_formatter(
        NonScientificLogitFormatter(
            one_half=maj_form._one_half,
            use_overline=maj_form._use_overline
        )
    )
    

    A logit plot with new formatter