@@ -598,7 +598,7 @@ def recache(self, always=False):
598
598
if always or self ._invalidx :
599
599
xconv = self .convert_xunits (self ._xorig )
600
600
if ma .isMaskedArray (self ._xorig ):
601
- x = ma .asarray (xconv , np .float_ )
601
+ x = ma .asarray (xconv , np .float_ ). filled ( np . nan )
602
602
else :
603
603
x = np .asarray (xconv , np .float_ )
604
604
x = x .ravel ()
@@ -607,7 +607,7 @@ def recache(self, always=False):
607
607
if always or self ._invalidy :
608
608
yconv = self .convert_yunits (self ._yorig )
609
609
if ma .isMaskedArray (self ._yorig ):
610
- y = ma .asarray (yconv , np .float_ )
610
+ y = ma .asarray (yconv , np .float_ ). filled ( np . nan )
611
611
else :
612
612
y = np .asarray (yconv , np .float_ )
613
613
y = y .ravel ()
@@ -622,23 +622,29 @@ def recache(self, always=False):
622
622
if len (x ) != len (y ):
623
623
raise RuntimeError ('xdata and ydata must be the same length' )
624
624
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
627
628
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 )
632
629
self ._x = self ._xy [:, 0 ] # just a view
633
630
self ._y = self ._xy [:, 1 ] # just a view
634
631
635
632
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
637
634
self .axes .name == 'rectilinear' and
638
635
self .axes .get_xscale () == 'linear' and
639
636
self ._markevery is None and
640
637
self .get_clip_on () is True ):
641
638
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
+
642
648
if hasattr (self , '_path' ):
643
649
interpolation_steps = self ._path ._interpolation_steps
644
650
else :
@@ -650,13 +656,14 @@ def recache(self, always=False):
650
656
651
657
def _transform_path (self , subslice = None ):
652
658
"""
653
- Puts a TransformedPath instance at self._transformed_path,
659
+ Puts a TransformedPath instance at self._transformed_path;
654
660
all invalidation of the transform is then handled by the
655
661
TransformedPath instance.
656
662
"""
657
663
# Masked arrays are now handled by the Path class itself
658
664
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 )
660
667
else :
661
668
_path = self ._path
662
669
self ._transformed_path = TransformedPath (_path , self .get_transform ())
@@ -682,10 +689,11 @@ def set_transform(self, t):
682
689
self .stale = True
683
690
684
691
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.
686
694
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
689
697
690
698
@allow_rasterization
691
699
def draw (self , renderer ):
@@ -697,13 +705,14 @@ def draw(self, renderer):
697
705
self .recache ()
698
706
self .ind_offset = 0 # Needed for contains() method.
699
707
if self ._subslice and self .axes :
700
- # Need to handle monotonically decreasing case also...
701
708
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' )
704
711
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 )
707
716
708
717
transf_path = self ._get_transformed_path ()
709
718
0 commit comments