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

Skip to content

Commit a611314

Browse files
committed
Simplify units.Registry.get_converter.
The caching of the converter was disabled 10 years ago (be73ef4) and is unlikely to ever work as the correct converter for ndarrays depends on the type of the contents, not on the container, so just drop the cache-related code. When a masked array is passed, it's OK to just get the first underlying data, even if it is masked (as it should have the same type as the unmasked entries), for the purpose of getting the converter.
1 parent cd0de0b commit a611314

File tree

1 file changed

+27
-72
lines changed

1 file changed

+27
-72
lines changed

lib/matplotlib/units.py

Lines changed: 27 additions & 72 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,28 @@ 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."""
167141
if isinstance(x, np.ndarray):
168-
# If there are no elements in x, infer the units from its dtype
169-
if not x.size:
170-
return self.get_converter(np.array([0], dtype=x.dtype))
171-
xravel = x.ravel()
142+
# In case x in a masked array, access the underlying data (only its
143+
# type matters). If x is a regular ndarray, getdata() just returns
144+
# the array itself.
145+
x = np.ma.getdata(x).ravel()
146+
try:
147+
return self[type(x)]
148+
except KeyError:
172149
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)
150+
first = safe_first_element(x)
195151
except (TypeError, StopIteration):
196152
pass
197153
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
154+
# Avoid infinite recursion for pathological iterables for which
155+
# indexing returns instances of the same iterable class.
156+
if type(first) is not type(x):
157+
return self.get_converter(first)
158+
return None
204159

205160

206161
registry = Registry()

0 commit comments

Comments
 (0)