@@ -55,9 +55,10 @@ class ConversionError(TypeError):
5555
5656class AxisInfo (object ):
5757"""
58- Information to support default axis labeling, tick labeling, and
59- default limits. An instance of this class must be returned by
60- :meth:`ConversionInterface.axisinfo`.
58+ Information to support default axis labeling, tick labeling, and limits.
59+
60+ An instance of this class must be returned by
61+ `ConversionInterface.axisinfo`.
6162 """
6263def __init__ (self ,majloc = None ,minloc = None ,
6364majfmt = None ,minfmt = None ,label = None ,
@@ -96,8 +97,7 @@ class ConversionInterface(object):
9697@staticmethod
9798def axisinfo (unit ,axis ):
9899"""
99- Return an `~units.AxisInfo` instance for the axis with the
100- specified units.
100+ Return an `~units.AxisInfo` for the axis with the specified units.
101101 """
102102return None
103103
@@ -112,19 +112,19 @@ def default_units(x, axis):
112112def convert (obj ,unit ,axis ):
113113"""
114114 Convert *obj* using *unit* for the specified *axis*.
115- If *obj* is a sequence, return the converted sequence.
116- The output must be a sequence of scalars that can be used by the numpy
117- array layer.
115+
116+ If *obj* is a sequence, return the converted sequence. The output must
117+ be a sequence of scalars that can be used by the numpy array layer.
118118 """
119119return obj
120120
121121@staticmethod
122122def is_numlike (x ):
123123"""
124- The Matplotlib datalim, autoscaling, locators etc work with
125- scalars which are the units converted to floats given the
126- current unit. The converter may be passed these floats, or
127- arrays of them, even when units are set.
124+ The Matplotlib datalim, autoscaling, locators etc work with scalars
125+ which are the units converted to floats given the current unit. The
126+ converter may be passed these floats, or arrays of them, even when
127+ units are set.
128128 """
129129if np .iterable (x ):
130130for thisx in x :
@@ -134,73 +134,33 @@ def is_numlike(x):
134134
135135
136136class Registry (dict ):
137- """
138- A register that maps types to conversion interfaces.
139- """
140- def __init__ (self ):
141- dict .__init__ (self )
142- self ._cached = {}
137+ """Register types with conversion interface."""
143138
144139def get_converter (self ,x ):
145- """
146- Get the converter for data that has the same type as *x*. If no
147- converters are registered for *x*, returns ``None``.
148- """
149-
150- if not len (self ):
151- return None # nothing registered
152- # DISABLED idx = id(x)
153- # DISABLED cached = self._cached.get(idx)
154- # DISABLED if cached is not None: return cached
155-
156- converter = None
157- classx = getattr (x ,'__class__' ,None )
158-
159- if classx is not None :
160- converter = self .get (classx )
161-
162- if converter is None and hasattr (x ,"values" ):
163- # this unpacks pandas series or dataframes...
164- x = x .values
165-
166- # If x is an array, look inside the array for data with units
140+ """Get the converter interface instance for *x*, or None."""
141+ if hasattr (x ,"values" ):
142+ x = x .values # Unpack pandas Series and DataFrames.
167143if isinstance (x ,np .ndarray ):
144+ # In case x in a masked array, access the underlying data (only its
145+ # type matters). If x is a regular ndarray, getdata() just returns
146+ # the array itself.
147+ x = np .ma .getdata (x ).ravel ()
168148# If there are no elements in x, infer the units from its dtype
169149if not x .size :
170150return self .get_converter (np .array ([0 ],dtype = x .dtype ))
171- xravel = x .ravel ()
172- try :
173- # pass the first value of x that is not masked back to
174- # get_converter
175- if not np .all (xravel .mask ):
176- # Get first non-masked item
177- converter = self .get_converter (
178- xravel [np .argmin (xravel .mask )])
179- return converter
180- except AttributeError :
181- # not a masked_array
182- # Make sure we don't recurse forever -- it's possible for
183- # ndarray subclasses to continue to return subclasses and
184- # not ever return a non-subclass for a single element.
185- next_item = xravel [0 ]
186- if (not isinstance (next_item ,np .ndarray )or
187- next_item .shape != x .shape ):
188- converter = self .get_converter (next_item )
189- return converter
190-
191- # If we haven't found a converter yet, try to get the first element
192- if converter is None :
193- try :
194- thisx = cbook .safe_first_element (x )
151+ try :# Look up in the cache.
152+ return self [type (x )]
153+ except KeyError :
154+ try :# If cache lookup fails, look up based on first element...
155+ first = cbook .safe_first_element (x )
195156except (TypeError ,StopIteration ):
196157pass
197158else :
198- if classx and classx != getattr (thisx ,'__class__' ,None ):
199- converter = self .get_converter (thisx )
200- return converter
201-
202- # DISABLED self._cached[idx] = converter
203- return converter
159+ # ... and avoid infinite recursion for pathological iterables
160+ # where indexing returns instances of the same iterable class.
161+ if type (first )is not type (x ):
162+ return self .get_converter (first )
163+ return None
204164
205165
206166registry = Registry ()