diff --git a/lib/matplotlib/category.py b/lib/matplotlib/category.py index e755bfed0330..cf625926ee69 100644 --- a/lib/matplotlib/category.py +++ b/lib/matplotlib/category.py @@ -12,14 +12,20 @@ """ from collections import OrderedDict +import dateutil.parser import itertools +import logging import numpy as np +import matplotlib.cbook as cbook import matplotlib.units as units import matplotlib.ticker as ticker +_log = logging.getLogger(__name__) + + class StrCategoryConverter(units.ConversionInterface): @staticmethod def convert(value, unit, axis): @@ -174,6 +180,21 @@ def __init__(self, data=None): if data is not None: self.update(data) + @staticmethod + def _str_is_convertible(val): + """ + Helper method to see if a string can be cast to float or + parsed as date. + """ + try: + float(val) + except ValueError: + try: + dateutil.parser.parse(val) + except ValueError: + return False + return True + def update(self, data): """Maps new values to integer identifiers. @@ -189,11 +210,22 @@ def update(self, data): """ data = np.atleast_1d(np.array(data, dtype=object)) + # check if convertable to number: + convertable = True for val in OrderedDict.fromkeys(data): + # OrderedDict just iterates over unique values in data. if not isinstance(val, (str, bytes)): raise TypeError("{val!r} is not a string".format(val=val)) + if convertable: + # this will only be called so long as convertable is True. + convertable = self._str_is_convertible(val) if val not in self._mapping: self._mapping[val] = next(self._counter) + if convertable: + _log.info('Using categorical units to plot a list of strings ' + 'that are all parsable as floats or dates. If these ' + 'strings should be plotted as numbers, cast to the ' + 'approriate data type before plotting.') # Register the converter with Matplotlib's unit framework