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

Skip to content

Commit d5adae3

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 83d614b commit d5adae3

File tree

1 file changed

+28
-66
lines changed

1 file changed

+28
-66
lines changed

lib/matplotlib/units.py

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ def default_units(x, axis):
5252

5353
class AxisInfo(object):
5454
"""
55-
Information to support default axis labeling, tick labeling, and
56-
default limits. An instance of this class must be returned by
57-
:meth:`ConversionInterface.axisinfo`.
55+
Information to support default axis labeling, tick labeling, and limits.
56+
57+
An instance of this class must be returned by
58+
`ConversionInterface.axisinfo`.
5859
"""
5960
def __init__(self, majloc=None, minloc=None,
6061
majfmt=None, minfmt=None, label=None,
@@ -93,8 +94,7 @@ class ConversionInterface(object):
9394
@staticmethod
9495
def axisinfo(unit, axis):
9596
"""
96-
Return an `~units.AxisInfo` instance for the axis with the
97-
specified units.
97+
Return an `~units.AxisInfo` for the axis with the specified units.
9898
"""
9999
return None
100100

@@ -109,19 +109,19 @@ def default_units(x, axis):
109109
def convert(obj, unit, axis):
110110
"""
111111
Convert *obj* using *unit* for the specified *axis*.
112-
If *obj* is a sequence, return the converted sequence.
113-
The output must be a sequence of scalars that can be used by the numpy
114-
array layer.
112+
113+
If *obj* is a sequence, return the converted sequence. The output must
114+
be a sequence of scalars that can be used by the numpy array layer.
115115
"""
116116
return obj
117117

118118
@staticmethod
119119
def is_numlike(x):
120120
"""
121-
The Matplotlib datalim, autoscaling, locators etc work with
122-
scalars which are the units converted to floats given the
123-
current unit. The converter may be passed these floats, or
124-
arrays of them, even when units are set.
121+
The Matplotlib datalim, autoscaling, locators etc work with scalars
122+
which are the units converted to floats given the current unit. The
123+
converter may be passed these floats, or arrays of them, even when
124+
units are set.
125125
"""
126126
if iterable(x):
127127
for thisx in x:
@@ -131,66 +131,28 @@ def is_numlike(x):
131131

132132

133133
class Registry(dict):
134-
"""
135-
A register that maps types to conversion interfaces.
136-
"""
137-
def __init__(self):
138-
dict.__init__(self)
139-
self._cached = {}
134+
"""Register types with conversion interface."""
140135

141136
def get_converter(self, x):
142-
"""
143-
Get the converter for data that has the same type as *x*. If no
144-
converters are registered for *x*, returns ``None``.
145-
"""
146-
147-
if not len(self):
148-
return None # nothing registered
149-
# DISABLED idx = id(x)
150-
# DISABLED cached = self._cached.get(idx)
151-
# DISABLED if cached is not None: return cached
152-
153-
converter = None
154-
classx = getattr(x, '__class__', None)
155-
156-
if classx is not None:
157-
converter = self.get(classx)
158-
159-
# If x is an array, look inside the array for data with units
160-
if isinstance(x, np.ndarray) and x.size:
161-
xravel = x.ravel()
137+
"""Get the converter interface instance for *x*, or None."""
138+
if isinstance(x, np.ndarray):
139+
# In case x in a masked array, access the underlying data (only its
140+
# type matters). If x is a regular ndarray, getdata() just returns
141+
# the array itself.
142+
x = np.ma.getdata(x).ravel()
143+
try:
144+
return self[type(x)]
145+
except KeyError:
162146
try:
163-
# pass the first value of x that is not masked back to
164-
# get_converter
165-
if not np.all(xravel.mask):
166-
# some elements are not masked
167-
converter = self.get_converter(
168-
xravel[np.argmin(xravel.mask)])
169-
return converter
170-
except AttributeError:
171-
# not a masked_array
172-
# Make sure we don't recurse forever -- it's possible for
173-
# ndarray subclasses to continue to return subclasses and
174-
# not ever return a non-subclass for a single element.
175-
next_item = xravel[0]
176-
if (not isinstance(next_item, np.ndarray) or
177-
next_item.shape != x.shape):
178-
converter = self.get_converter(next_item)
179-
return converter
180-
181-
# If we haven't found a converter yet, try to get the first element
182-
if converter is None:
183-
try:
184-
thisx = safe_first_element(x)
147+
first = safe_first_element(x)
185148
except (TypeError, StopIteration):
186149
pass
187150
else:
188-
if classx and classx != getattr(thisx, '__class__', None):
189-
converter = self.get_converter(thisx)
190-
return converter
191-
192-
# DISABLED self._cached[idx] = converter
193-
return converter
151+
# Avoid infinite recursion for pathological iterables for which
152+
# indexing returns instances of the same iterable class.
153+
if type(first) is not type(x):
154+
return self.get_converter(first)
155+
return None
194156

195157

196158
registry = Registry()

0 commit comments

Comments
 (0)