Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cd3ed7a

Browse files
authored
Merge pull request #9314 from anntzer/simpler-units
Simplify units.Registry.get_converter.
2 parents 79dad18 + 25cae8e commit cd3ed7a

File tree

1 file changed

+30
-70
lines changed

1 file changed

+30
-70
lines changed

lib/matplotlib/units.py

Lines changed: 30 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ class ConversionError(TypeError):
5555

5656
class 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
"""
6263
def __init__(self, majloc=None, minloc=None,
6364
majfmt=None, minfmt=None, label=None,
@@ -96,8 +97,7 @@ class ConversionInterface(object):
9697
@staticmethod
9798
def 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
"""
102102
return None
103103

@@ -112,19 +112,19 @@ def default_units(x, axis):
112112
def 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
"""
119119
return obj
120120

121121
@staticmethod
122122
def 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
"""
129129
if np.iterable(x):
130130
for thisx in x:
@@ -134,73 +134,33 @@ def is_numlike(x):
134134

135135

136136
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."""
143138

144139
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.
167143
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()
168148
# If there are no elements in x, infer the units from its dtype
169149
if not x.size:
170150
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)
195156
except (TypeError, StopIteration):
196157
pass
197158
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
204164

205165

206166
registry = Registry()

0 commit comments

Comments
 (0)