@@ -55,9 +55,10 @@ class ConversionError(TypeError):
55
55
56
56
class AxisInfo (object ):
57
57
"""
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`.
61
62
"""
62
63
def __init__ (self , majloc = None , minloc = None ,
63
64
majfmt = None , minfmt = None , label = None ,
@@ -96,8 +97,7 @@ class ConversionInterface(object):
96
97
@staticmethod
97
98
def axisinfo (unit , axis ):
98
99
"""
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.
101
101
"""
102
102
return None
103
103
@@ -112,19 +112,19 @@ def default_units(x, axis):
112
112
def convert (obj , unit , axis ):
113
113
"""
114
114
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.
118
118
"""
119
119
return obj
120
120
121
121
@staticmethod
122
122
def is_numlike (x ):
123
123
"""
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.
128
128
"""
129
129
if np .iterable (x ):
130
130
for thisx in x :
@@ -134,73 +134,33 @@ def is_numlike(x):
134
134
135
135
136
136
class 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."""
143
138
144
139
def 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.
167
143
if 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 ()
168
148
# If there are no elements in x, infer the units from its dtype
169
149
if not x .size :
170
150
return 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 )
195
156
except (TypeError , StopIteration ):
196
157
pass
197
158
else :
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
204
164
205
165
206
166
registry = Registry ()
0 commit comments