Better ticks and tick labels with log scale

Viewed 8751

I am trying to get better looking log-log plots and I almost got what I want except for a minor problem.

The reason my example throws off the standard settings is that the x values are confined within less than one decade and I want to use decimal, not scientific notation.

Allow me to illustrate with an example:

import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib as mpl
import numpy as np

x = np.array([0.6,0.83,1.1,1.8,2])
y = np.array([1e-5,1e-4,1e-3,1e-2,0.1])

fig1,ax = plt.subplots()
ax.plot(x,y)
ax.set_xscale('log')
ax.set_yscale('log')

which produces:

Fig1

There are two problems with the x axis:

  1. The use of scientific notation, which in this case is counterproductive

  2. The horrible "offset" at the lower right corner

After much reading, I added three lines of code:

ax.xaxis.set_major_formatter(mpl.ticker.ScalarFormatter())
ax.xaxis.set_minor_formatter(mpl.ticker.ScalarFormatter())
ax.ticklabel_format(style='plain',axis='x',useOffset=False)

This produces:

Fig.2

My understanding of this is that there are 5 minor ticks and 1 major one. It is much better, but still not perfect:

  1. I would like some additional ticks between 1 and 2
  2. Formatting of label at 1 is wrong. It should be "1.0"

So I inserted the following line before the formatter statement:

ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(0.2))

I finally get the ticks I want:

Fig. 3

I now have 8 major and 2 minor ticks. Now, this almost looks right except for the fact that the tick labels at 0.6, 0.8 and 2.0 appear bolder than the others. What is the reason for this and how can I correct it?

1 Answers

The reason, some of the labels appear bold is that they are part of the major and minor ticklabels. If two texts perfectly overlap, they appear bolder due to the antialiasing.
You may decide to only use minor ticklabels and set the major ones with a NullLocator.

Since the locations of the ticklabels you wish to have is really specific there is no automatic locator that would provide them out of the box. For this special case it may be easiest to use a FixedLocator and specify the labels you wish to have as a list.

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

x = np.array([0.6,0.83,1.1,1.8,2])
y = np.array([1e-5,1e-4,1e-3,1e-2,0.1])

fig1,ax = plt.subplots(dpi=72, figsize=(6,4))
ax.plot(x,y)
ax.set_xscale('log')
ax.set_yscale('log')

locs = np.append( np.arange(0.1,1,0.1),np.arange(1,10,0.2))
ax.xaxis.set_minor_locator(ticker.FixedLocator(locs))
ax.xaxis.set_major_locator(ticker.NullLocator())

ax.xaxis.set_minor_formatter(ticker.ScalarFormatter())

plt.show()

enter image description here

For a more generic labeling, one could of course subclass a locator, but we would then need to know the logic to use to determine the ticklabels. (As I do not see a well defined logic for the desired ticks from the question, I feel it would be wasted effort to provide such a solution for now.)

Related