Search code examples
pythonmatplotlibaxis-labels

Matplotlib log log plot not displaying all major and minor ticks when using loglocator and different x and y limits


I am making a log log plot and using matplotlib. I am using loglocator to make sure the relevant major and minor ticks are displayed. However, I noticed that when the x and y limits are different, some ticks and tick labels and missing: (see figure)

Below there is a simple example that produces this undesired behaviour. Any help would be greatly appreciated.

import matplotlib.pyplot as plt
import numpy as np
import matplotlib

Npoints=100
xs=np.logspace(-8,0, 100)
ys=xs

fig=plt.figure(figsize=(4,3))
ax=fig.add_subplot(111)
ax.plot(xs, ys)
ax.set_xscale('log')
ax.set_yscale('log')

locmaj = matplotlib.ticker.LogLocator(base=10,numticks=100) 
locmin = matplotlib.ticker.LogLocator(base=10,subs=np.arange(2, 10) * .1,numticks=100) # subs=(0.2,0.4,0.6,0.8)

ax.yaxis.set_major_locator(locmaj)
ax.yaxis.set_minor_locator(locmin)
ax.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())

ax.xaxis.set_major_locator(locmaj)
ax.xaxis.set_minor_locator(locmin)
ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())

ax.set_xlim(1.0e-3, 1.0)
ax.set_ylim(1.0e-8, 1.0)

plt.show()

Solution

  • In general, Locator instances should not be reused on different axes. From the Locator docs:

    Note that the same locator should not be used across multiple Axis because the locator stores references to the Axis data and view limits.

    So, for your plot, when you reuse the locators on the x-axis, they modify the ticks on the y-axis in an undesirable way. To fix this. you should make a separate instance of each LogLocator for use on each axis. For example:

    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib
    
    Npoints=100
    xs=np.logspace(-8,0, 100)
    ys=xs
    
    fig=plt.figure(figsize=(4,3))
    ax=fig.add_subplot(111)
    ax.plot(xs, ys)
    ax.set_xscale('log')
    ax.set_yscale('log')
    
    locmajx = matplotlib.ticker.LogLocator(base=10,numticks=100) 
    locminx = matplotlib.ticker.LogLocator(base=10,subs=np.arange(2, 10) * .1,numticks=100) # subs=(0.2,0.4,0.6,0.8)
    locmajy = matplotlib.ticker.LogLocator(base=10,numticks=100) 
    locminy = matplotlib.ticker.LogLocator(base=10,subs=np.arange(2, 10) * .1,numticks=100) # subs=(0.2,0.4,0.6,0.8)
    
    ax.yaxis.set_major_locator(locmajy)
    ax.yaxis.set_minor_locator(locminy)
    ax.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
    
    ax.xaxis.set_major_locator(locmajx)
    ax.xaxis.set_minor_locator(locminx)
    ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
    
    ax.set_xlim(1.0e-3, 1.0)
    ax.set_ylim(1.0e-8, 1.0)
    
    plt.show()
    

    enter image description here