@@ -413,3 +413,72 @@ def _lazy_headless():
413413@pytest .mark .backend ('QtAgg' , skip_on_importerror = True )
414414def test_lazy_linux_headless ():
415415 proc = _run_helper (_lazy_headless , timeout = _test_timeout , MPLBACKEND = "" )
416+
417+
418+ def _test_number_of_draws_script ():
419+ import matplotlib .pyplot as plt
420+
421+ fig , ax = plt .subplots ()
422+
423+ # animated=True tells matplotlib to only draw the artist when we
424+ # explicitly request it
425+ ln , = ax .plot ([0 , 1 ], [1 , 2 ], animated = True )
426+
427+ # make sure the window is raised, but the script keeps going
428+ plt .show (block = False )
429+ plt .pause (0.3 )
430+ # Connect to draw_event to count the occurrences
431+ fig .canvas .mpl_connect ('draw_event' , print )
432+
433+ # get copy of entire figure (everything inside fig.bbox)
434+ # sans animated artist
435+ bg = fig .canvas .copy_from_bbox (fig .bbox )
436+ # draw the animated artist, this uses a cached renderer
437+ ax .draw_artist (ln )
438+ # show the result to the screen
439+ fig .canvas .blit (fig .bbox )
440+
441+ for j in range (10 ):
442+ # reset the background back in the canvas state, screen unchanged
443+ fig .canvas .restore_region (bg )
444+ # Create a **new** artist here, this is poor usage of blitting
445+ # but good for testing to make sure that this doesn't create
446+ # excessive draws
447+ ln , = ax .plot ([0 , 1 ], [1 , 2 ])
448+ # render the artist, updating the canvas state, but not the screen
449+ ax .draw_artist (ln )
450+ # copy the image to the GUI state, but screen might not changed yet
451+ fig .canvas .blit (fig .bbox )
452+ # flush any pending GUI events, re-painting the screen if needed
453+ fig .canvas .flush_events ()
454+
455+ # Let the event loop process everything before leaving
456+ plt .pause (0.1 )
457+
458+
459+ _blit_backends = _get_testable_interactive_backends ()
460+ for param in _blit_backends :
461+ backend = param .values [0 ]["MPLBACKEND" ]
462+ if backend == "gtk3cairo" :
463+ # copy_from_bbox only works when rendering to an ImageSurface
464+ param .marks .append (
465+ pytest .mark .skip ("gtk3cairo does not support blitting" ))
466+ elif backend == "wx" :
467+ param .marks .append (
468+ pytest .mark .skip ("wx does not support blitting" ))
469+
470+
471+ @pytest .mark .parametrize ("env" , _blit_backends )
472+ # subprocesses can struggle to get the display, so rerun a few times
473+ @pytest .mark .flaky (reruns = 4 )
474+ def test_blitting_events (env ):
475+ proc = _run_helper (_test_number_of_draws_script ,
476+ timeout = _test_timeout ,
477+ ** env )
478+
479+ # Count the number of draw_events we got. We could count some initial
480+ # canvas draws (which vary in number by backend), but the critical
481+ # check here is that it isn't 10 draws, which would be called if
482+ # blitting is not properly implemented
483+ ndraws = proc .stdout .count ("DrawEvent" )
484+ assert 0 < ndraws < 5
0 commit comments