Home > Software engineering >  setting major yticks in log-scale plot in Matplotlib
setting major yticks in log-scale plot in Matplotlib

Time:03-01

I want to create a plot where the vertical scale is in log scale. I want the major ticks (with number labels) to be at 1e-9, 1e-6, 1e-3, 1e0, and I want minor ticks to be at every powers of 10, i.e. 1e-9, 1e-8, 1e-7, ... , 1e-1, 1e0. In other words, I want a total of 4 major tick (with number labels) and 10 minor tick. I got it work using the following brute force method:

fig, ax = plt.subplots()

ax.set_yscale('log')

ax.set_ylim([1e-9,1])
ax.set_yticks(np.logspace(-9,0,10))
ax.set_yticklabels([r'$10^{-9}$','','',r'$10^{-6}$','','',r'$10^{-3}$','','',r'$10^{0}$'])

plt.show()

But I want to avoid using MathText whenever possible since that can messes up with the font for the figure, and it also requires me to manually write down the ticks so that can be a lot of work if I change the location of the ticks.

Is there a more automatic way of doing it? I have tried looking at ax.yaxis.set_minor_locator(LogLocator(base=10, numticks=10)) but I can't figure out the correct parameter values for my case.

CodePudding user response:

You could set all the ticks at powers of 10 with:

ax.yaxis.set_major_locator(FixedLocator(locs = np.logspace(-9, 0, 10)))

Then you can remove the ticks where the absolute value of the exponent is not a multiple of 3, in this way you keep only 1e-9, 1e-6, 1e-3 and 1e0 ticks:

fig.canvas.draw()

yticks = ax.yaxis.get_major_ticks()
for tick in yticks:
    if np.log10(tick.get_loc())%3 != 0:
        tick.label1.set_visible(False)

Complete code

from matplotlib import pyplot as plt
from matplotlib.ticker import FixedLocator
import numpy as np


x = np.linspace(0, 20, 21)
y = np.exp(-x)


fig, ax = plt.subplots()

ax.plot(x, y, marker = 'o')

ax.set_yscale('log')
ax.yaxis.set_major_locator(FixedLocator(locs = np.logspace(-9, 0, 10)))

fig.canvas.draw()

yticks = ax.yaxis.get_major_ticks()
for tick in yticks:
    if np.log10(tick.get_loc())%3 != 0:
        tick.label1.set_visible(False)

plt.show()

enter image description here


You can also use major ticks for 1e-9, 1e-6, 1e-3 and 1e0 (with labels) and minor ticks for others (without labels):

ax.set_yscale('log')
ax.yaxis.set_major_locator(FixedLocator(locs = np.logspace(-9, 0, 4)))
ax.yaxis.set_minor_locator(FixedLocator(locs = np.logspace(-9, 0, 10)))

fig.canvas.draw()

yticks = ax.yaxis.get_minor_ticks()
for tick in yticks:
    if np.log10(tick.get_loc())%3 != 0:
        tick.label1.set_visible(False)

enter image description here

  • Related