FIX: Update blitting and drawing on the macosx backend by greglucas · Pull Request #21790 · matplotlib/matplotlib · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions lib/matplotlib/backends/backend_macosx.py
69 changes: 69 additions & 0 deletions lib/matplotlib/tests/test_backends_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,72 @@ def _lazy_headless():
@pytest.mark.backend('QtAgg', skip_on_importerror=True)
def test_lazy_linux_headless():
proc = _run_helper(_lazy_headless, timeout=_test_timeout, MPLBACKEND="")


def _test_number_of_draws_script():
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# animated=True tells matplotlib to only draw the artist when we
# explicitly request it
ln, = ax.plot([0, 1], [1, 2], animated=True)

# make sure the window is raised, but the script keeps going
plt.show(block=False)
plt.pause(0.3)
# Connect to draw_event to count the occurrences
fig.canvas.mpl_connect('draw_event', print)

# get copy of entire figure (everything inside fig.bbox)
# sans animated artist
bg = fig.canvas.copy_from_bbox(fig.bbox)
# draw the animated artist, this uses a cached renderer
ax.draw_artist(ln)
# show the result to the screen
fig.canvas.blit(fig.bbox)

for j in range(10):
# reset the background back in the canvas state, screen unchanged
fig.canvas.restore_region(bg)
# Create a **new** artist here, this is poor usage of blitting
# but good for testing to make sure that this doesn't create
# excessive draws
ln, = ax.plot([0, 1], [1, 2])
# render the artist, updating the canvas state, but not the screen
ax.draw_artist(ln)
# copy the image to the GUI state, but screen might not changed yet
fig.canvas.blit(fig.bbox)
# flush any pending GUI events, re-painting the screen if needed
fig.canvas.flush_events()

# Let the event loop process everything before leaving
plt.pause(0.1)


_blit_backends = _get_testable_interactive_backends()
for param in _blit_backends:
backend = param.values[0]["MPLBACKEND"]
if backend == "gtk3cairo":
# copy_from_bbox only works when rendering to an ImageSurface
param.marks.append(
pytest.mark.skip("gtk3cairo does not support blitting"))
elif backend == "wx":
param.marks.append(
pytest.mark.skip("wx does not support blitting"))


@pytest.mark.parametrize("env", _blit_backends)
# subprocesses can struggle to get the display, so rerun a few times
@pytest.mark.flaky(reruns=4)
def test_blitting_events(env):
proc = _run_helper(_test_number_of_draws_script,
timeout=_test_timeout,
**env)

# Count the number of draw_events we got. We could count some initial
# canvas draws (which vary in number by backend), but the critical
# check here is that it isn't 10 draws, which would be called if
# blitting is not properly implemented
ndraws = proc.stdout.count("DrawEvent")
assert 0 < ndraws < 5
22 changes: 7 additions & 15 deletions src/_macosx.m