Skip to content

matplotlib.dates.DayLocator cannot handle invalid input #6935

Closed

Description

@chrisjcameron

This is a relatively minor bug in the way DayLocator tries to report an error message when running the tick_values() method. It is unable to report the invalid input because the invalid input causes a type error while formatting the error message. To be clear, the issue is not that the class breaks with invlaid input but how it breaks with invalid input.

The method could check for Nan or Inf numpy.float64 values before trying to use the %d format, switch to the %f format or catch zero-width intervals at initialization time.

Matplotlib 1.5.2, Anaconda Python 2.7 on Mac OSX

    import datetime
    import matplotlib
    import matplotlib.pyplot as plt
    from matplotlib.dates import DateFormatter, DayLocator

    vals = range(22)
    dates = [datetime.datetime(2016, 8, 1, x, 20, 20) for x in range(22)]

    plt.plot(dates, vals)
    ax = plt.subplot(111)
    ax.xaxis.set_major_locator(DayLocator(interval=0))  #causes exception
/Users/cjc73/anaconda/lib/python2.7/site-packages/matplotlib/axis.pyc in iter_ticks(self)
    892         Iterate through all of the major and minor ticks.
    893         """
--> 894         majorLocs = self.major.locator()
    895         majorTicks = self.get_major_ticks(len(majorLocs))
    896         self.major.formatter.set_locs(majorLocs)

/Users/cjc73/anaconda/lib/python2.7/site-packages/matplotlib/dates.pyc in __call__(self)
    812             return []
    813 
--> 814         return self.tick_values(dmin, dmax)
    815 
    816     def tick_values(self, vmin, vmax):

/Users/cjc73/anaconda/lib/python2.7/site-packages/matplotlib/dates.pyc in tick_values(self, vmin, vmax)
    842                 'RRuleLocator estimated to generate %d ticks from %s to %s: '
    843                 'exceeds Locator.MAXTICKS * 2 (%d) ' % (estimate, vmin, vmax,
--> 844                                                         self.MAXTICKS * 2))
    845 
    846         dates = self.rule.between(vmin, vmax, True)

TypeError: %d format: a number is required, not numpy.float64

Activity

  1. anntzer commented on Aug 10, 2016

    @anntzer
    Contributor

    Looks like we're having a premature optimization:

            # estimate the number of ticks very approximately so we don't
            # have to do a very expensive (and potentially near infinite)
            # 'between' calculation, only to find out it will fail.
            nmax, nmin = date2num((vmax, vmin))
            estimate = (nmax - nmin) / (self._get_unit() * self._get_interval())
            # This estimate is only an estimate, so be really conservative
            # about bailing...
            if estimate > self.MAXTICKS * 2:
                raise RuntimeError(
                    'RRuleLocator estimated to generate %d ticks from %s to %s: '
                    'exceeds Locator.MAXTICKS * 2 (%d) ' % (estimate, vmin, vmax,
                                                            self.MAXTICKS * 2))
    
            dates = self.rule.between(vmin, vmax, True)
    

    I'd just strip out everything but the last line and call Locator.raise_if_exceeds with the actual tick count.

  2. added this to the milestone on Aug 13, 2016
  3. added
    Difficulty: Easyhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
    on Aug 13, 2016
  4. added 4 commits that reference this issue on Aug 18, 2016
    1da1633
    e577564
    7f8c295
    2904547
  5. modified the milestones: , on Aug 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Difficulty: Easyhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issues

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions