Skip to content
This repository

Crash when using zoom tools on a plot: AutoMinorLocator after MultipleLocator gives "ValueError: Need at least two major ticks to find minor tick locations" #807

Closed
cgra opened this Issue March 29, 2012 · 2 comments

2 participants

cgra Michael Droettboom
cgra
cgra commented March 29, 2012

Run the following code and then zoom in with the zoom-box tool or the cross and right-click drag to zoom in.

from pylab import *
from matplotlib.ticker import MultipleLocator, AutoMinorLocator
plot([0,3],[0,2.2])
ax = gca()
ax.xaxis.set_major_locator(MultipleLocator(0.5))
ax.xaxis.set_minor_locator(AutoMinorLocator(2))
show()

Once MultipleLocator has been called, the auto-reassigning of tick spacing when zooming (either with the zoom box or the cross and right-click drag) does not happen, and then AutoMinorLocator gives the following error because it has "majorstep = majorlocs[1] - majorlocs[0]" and majorlocs has less than 2 elements when zoomed in that far.
"ValueError: Need at least two major ticks to find minor tick locations
( File "/usr/lib/pymodules/python2.7/matplotlib/ticker.py", line 1528, in call )"

cgra
cgra commented March 29, 2012

Found with matplotlib 1.1.0, and confirmed by Mike Kaufman on Mar 28 2012 github checkout (see matplotlib-users mailing list, thread view of http://sourceforge.net/mailarchive/message.php?msg_id=29040134).

cgra
cgra commented June 21, 2012

Ok, I took a look at the source of the error, class AutoMinorLocator(Locator), in ticker.py, and came up with a very simple fix that involves editing 1 line and adding 2 lines.

Inside

class AutoMinorLocator(Locator):

change the following

        except IndexError:
            raise ValueError('Need at least two major ticks to find minor tick locations')

to

        except IndexError:
            majorstep = 0

and change the following

        t0 = majorlocs[0]
        tmin = np.ceil((vmin - t0) / minorstep) * minorstep
        tmax = np.floor((vmax - t0) / minorstep) * minorstep
        locs = np.arange(tmin, tmax, minorstep) + t0
        cond = np.abs((locs - t0) % majorstep) > minorstep/10.0
        locs = locs.compress(cond)
        locs = []

to

        if len(majorlocs) > 0:
            t0 = majorlocs[0]
            tmin = np.ceil((vmin - t0) / minorstep) * minorstep
            tmax = np.floor((vmax - t0) / minorstep) * minorstep
            locs = np.arange(tmin, tmax, minorstep) + t0
            cond = np.abs((locs - t0) % majorstep) > minorstep/10.0
            locs = locs.compress(cond)
        else:
            locs = []

The second change could also be done with a try/except instead of an if/else, e.g.

        try:
            t0 = majorlocs[0]
            ...
        except IndexError:
            locs = []

Then when there are less than 2 major ticks visible on an axis, the minor ticks are not shown at all. (When zooming back out, the minor ticks are shown again.) This seems to be the best solution, since there does not seem to be an axis property to get tick locations that are outside the plot view range.

How does one go about submitting this to the matplotlib package?

cgra cgra closed this August 06, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.