@@ -232,7 +232,7 @@ class SliderBase(AxesWidget):
232
232
For the slider to remain responsive you must maintain a reference to it.
233
233
"""
234
234
def __init__ (self , ax , orientation , closedmin , closedmax ,
235
- valmin , valmax , valfmt , dragging , valstep ):
235
+ valmin , valmax , valfmt , dragging , valstep , useblit ):
236
236
if ax .name == '3d' :
237
237
raise ValueError ('Sliders cannot be added to 3D Axes' )
238
238
@@ -265,6 +265,11 @@ def __init__(self, ax, orientation, closedmin, closedmax,
265
265
ax .set_axis_off ()
266
266
ax .set_navigate (False )
267
267
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
+
268
273
self .connect_event ("button_press_event" , self ._update )
269
274
self .connect_event ("button_release_event" , self ._update )
270
275
if dragging :
@@ -301,6 +306,18 @@ def reset(self):
301
306
if np .any (self .val != self .valinit ):
302
307
self .set_val (self .valinit )
303
308
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
+
304
321
305
322
class Slider (SliderBase ):
306
323
"""
@@ -320,7 +337,8 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
320
337
closedmin = True , closedmax = True , slidermin = None ,
321
338
slidermax = None , dragging = True , valstep = None ,
322
339
orientation = 'horizontal' , * , initcolor = 'r' ,
323
- track_color = 'lightgrey' , handle_style = None , ** kwargs ):
340
+ track_color = 'lightgrey' , handle_style = None , useblit = False ,
341
+ ** kwargs ):
324
342
"""
325
343
Parameters
326
344
----------
@@ -390,6 +408,13 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
390
408
`~.Line2D` constructor. e.g. ``handle_style = {'style'='x'}`` will
391
409
result in ``markerstyle = 'x'``.
392
410
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
+
393
418
Notes
394
419
-----
395
420
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,
398
423
``edgecolor``, ``alpha``, etc.).
399
424
"""
400
425
super ().__init__ (ax , orientation , closedmin , closedmax ,
401
- valmin , valmax , valfmt , dragging , valstep )
426
+ valmin , valmax , valfmt , dragging , valstep , useblit )
402
427
403
428
if slidermin is not None and not hasattr (slidermin , 'val' ):
404
429
raise ValueError (
@@ -419,6 +444,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
419
444
marker_props = {
420
445
f'marker{ k } ' : v for k , v in {** defaults , ** handle_style }.items ()
421
446
}
447
+ animated_style = {'animated' : True } if self ._useblit else {}
422
448
423
449
if orientation == 'vertical' :
424
450
self .track = Rectangle (
@@ -427,11 +453,14 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
427
453
facecolor = track_color
428
454
)
429
455
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 )
431
458
# Drawing a longer line and clipping it to the track avoids
432
459
# 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 )
435
464
handleXY = [[0.5 ], [valinit ]]
436
465
else :
437
466
self .track = Rectangle (
@@ -440,15 +469,19 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
440
469
facecolor = track_color
441
470
)
442
471
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 )
446
478
handleXY = [[valinit ], [0.5 ]]
447
479
self ._handle , = ax .plot (
448
480
* handleXY ,
449
481
"o" ,
450
482
** marker_props ,
451
- clip_on = False
483
+ clip_on = False ,
484
+ ** animated_style
452
485
)
453
486
454
487
if orientation == 'vertical' :
@@ -459,7 +492,8 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
459
492
self .valtext = ax .text (0.5 , - 0.02 , self ._format (valinit ),
460
493
transform = ax .transAxes ,
461
494
verticalalignment = 'top' ,
462
- horizontalalignment = 'center' )
495
+ horizontalalignment = 'center' ,
496
+ ** animated_style )
463
497
else :
464
498
self .label = ax .text (- 0.02 , 0.5 , label , transform = ax .transAxes ,
465
499
verticalalignment = 'center' ,
@@ -468,10 +502,22 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
468
502
self .valtext = ax .text (1.02 , 0.5 , self ._format (valinit ),
469
503
transform = ax .transAxes ,
470
504
verticalalignment = 'center' ,
471
- horizontalalignment = 'left' )
505
+ horizontalalignment = 'left' ,
506
+ ** animated_style )
472
507
473
508
self .set_val (valinit )
474
509
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
+ artists = [self .poly , self ._line , self .valtext , self ._handle ]
517
+ for a in artists :
518
+ self .ax .draw_artist (a )
519
+ self .canvas .blit (self .ax .get_tightbbox ())
520
+
475
521
def _value_in_bounds (self , val ):
476
522
"""Makes sure *val* is with given bounds."""
477
523
val = self ._stepped_value (val )
@@ -549,8 +595,7 @@ def set_val(self, val):
549
595
self ._handle .set_xdata ([val ])
550
596
self .poly .xy = xy
551
597
self .valtext .set_text (self ._format (val ))
552
- if self .drawon :
553
- self .ax .figure .canvas .draw_idle ()
598
+ self ._blit_draw ([self .poly , self ._line , self .valtext , self ._handle ])
554
599
self .val = val
555
600
if self .eventson :
556
601
self ._observers .process ('changed' , val )
@@ -603,6 +648,7 @@ def __init__(
603
648
orientation = "horizontal" ,
604
649
track_color = 'lightgrey' ,
605
650
handle_style = None ,
651
+ useblit = False ,
606
652
** kwargs ,
607
653
):
608
654
"""
@@ -662,6 +708,13 @@ def __init__(
662
708
`~.Line2D` constructor. e.g. ``handle_style = {'style'='x'}`` will
663
709
result in ``markerstyle = 'x'``.
664
710
711
+ useblit : bool, default: False
712
+ Use blitting for faster drawing if supported by the backend.
713
+ See the tutorial :doc:`/tutorials/advanced/blitting` for details.
714
+
715
+ If you enable blitting, you should set *valfmt* to a fixed-width
716
+ format, or there may be artifacts if the text changes width.
717
+
665
718
Notes
666
719
-----
667
720
Additional kwargs are passed on to ``self.poly`` which is the
@@ -670,7 +723,7 @@ def __init__(
670
723
``edgecolor``, ``alpha``, etc.).
671
724
"""
672
725
super ().__init__ (ax , orientation , closedmin , closedmax ,
673
- valmin , valmax , valfmt , dragging , valstep )
726
+ valmin , valmax , valfmt , dragging , valstep , useblit )
674
727
675
728
# Set a value to allow _value_in_bounds() to work.
676
729
self .val = [valmin , valmax ]
@@ -689,6 +742,7 @@ def __init__(
689
742
marker_props = {
690
743
f'marker{ k } ' : v for k , v in {** defaults , ** handle_style }.items ()
691
744
}
745
+ animated_style = {'animated' : True } if self ._useblit else {}
692
746
693
747
if orientation == "vertical" :
694
748
self .track = Rectangle (
@@ -710,7 +764,7 @@ def __init__(
710
764
poly_transform = self .ax .get_xaxis_transform (which = "grid" )
711
765
handleXY_1 = [valinit [0 ], .5 ]
712
766
handleXY_2 = [valinit [1 ], .5 ]
713
- self .poly = Polygon (np .zeros ([5 , 2 ]), ** kwargs )
767
+ self .poly = Polygon (np .zeros ([5 , 2 ]), ** animated_style , ** kwargs )
714
768
self ._update_selection_poly (* valinit )
715
769
self .poly .set_transform (poly_transform )
716
770
self .poly .get_path ()._interpolation_steps = 100
@@ -721,13 +775,15 @@ def __init__(
721
775
* handleXY_1 ,
722
776
"o" ,
723
777
** marker_props ,
724
- clip_on = False
778
+ clip_on = False ,
779
+ ** animated_style
725
780
)[0 ],
726
781
ax .plot (
727
782
* handleXY_2 ,
728
783
"o" ,
729
784
** marker_props ,
730
- clip_on = False
785
+ clip_on = False ,
786
+ ** animated_style
731
787
)[0 ]
732
788
]
733
789
@@ -748,6 +804,7 @@ def __init__(
748
804
transform = ax .transAxes ,
749
805
verticalalignment = "top" ,
750
806
horizontalalignment = "center" ,
807
+ ** animated_style
751
808
)
752
809
else :
753
810
self .label = ax .text (
@@ -766,11 +823,22 @@ def __init__(
766
823
transform = ax .transAxes ,
767
824
verticalalignment = "center" ,
768
825
horizontalalignment = "left" ,
826
+ ** animated_style
769
827
)
770
828
771
829
self ._active_handle = None
772
830
self .set_val (valinit )
773
831
832
+ def _clear (self , event ):
833
+ """Internal event handler to refresh the blitting background."""
834
+ if self .ignore (event ):
835
+ return
836
+ artists = [self .poly , self .valtext , * self ._handles ]
837
+ self ._background = self .canvas .copy_from_bbox (self .ax .get_tightbbox ())
838
+ for a in artists :
839
+ self .ax .draw_artist (a )
840
+ self .canvas .blit (self .ax .get_tightbbox ())
841
+
774
842
def _update_selection_poly (self , vmin , vmax ):
775
843
"""
776
844
Update the vertices of the *self.poly* slider in-place
@@ -931,8 +999,7 @@ def set_val(self, val):
931
999
932
1000
self .valtext .set_text (self ._format ((vmin , vmax )))
933
1001
934
- if self .drawon :
935
- self .ax .figure .canvas .draw_idle ()
1002
+ self ._blit_draw ([self .poly , self .valtext , * self ._handles ])
936
1003
self .val = (vmin , vmax )
937
1004
if self .eventson :
938
1005
self ._observers .process ("changed" , (vmin , vmax ))
0 commit comments