Skip to content

Commit 8536c7a

Browse files
committed
TST: Test number of draw events from a blitted animation
This adds a test that only one draw_event is called when using blitting with animations. There will be more than one draw_event if blitting is not implemented properly and instead calls a full redraw of the canvas each time.
1 parent e29b6f2 commit 8536c7a

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

lib/matplotlib/tests/test_backends_interactive.py

+86
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,89 @@ def _lazy_headless():
413413
@pytest.mark.backend('QtAgg', skip_on_importerror=True)
414414
def 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.1)
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+
# if env["MPLBACKEND"] == "macosx":
476+
# if toolbar == "toolmanager":
477+
# pytest.skip("toolmanager is not implemented for macosx.")
478+
# proc = _run_helper(_test_interactive_impl,
479+
# timeout=_test_timeout,
480+
# **env)
481+
482+
# assert proc.stdout.count("CloseEvent") == 1
483+
484+
# proc = subprocess.run(
485+
# [sys.executable, "-c",
486+
# inspect.getsource(_test_number_of_draws_script)
487+
# + "\n_test_number_of_draws_script()"],
488+
# env={**os.environ, "SOURCE_DATE_EPOCH": "0", **env},
489+
# timeout=_test_timeout,
490+
# stdout=subprocess.PIPE, universal_newlines=True)
491+
492+
proc = _run_helper(_test_number_of_draws_script,
493+
timeout=_test_timeout,
494+
**env)
495+
496+
# Count the number of draw_events we got. We could count some initial
497+
# canvas draws (which vary in number by backend), but the critical
498+
# check here is that it isn't 10 draws, which would be called if
499+
# blitting is not properly implemented
500+
ndraws = proc.stdout.count("DrawEvent")
501+
assert 0 < ndraws < 5

0 commit comments

Comments
 (0)