2
votes

I am trying to make a log-log plot that covers many decades in Matplotlib. However, the default x-axis ticks returned to me are far from ideal as they cover two decades at a time, with only 4 tick marks in between. The code I am using is the following:

rc('text', usetex=True)
f,ax=plt.subplots(figsize=(10,8))
plt.xscale('log')
plt.yscale('log')
plt.ylim([1e26,1e29])
plt.xlim([20,1e10])
plt.xlabel(r'x',fontsize=22)
plt.ylabel(r'y',fontsize=22)
plt.tick_params(axis='both', which='major', labelsize=22,length=9,direction='in')
plt.tick_params(axis='both', which='minor', labelsize=22,length=5,direction='in')
ax.yaxis.set_tick_params(right='on',which='both')
ax.xaxis.set_tick_params(top='on',which='both')
plt.savefig('example.pdf',bbox_inches='tight')

The image returned to me is shown below:

enter image description here

As you can see, the major x-axis labels go from 10^3 to 10^5, etc. On the other hand, there are only 4 minor x-axis labels between major labels. I would like to have major labels every decade, as on the y-axis, with the standard 8 ticks in between each decade. Moreover, I would ideally like for the labelling on the x-axis to stay as is now, in order for the axis to not be too cluttered. That is, I want 10^3, 10^5, 10^7, 10^9 to be labeled as they are now. I just want to extend the major/minor ticks to all decades in between.

Thanks in advance. Also, if it is helpful, I'm using matplotlib version 2.0.0. I need to be using this version (instead of an older version) for additional functionality that is only in 2.0.0.

1

1 Answers

2
votes

It seems that with v2, matplotlib changed to reduce the number of ticks/labels that it draws on logarithmic axes spanning large ranges. The code below shows one way of adding the ticks back.

With this code,

import pylab as plt
import numpy as np
from matplotlib.ticker import LogLocator

plt.rc('text', usetex=True)
f,ax=plt.subplots(figsize=(10,8))
plt.xscale('log')
plt.yscale('log')
plt.ylim([1e26,1e29])
plt.xlim([20,1e10])
plt.xlabel(r'x',fontsize=22)
plt.ylabel(r'y',fontsize=22)
plt.tick_params(axis='both', which='major', labelsize=22,length=9,direction='in')
plt.tick_params(axis='both', which='minor', labelsize=22,length=5,direction='in')
ax.yaxis.set_tick_params(right='on',which='both')
ax.xaxis.set_tick_params(top='on',which='both')

# manipulate x-axis ticks and labels
ax.xaxis.set_major_locator(LogLocator(numticks=15)) #(1)
ax.xaxis.set_minor_locator(LogLocator(numticks=15,subs=np.arange(2,10))) #(2)
for label in ax.xaxis.get_ticklabels()[::2]:
    label.set_visible(False) #(3)

plt.savefig('example.pdf',bbox_inches='tight')

I obtain a major tick every decade, 8 minor ticks in between major ticks, and axis labels for every other major tick. But as I've just made an account to post this answer, I don't have enough reputation to share the corresponding image :(.

Some details on each of the labeled lines (see numbered comments in code above):

  1. Increases the maximum number of allowed tick marks. The value 15 is the threshold from v1, see the source code at matplotlib/lib/matplotlib/ticker.py.
  2. When the plot axis spans more than 5 decades (undocumented, but see source code), matplotlib v2 defaults to drawing minor ticks at (2,4,6,8) only. This specifies the full range of minor ticks.
  3. Turns off every other x-axis label, see e.g. this answer.