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

Skip to content

Commit 3c2c037

Browse files
committed
support subslicing when x is masked or has nans
1 parent b7ef642 commit 3c2c037

File tree

1 file changed

+28
-19
lines changed

1 file changed

+28
-19
lines changed

lib/matplotlib/lines.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ def recache(self, always=False):
598598
if always or self._invalidx:
599599
xconv = self.convert_xunits(self._xorig)
600600
if ma.isMaskedArray(self._xorig):
601-
x = ma.asarray(xconv, np.float_)
601+
x = ma.asarray(xconv, np.float_).filled(np.nan)
602602
else:
603603
x = np.asarray(xconv, np.float_)
604604
x = x.ravel()
@@ -607,7 +607,7 @@ def recache(self, always=False):
607607
if always or self._invalidy:
608608
yconv = self.convert_yunits(self._yorig)
609609
if ma.isMaskedArray(self._yorig):
610-
y = ma.asarray(yconv, np.float_)
610+
y = ma.asarray(yconv, np.float_).filled(np.nan)
611611
else:
612612
y = np.asarray(yconv, np.float_)
613613
y = y.ravel()
@@ -622,23 +622,29 @@ def recache(self, always=False):
622622
if len(x) != len(y):
623623
raise RuntimeError('xdata and ydata must be the same length')
624624

625-
x = x.reshape((len(x), 1))
626-
y = y.reshape((len(y), 1))
625+
self._xy = np.empty((len(x), 2), dtype=np.float_)
626+
self._xy[:, 0] = x
627+
self._xy[:, 1] = y
627628

628-
if ma.isMaskedArray(x) or ma.isMaskedArray(y):
629-
self._xy = ma.concatenate((x, y), 1)
630-
else:
631-
self._xy = np.concatenate((x, y), 1)
632629
self._x = self._xy[:, 0] # just a view
633630
self._y = self._xy[:, 1] # just a view
634631

635632
self._subslice = False
636-
if (self.axes and len(x) > 100 and self._is_sorted(x) and
633+
if (self.axes and len(x) > 1000 and self._is_sorted(x) and
637634
self.axes.name == 'rectilinear' and
638635
self.axes.get_xscale() == 'linear' and
639636
self._markevery is None and
640637
self.get_clip_on() is True):
641638
self._subslice = True
639+
nanmask = np.isnan(x)
640+
if nanmask.any():
641+
self._x_filled = self._x.copy()
642+
indices = np.arange(len(x))
643+
self._x_filled[nanmask] = np.interp(indices[nanmask],
644+
indices[~nanmask], self._x[~nanmask])
645+
else:
646+
self._x_filled = self._x
647+
642648
if hasattr(self, '_path'):
643649
interpolation_steps = self._path._interpolation_steps
644650
else:
@@ -650,13 +656,14 @@ def recache(self, always=False):
650656

651657
def _transform_path(self, subslice=None):
652658
"""
653-
Puts a TransformedPath instance at self._transformed_path,
659+
Puts a TransformedPath instance at self._transformed_path;
654660
all invalidation of the transform is then handled by the
655661
TransformedPath instance.
656662
"""
657663
# Masked arrays are now handled by the Path class itself
658664
if subslice is not None:
659-
_path = Path(self._xy[subslice, :])
665+
_steps = self._path._interpolation_steps
666+
_path = Path(self._xy[subslice, :], _interpolation_steps=_steps)
660667
else:
661668
_path = self._path
662669
self._transformed_path = TransformedPath(_path, self.get_transform())
@@ -682,10 +689,11 @@ def set_transform(self, t):
682689
self.stale = True
683690

684691
def _is_sorted(self, x):
685-
"""return true if x is sorted"""
692+
"""return True if x is sorted in ascending order"""
693+
# We don't handle the monotonically decreasing case.
686694
if len(x) < 2:
687-
return 1
688-
return np.amin(x[1:] - x[0:-1]) >= 0
695+
return True
696+
return np.nanmin(x[1:] - x[:-1]) >= 0
689697

690698
@allow_rasterization
691699
def draw(self, renderer):
@@ -697,13 +705,14 @@ def draw(self, renderer):
697705
self.recache()
698706
self.ind_offset = 0 # Needed for contains() method.
699707
if self._subslice and self.axes:
700-
# Need to handle monotonically decreasing case also...
701708
x0, x1 = self.axes.get_xbound()
702-
i0, = self._x.searchsorted([x0], 'left')
703-
i1, = self._x.searchsorted([x1], 'right')
709+
i0, = self._x_filled.searchsorted([x0], 'left')
710+
i1, = self._x_filled.searchsorted([x1], 'right')
704711
subslice = slice(max(i0 - 1, 0), i1 + 1)
705-
self.ind_offset = subslice.start
706-
self._transform_path(subslice)
712+
# Don't remake the Path unless it will be sufficiently smaller.
713+
if subslice.start > 100 or len(self._x) - subslice.stop > 100:
714+
self.ind_offset = subslice.start
715+
self._transform_path(subslice)
707716

708717
transf_path = self._get_transformed_path()
709718

0 commit comments

Comments
 (0)