@@ -232,7 +232,7 @@ class SliderBase(AxesWidget):
232232 For the slider to remain responsive you must maintain a reference to it.
233233 """
234234 def __init__ (self , ax , orientation , closedmin , closedmax ,
235- valmin , valmax , valfmt , dragging , valstep ):
235+ valmin , valmax , valfmt , dragging , valstep , useblit ):
236236 if ax .name == '3d' :
237237 raise ValueError ('Sliders cannot be added to 3D Axes' )
238238
@@ -265,6 +265,11 @@ def __init__(self, ax, orientation, closedmin, closedmax,
265265 ax .set_axis_off ()
266266 ax .set_navigate (False )
267267
268+ self ._useblit = useblit and self .canvas .supports_blit
269+ if self ._useblit :
270+ self ._background = None
271+ self .connect_event ("draw_event" , self ._clear )
272+
268273 self .connect_event ("button_press_event" , self ._update )
269274 self .connect_event ("button_release_event" , self ._update )
270275 if dragging :
@@ -301,6 +306,18 @@ def reset(self):
301306 if np .any (self .val != self .valinit ):
302307 self .set_val (self .valinit )
303308
309+ def _blit_draw (self , artists ):
310+ if not self .drawon :
311+ return
312+ if not self ._useblit or self ._background is None :
313+ self .ax .figure .canvas .draw_idle ()
314+ return
315+
316+ self .canvas .restore_region (self ._background )
317+ for a in artists :
318+ self .ax .draw_artist (a )
319+ self .canvas .blit (self .ax .get_tightbbox ())
320+
304321
305322class Slider (SliderBase ):
306323 """
@@ -320,7 +337,8 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
320337 closedmin = True , closedmax = True , slidermin = None ,
321338 slidermax = None , dragging = True , valstep = None ,
322339 orientation = 'horizontal' , * , initcolor = 'r' ,
323- track_color = 'lightgrey' , handle_style = None , ** kwargs ):
340+ track_color = 'lightgrey' , handle_style = None , useblit = False ,
341+ ** kwargs ):
324342 """
325343 Parameters
326344 ----------
@@ -390,6 +408,13 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
390408 `~.Line2D` constructor. e.g. ``handle_style = {'style'='x'}`` will
391409 result in ``markerstyle = 'x'``.
392410
411+ useblit : bool, default: False
412+ Use blitting for faster drawing if supported by the backend.
413+ See the tutorial :doc:`/tutorials/advanced/blitting` for details.
414+
415+ If you enable blitting, you should set *valfmt* to a fixed-width
416+ format, or there may be artifacts if the text changes width.
417+
393418 Notes
394419 -----
395420 Additional kwargs are passed on to ``self.poly`` which is the
@@ -398,7 +423,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
398423 ``edgecolor``, ``alpha``, etc.).
399424 """
400425 super ().__init__ (ax , orientation , closedmin , closedmax ,
401- valmin , valmax , valfmt , dragging , valstep )
426+ valmin , valmax , valfmt , dragging , valstep , useblit )
402427
403428 if slidermin is not None and not hasattr (slidermin , 'val' ):
404429 raise ValueError (
@@ -419,6 +444,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
419444 marker_props = {
420445 f'marker{ k } ' : v for k , v in {** defaults , ** handle_style }.items ()
421446 }
447+ animated_style = {'animated' : True } if self ._useblit else {}
422448
423449 if orientation == 'vertical' :
424450 self .track = Rectangle (
@@ -427,11 +453,14 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
427453 facecolor = track_color
428454 )
429455 ax .add_patch (self .track )
430- self .poly = ax .axhspan (valmin , valinit , .25 , .75 , ** kwargs )
456+ self .poly = ax .axhspan (valmin , valinit , .25 , .75 , ** animated_style ,
457+ ** kwargs )
431458 # Drawing a longer line and clipping it to the track avoids
432459 # pixelation-related asymmetries.
433- self .hline = ax .axhline (valinit , 0 , 1 , color = initcolor , lw = 1 ,
434- clip_path = TransformedPatchPath (self .track ))
460+ self ._line = self .hline = ax .axhline (
461+ valinit , 0 , 1 , color = initcolor , lw = 1 ,
462+ clip_path = TransformedPatchPath (self .track ),
463+ ** animated_style )
435464 handleXY = [[0.5 ], [valinit ]]
436465 else :
437466 self .track = Rectangle (
@@ -440,15 +469,19 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
440469 facecolor = track_color
441470 )
442471 ax .add_patch (self .track )
443- self .poly = ax .axvspan (valmin , valinit , .25 , .75 , ** kwargs )
444- self .vline = ax .axvline (valinit , 0 , 1 , color = initcolor , lw = 1 ,
445- clip_path = TransformedPatchPath (self .track ))
472+ self .poly = ax .axvspan (valmin , valinit , .25 , .75 , ** animated_style ,
473+ ** kwargs )
474+ self ._line = self .vline = ax .axvline (
475+ valinit , 0 , 1 , color = initcolor , lw = 1 ,
476+ clip_path = TransformedPatchPath (self .track ),
477+ ** animated_style )
446478 handleXY = [[valinit ], [0.5 ]]
447479 self ._handle , = ax .plot (
448480 * handleXY ,
449481 "o" ,
450482 ** marker_props ,
451- clip_on = False
483+ clip_on = False ,
484+ ** animated_style
452485 )
453486
454487 if orientation == 'vertical' :
@@ -459,7 +492,8 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
459492 self .valtext = ax .text (0.5 , - 0.02 , self ._format (valinit ),
460493 transform = ax .transAxes ,
461494 verticalalignment = 'top' ,
462- horizontalalignment = 'center' )
495+ horizontalalignment = 'center' ,
496+ ** animated_style )
463497 else :
464498 self .label = ax .text (- 0.02 , 0.5 , label , transform = ax .transAxes ,
465499 verticalalignment = 'center' ,
@@ -468,10 +502,21 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
468502 self .valtext = ax .text (1.02 , 0.5 , self ._format (valinit ),
469503 transform = ax .transAxes ,
470504 verticalalignment = 'center' ,
471- horizontalalignment = 'left' )
505+ horizontalalignment = 'left' ,
506+ ** animated_style )
472507
473508 self .set_val (valinit )
474509
510+ def _clear (self , event ):
511+ """Internal event handler to refresh the blitting background."""
512+ if self .ignore (event ):
513+ return
514+ area = self .ax .get_tightbbox ()
515+ self ._background = self .canvas .copy_from_bbox (area )
516+ for a in artists :
517+ self .ax .draw_artist (a )
518+ self .ax .figure .canvas .blit (area )
519+
475520 def _value_in_bounds (self , val ):
476521 """Makes sure *val* is with given bounds."""
477522 val = self ._stepped_value (val )
@@ -549,8 +594,7 @@ def set_val(self, val):
549594 self ._handle .set_xdata ([val ])
550595 self .poly .xy = xy
551596 self .valtext .set_text (self ._format (val ))
552- if self .drawon :
553- self .ax .figure .canvas .draw_idle ()
597+ self ._blit_draw ([self .poly , self ._line , self .valtext , self ._handle ])
554598 self .val = val
555599 if self .eventson :
556600 self ._observers .process ('changed' , val )
@@ -603,6 +647,7 @@ def __init__(
603647 orientation = "horizontal" ,
604648 track_color = 'lightgrey' ,
605649 handle_style = None ,
650+ useblit = False ,
606651 ** kwargs ,
607652 ):
608653 """
@@ -662,6 +707,13 @@ def __init__(
662707 `~.Line2D` constructor. e.g. ``handle_style = {'style'='x'}`` will
663708 result in ``markerstyle = 'x'``.
664709
710+ useblit : bool, default: False
711+ Use blitting for faster drawing if supported by the backend.
712+ See the tutorial :doc:`/tutorials/advanced/blitting` for details.
713+
714+ If you enable blitting, you should set *valfmt* to a fixed-width
715+ format, or there may be artifacts if the text changes width.
716+
665717 Notes
666718 -----
667719 Additional kwargs are passed on to ``self.poly`` which is the
@@ -670,7 +722,7 @@ def __init__(
670722 ``edgecolor``, ``alpha``, etc.).
671723 """
672724 super ().__init__ (ax , orientation , closedmin , closedmax ,
673- valmin , valmax , valfmt , dragging , valstep )
725+ valmin , valmax , valfmt , dragging , valstep , useblit )
674726
675727 # Set a value to allow _value_in_bounds() to work.
676728 self .val = [valmin , valmax ]
@@ -689,6 +741,7 @@ def __init__(
689741 marker_props = {
690742 f'marker{ k } ' : v for k , v in {** defaults , ** handle_style }.items ()
691743 }
744+ animated_style = {'animated' : True } if self ._useblit else {}
692745
693746 if orientation == "vertical" :
694747 self .track = Rectangle (
@@ -710,7 +763,7 @@ def __init__(
710763 poly_transform = self .ax .get_xaxis_transform (which = "grid" )
711764 handleXY_1 = [valinit [0 ], .5 ]
712765 handleXY_2 = [valinit [1 ], .5 ]
713- self .poly = Polygon (np .zeros ([5 , 2 ]), ** kwargs )
766+ self .poly = Polygon (np .zeros ([5 , 2 ]), ** animated_style , ** kwargs )
714767 self ._update_selection_poly (* valinit )
715768 self .poly .set_transform (poly_transform )
716769 self .poly .get_path ()._interpolation_steps = 100
@@ -721,13 +774,15 @@ def __init__(
721774 * handleXY_1 ,
722775 "o" ,
723776 ** marker_props ,
724- clip_on = False
777+ clip_on = False ,
778+ ** animated_style
725779 )[0 ],
726780 ax .plot (
727781 * handleXY_2 ,
728782 "o" ,
729783 ** marker_props ,
730- clip_on = False
784+ clip_on = False ,
785+ ** animated_style
731786 )[0 ]
732787 ]
733788
@@ -748,6 +803,7 @@ def __init__(
748803 transform = ax .transAxes ,
749804 verticalalignment = "top" ,
750805 horizontalalignment = "center" ,
806+ ** animated_style
751807 )
752808 else :
753809 self .label = ax .text (
@@ -766,11 +822,21 @@ def __init__(
766822 transform = ax .transAxes ,
767823 verticalalignment = "center" ,
768824 horizontalalignment = "left" ,
825+ ** animated_style
769826 )
770827
771828 self ._active_handle = None
772829 self .set_val (valinit )
773830
831+ def _clear (self , event ):
832+ """Internal event handler to refresh the blitting background."""
833+ if self .ignore (event ):
834+ return
835+ self ._background = self .canvas .copy_from_bbox (self .ax .get_tightbbox ())
836+ for a in artists :
837+ self .ax .draw_artist (a )
838+ self .canvas .blit (area )
839+
774840 def _update_selection_poly (self , vmin , vmax ):
775841 """
776842 Update the vertices of the *self.poly* slider in-place
@@ -931,8 +997,7 @@ def set_val(self, val):
931997
932998 self .valtext .set_text (self ._format ((vmin , vmax )))
933999
934- if self .drawon :
935- self .ax .figure .canvas .draw_idle ()
1000+ self ._blit_draw ([self .poly , self .valtext , * self ._handles ])
9361001 self .val = (vmin , vmax )
9371002 if self .eventson :
9381003 self ._observers .process ("changed" , (vmin , vmax ))
0 commit comments