Search code examples
pythonmatplotlibaxis-labels

python matplotlib 2.x axis autolimit


I've got a problem with matplotlib 2.x code not reproducing 1.x behaviour, when it comes to choosing the auto-limits on the axes. According to https://matplotlib.org/users/dflt_style_changes.html , version 1.x axis rounding should be reproduced by the using the commands:

mpl.rcParams['axes.autolimit_mode'] = 'round_numbers'
mpl.rcParams['axes.xmargin'] = 0
mpl.rcParams['axes.ymargin'] = 0

But it doesn't. See the code below. My y values range from just above 5 to just below 50. When I run the code:

  • with classic (version 1.x) behaviour (sys.argv[1]=="1"), the y axis ticks are 5 and 50.
  • with version 2.x behaviour (sys.argv[1]=="2") the y axis ticks are 0 and 60.

Version 2.x rounding appears to be coarser. How do I reproduce version 1.x rounding?

import sys
import matplotlib.pyplot as plt
import matplotlib as mpl

if sys.argv[1]=="1":
    import matplotlib.style
    matplotlib.style.use('classic')
elif sys.argv[1]=="2":
    mpl.rcParams['axes.autolimit_mode'] = 'round_numbers'
    mpl.rcParams['axes.xmargin'] = 0
    mpl.rcParams['axes.ymargin'] = 0
else:
    raise Exception("param must be 1 or 2")

z = [49.0, 14.5, 6.0, 5.8]
steps = len(z)

plt.clf()
plt.figure(figsize=(8,6)) # Matplotlib 1.x default
plt.subplot(311)
plt.plot(range(steps), z)

plt.xlim(xmin=0, xmax=steps-1)
plt.xticks(range(steps))
ymin, ymax = plt.ylim()
plt.yticks([ymin, ymax])

plt.savefig("mpltest%s.pdf" % sys.argv[1])

Solution

  • First, note that the number of ticks on the axes is different between the classic mode and the adapted rcParams.

    import matplotlib.pyplot as plt
    
    mode = "classic" #"classic" #"modern"
    if mode == "classic":
        plt.style.use('classic')
    else:
        plt.rcParams['axes.autolimit_mode'] = 'round_numbers'
        plt.rcParams['axes.xmargin'] = 0
        plt.rcParams['axes.ymargin'] = 0
    
    z = [49.0, 14.5, 6.0, 5.8]
    
    plt.figure(figsize=(3,6))
    plt.subplot(311)
    plt.title("{} mode".format(mode))
    plt.plot(range(len(z)), z)
    

    enter image description here enter image description here

    Because of that different number of ticks, also the next "round number" is different. In classic mode it is 5 and 50, in "modern" mode 0 and 60.

    The changes to the defaults guide states in the "number of ticks" section:

    The locator now includes an algorithm to estimate the maximum number of ticks that will leave room for the tick labels. [...] There is no way, other than using mpl.style.use('classic'), to restore the previous behavior as the default. [...] The algorithm used by MaxNLocator has been improved, and this may change the choice of tick locations in some cases. This also affects AutoLocator, which uses MaxNLocator internally.

    Here, you have run into exactly one of those "in some cases".