-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Implement a consistent behavior in TkAgg backend for bad blit bbox #20887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a consistent behavior in TkAgg backend for bad blit bbox #20887
Conversation
I think it would be nice to spec exactly what is the expected rounding/clipping behavior expected by blit(); for mplcairo I basically had to reverse engineer what I think is the correct behavior (implemented at https://github.com/matplotlib/mplcairo/blob/9ad105795ef106c74fe37a165b96ca9b02e204ac/src/_mplcairo.cpp#L1531). |
Perhaps in such a spec, instead of simply clipping the bbox, we could inspect if the rounding was a round-up from e.g. width+eps to width+1 where 0<eps<1. it is not actually a problem on the lower limits, right? That way more bad bboxes could be identified. |
e13a071
to
e644934
Compare
After stewing on this for a few months, I feel like the best option is to just merge this patch and make a new issue about harmonizing the blit spec across backends. |
Sorry for letting this wait for so long. I didn't realize that there are actually a few different points here.
Intuitively, I think I would rather error out on invalid inputs, but I understand that this erroring out currently occurs at an uncatchable place, and having this error out consistently across backends is a bit of work; so, at least as a stopgap, I agree with silently ignorining such bboxes for now (but perhaps this may get revisited in the future). |
e644934
to
32e0474
Compare
PR Summary
This PR seeks to make the failure modes more consistent and manageable when blitting on the
TkAgg
backend. Draft for now because I don't think it is release critical and some feedback is needed on design choices.Background
The thread safety changes of #18565 interact a bit awkwardly with the memory safety changes of #14478, namely when
_tkagg.blit
raises, it pops directly out of the tkintermainloop
call and poisons the current instance of tkapp so that pumping the event loop always raises theValueError
forever. This isn't a big deal for bad values ofcomp_rule
orphotoimage
since those are matplotlib's responsibilities, however as a user-facing API this prevents a client application from gracefully handling bad bboxes; they are basically fatal.Why, if this is so bad, did nobody notice? In #14461 the bbox limits are clipped to a mostly-safe range, so only very bad bboxes that fall entirely outside the canvas trigger the issue. (And only my app is crazy enough to generate such bboxes 🤦)
Proposed fix(es)
Extend safe-clipping
The initial commit in this PR makes the most minimal possible change to existing behavior, extending the safe-clipping to boxes outside the canvas; they are simply dropped, and with a fast path optimization to boot. This way if
ValueErrors
are generated, they are 100% our fault. Theif
expression comes from the check in_tkagg.cpp
but stripping the rules that are redundant to the clipping logic. The disadvantage is that the only way a user knows that their bbox is being clipped is by weird visual artifacts.Raise aggressively
An alternative fix is to promote the
_tkagg.cpp
check into the first lines of_backend_tk.blit
:This
raise
is now catchable and the check inside_tkagg.blit
is redundant (though it is super cheap so it should remain in both places). Adding tests for this would finally cover this branch of the if statement. Also ALL bad bbox blits are errors now.I see two disadvantages to this alternative. The integer conversion has to be different (truncated) so that full-canvas blits are not liable to pick up an extra pixel and error out, however this floor rounding behavior is consistent with other backends. Some user code that worked by silently clipping will now raise.
Open questions
Should we consider this alternative option as exposing latent bugs that should have been caught before, or as making
blit
"less robust"? Should we reconsider the current rounding/clipping rules? How strict are other backends to weird bboxes and can we make things consistent across all of them?PR Checklist
pytest
passes).flake8
on changed files to check).flake8-docstrings
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).