4

I am making a figure where the x-axis should be logarithmically spaced, but I want to manually set the tick labels, and I want the tick labels to appear in ordinary '%.2f' notation, not exponential notation. The following solution based on Matplotlib - logarithmic scale, but require non-logarithmic labels suggests to use ScalarFormatter, but does not work with matplotlib 2.0:

x = np.logspace(2, 3, 100)
y = x

fig, ax = plt.subplots(1, 1)
xscale = ax.set_xscale('log')
ax.set_xticks((100, 200, 300, 500))
xlim = ax.set_xlim(100, 1000)

from matplotlib.ticker import ScalarFormatter
ax.get_xaxis().set_major_formatter(ScalarFormatter())

__=ax.plot(x, y)

enter image description here

aph
  • 1,765
  • 2
  • 19
  • 34

2 Answers2

5

The use of a ScalarFormatter is sure possible. You would then need to make sure that no minor ticklabels are shown as seen in this question: Matplotlib: setting x-limits also forces tick labels?

In your case the code would then look like:

import matplotlib.pyplot as plt
import numpy as np

x = np.logspace(2, 3, 100)
y = x

fig, ax = plt.subplots(1, 1)
xscale = ax.set_xscale('log')
ax.set_xticks((100, 200, 300, 500))
xlim = ax.set_xlim(100, 1000)

import matplotlib.ticker

ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.get_xaxis().set_minor_formatter(matplotlib.ticker.NullFormatter())

__=ax.plot(x, y)

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
2

Because you are hard-coding the min and max for the axis, it looks like you are trying to create the graph one-off rather than programatically for more general data. In this case, and especially because you are already getting a reference to the x-xais, you could place the tick label strings in a list and use the axis method set_ticklabels. In general, see the API for axis and tick objects.

Bennett Brown
  • 5,234
  • 1
  • 27
  • 35
  • Thanks Bennett, though I think I must be incorrectly implementing your suggestion. The following does not produce the desired result: ax.get_xaxis().set_ticklabels(('100', '200', '300', '500')). The API/docs indicate that you are correct, and so do not clarify what I am doing wrong. – aph Jul 31 '17 at 15:18
  • You need a list with length equal to the number of ticks: `set_ticklabels(["100", "200", "", "", "", "", "", "", "", "1000"])`. `*` works on lists in Python, so I'd use `set_ticklabels(["100", "200"]+[""]*7+["1000"])`. – Bennett Brown Jul 31 '17 at 15:25
  • Also, when you `set_xlim` I think that will `set_ticks` afresh, overriding the effect of your earlier call to `set_ticks`, as can be seen in your graphic. That's why the length of the list of ticks is not 4. – Bennett Brown Jul 31 '17 at 15:29
  • Yes, the problem is definitely with simultaneous use of set_xlim. When I remove that line, your solution works perfectly. When that line is present (and no matter where it appears in the sequence), the axis labels are duplicated and overlapping. – aph Jul 31 '17 at 15:31
  • 1
    xlim = ax.set_xlim(100, 1000) xscale = ax.set_xscale('log') ax.set_xticks((100, 200, 300, 500)) ax.set_xticklabels(['100', '200', '300', '500']) ax.xaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter('%.1f')) – aph Jul 31 '17 at 15:33
  • sorry, comments section is pretty limiting for code (and figures not an option) – aph Jul 31 '17 at 15:33