@@ -51,9 +51,10 @@ def default_units(x, axis):
51
51
52
52
class AxisInfo (object ):
53
53
"""
54
- Information to support default axis labeling, tick labeling, and
55
- default limits. An instance of this class must be returned by
56
- :meth:`ConversionInterface.axisinfo`.
54
+ Information to support default axis labeling, tick labeling, and limits.
55
+
56
+ An instance of this class must be returned by
57
+ `ConversionInterface.axisinfo`.
57
58
"""
58
59
def __init__ (self , majloc = None , minloc = None ,
59
60
majfmt = None , minfmt = None , label = None ,
@@ -92,8 +93,7 @@ class ConversionInterface(object):
92
93
@staticmethod
93
94
def axisinfo (unit , axis ):
94
95
"""
95
- Return an `~units.AxisInfo` instance for the axis with the
96
- specified units.
96
+ Return an `~units.AxisInfo` for the axis with the specified units.
97
97
"""
98
98
return None
99
99
@@ -108,19 +108,19 @@ def default_units(x, axis):
108
108
def convert (obj , unit , axis ):
109
109
"""
110
110
Convert *obj* using *unit* for the specified *axis*.
111
- If *obj* is a sequence, return the converted sequence.
112
- The output must be a sequence of scalars that can be used by the numpy
113
- array layer.
111
+
112
+ If *obj* is a sequence, return the converted sequence. The output must
113
+ be a sequence of scalars that can be used by the numpy array layer.
114
114
"""
115
115
return obj
116
116
117
117
@staticmethod
118
118
def is_numlike (x ):
119
119
"""
120
- The Matplotlib datalim, autoscaling, locators etc work with
121
- scalars which are the units converted to floats given the
122
- current unit. The converter may be passed these floats, or
123
- arrays of them, even when units are set.
120
+ The Matplotlib datalim, autoscaling, locators etc work with scalars
121
+ which are the units converted to floats given the current unit. The
122
+ converter may be passed these floats, or arrays of them, even when
123
+ units are set.
124
124
"""
125
125
if iterable (x ):
126
126
for thisx in x :
@@ -130,70 +130,28 @@ def is_numlike(x):
130
130
131
131
132
132
class Registry (dict ):
133
- """
134
- A register that maps types to conversion interfaces.
135
- """
136
- def __init__ (self ):
137
- dict .__init__ (self )
138
- self ._cached = {}
133
+ """Register types with conversion interface."""
139
134
140
135
def get_converter (self , x ):
141
- """
142
- Get the converter for data that has the same type as *x*. If no
143
- converters are registered for *x*, returns ``None``.
144
- """
145
-
146
- if not len (self ):
147
- return None # nothing registered
148
- # DISABLED idx = id(x)
149
- # DISABLED cached = self._cached.get(idx)
150
- # DISABLED if cached is not None: return cached
151
-
152
- converter = None
153
- classx = getattr (x , '__class__' , None )
154
-
155
- if classx is not None :
156
- converter = self .get (classx )
157
-
158
- if converter is None and hasattr (x , "values" ):
159
- # this unpacks pandas series or dataframes...
160
- x = x .values
161
-
162
- # If x is an array, look inside the array for data with units
163
- if isinstance (x , np .ndarray ) and x .size :
164
- xravel = x .ravel ()
136
+ """Get the converter interface instance for *x*, or None."""
137
+ if isinstance (x , np .ndarray ):
138
+ # In case x in a masked array, access the underlying data (only its
139
+ # type matters). If x is a regular ndarray, getdata() just returns
140
+ # the array itself.
141
+ x = np .ma .getdata (x ).ravel ()
142
+ try :
143
+ return self [type (x )]
144
+ except KeyError :
165
145
try :
166
- # pass the first value of x that is not masked back to
167
- # get_converter
168
- if not np .all (xravel .mask ):
169
- # some elements are not masked
170
- converter = self .get_converter (
171
- xravel [np .argmin (xravel .mask )])
172
- return converter
173
- except AttributeError :
174
- # not a masked_array
175
- # Make sure we don't recurse forever -- it's possible for
176
- # ndarray subclasses to continue to return subclasses and
177
- # not ever return a non-subclass for a single element.
178
- next_item = xravel [0 ]
179
- if (not isinstance (next_item , np .ndarray ) or
180
- next_item .shape != x .shape ):
181
- converter = self .get_converter (next_item )
182
- return converter
183
-
184
- # If we haven't found a converter yet, try to get the first element
185
- if converter is None :
186
- try :
187
- thisx = safe_first_element (x )
146
+ first = safe_first_element (x )
188
147
except (TypeError , StopIteration ):
189
148
pass
190
149
else :
191
- if classx and classx != getattr (thisx , '__class__' , None ):
192
- converter = self .get_converter (thisx )
193
- return converter
194
-
195
- # DISABLED self._cached[idx] = converter
196
- return converter
150
+ # Avoid infinite recursion for pathological iterables for which
151
+ # indexing returns instances of the same iterable class.
152
+ if type (first ) is not type (x ):
153
+ return self .get_converter (first )
154
+ return None
197
155
198
156
199
157
registry = Registry ()
0 commit comments