Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

BUG: Return null Bbox when there is no intersection for bar_label center.#25681

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ksunden merged 3 commits intomatplotlib:mainfromstefmolin:null-bbox
Apr 17, 2023

Conversation

stefmolin
Copy link
Contributor

PR Summary

Addresses#25625

When usingbar_label(label_type='center') and axis limits that cut off some of the bars, an exception was raised because the Bbox intersection wasNone. This PR makes sure the plot can still be created.

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (andpytest passes)
  • [N/A] Documentation is sphinx and numpydoc compliant (the docs shouldbuild without error).
  • [N/A] New plotting related features are documented with examples.

Release Notes

  • [N/A] New features are marked with a.. versionadded:: directive in the docstring and documented indoc/users/next_whats_new/
  • [N/A] API changes are marked with a.. versionchanged:: directive in the docstring and documented indoc/api/next_api_changes/
  • [N/A] Release notes conform with instructions innext_whats_new/README.rst ornext_api_changes/README.rst

@ksunden
Copy link
Member

I think this raises the more fundamental question of whetherintersection should ever returnNone in the first place.

Certainly I missed that possibility when implementing#24976, so if wedon't change it that type hint should be corrected, and also affects some other places where an intersection is returned directly (e.g.get_tightbbox, where the docstring doesn't acknowledge it can returnNone either).

We in one place (internally) rely on the Falsiness of the non-overlap case.

My suggestion (and I want some buy-in from other maintainers before a final decision is made, perhaps@timhoffm as API lead, in particular) would be to implement__bool__ onBbox:

def__bool__(self):returnself.x1>=self.x0andself.y1>=self.y0

This would makeBbox.null() Falsey (as well as any other bbox where either x or y has negative length) and allow simplifying theintersection code such that it never returnsNone, thus simplifying the return type while retaining (most) behavior (aside fromBbox.intersection(a, b) is[ not] None checks)

There are a small handful of internal checks which dois None on a bbox (potentially) computed viaintersection e.g.if clipped_bbox is None: inimage.py andvar = get_tightbbox(...) ... if var is not None in a few places. These could be replaced with simplyif [not] var:, so the fix is pretty easy and actually backwards compatible (on the condition that the direct output of intersection is fed in, as any case that results in a Falsey bbox would result inNone from intersection).

I did not see any downstream packages that have similar checks, though certainly not an exhaustive search. Astropy and PIL have somebbox is None checks, but pretty sure they are referring to their own Bbox implementations when they do, not ours (especially for PIL, of course).
Astropy does have a short circuit inWCSAxes.get_tightbbox which returns None directly.

Doing so at theintersection level would render this code change proposed here unnecessary, as desired behavior would simply fall out from intersection calculation.

@timhoffm
Copy link
Member

timhoffm commentedApr 14, 2023
edited
Loading

@ksunden - Your proposal is quite orthogonal to the above issue. (It would open up another type of fix, but only after a deprecation period)

  1. bool-evaluating a null-object to false totally makes sense. Slight unclarity should the half-null boxes with one finite dimension also be false or not? I have no clear opinion on that, which is likely because I don't know in which contexts they appear.

  2. Returning null boxes instead ofNone.

SinceBbox.null() already defines the null-object concept, we could use it. (I'm generally very torn on the use of null-objects in Python). However, we have a significant compatibility barrier:

https://matplotlib.org/stable/api/transformations.html#matplotlib.transforms.BboxBase.intersection

Return the intersection of bbox1 and bbox2 if they intersect, or None if they don't.

is public API and very clear about the return value. Any user will canonically checkintersection() is not None and notnot intersection(). If we want to go there we need a regular deprecation cycle (and it's nasty because we cannot runtime-warn on it).

I've no clear how widespread this is used, but would imagine that there's a bit of user code out there, that would be affected.

Additional question: How is consistency across other functions returning bboxes. Do we have other cases that can return invalid boxes? If so, do they return null() or None?

Overall:

  • (1) yes;
  • (2) I'm sceptical on the cost-benefit ratio.

@tacaswell
Copy link
Member

I agree with@timhoffm 's analysis and that we should handle the wider issue independently of this PR.

@tacaswelltacaswell added this to thev3.7.2 milestoneApr 14, 2023
@timhoffm
Copy link
Member

None of the below is critical, because fixing the RuntimeError is most important. But


When running the code from the test I get a warning log from

_log.warning("posx and posy should be finite values")

This is not helpful for the end user, but I don't know whether we can do something about it. - Does a warning from a deep burried draw() function make sense at all? Maybe we should switch to info or debug.


Edge case: Setting the limit to the bar border still draws the label:

import matplotlib.pyplot as plt_, ax = plt.subplots()last = 0for label, value in zip(['a', 'b', 'c'], [10, 20, 50]):    bar_container = ax.barh('col', value, label=label, left=last)    ax.bar_label(bar_container, label_type='center')    last += valueax.set_xlim(None, 30)#plt.savefig(tmp_path / 'test')plt.show()

grafik

mrgransky reacted with thumbs up emoji

Copy link
Member

@QuLogicQuLogic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Please rebase to latestmain to fix CI.

Copy link
Member

@ksundenksunden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Fair points, all around, just a thought prompted by this change.

@ksundenksunden merged commit0e7f29e intomatplotlib:mainApr 17, 2023
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull requestApr 17, 2023
oscargus added a commit that referenced this pull requestApr 17, 2023
…681-on-v3.7.xBackport PR#25681 on branch v3.7.x (BUG: Return null Bbox when there is no intersection for bar_label center.)
@mrgransky
Copy link

None of the below is critical, because fixing the RuntimeError is most important. But

When running the code from the test I get a warning log from

_log.warning("posx and posy should be finite values")

This is not helpful for the end user, but I don't know whether we can do something about it. - Does a warning from a deep burried draw() function make sense at all? Maybe we should switch to info or debug.

Edge case: Setting the limit to the bar border still draws the label:

import matplotlib.pyplot as plt_, ax = plt.subplots()last = 0for label, value in zip(['a', 'b', 'c'], [10, 20, 50]):    bar_container = ax.barh('col', value, label=label, left=last)    ax.bar_label(bar_container, label_type='center')    last += valueax.set_xlim(None, 30)#plt.savefig(tmp_path / 'test')plt.show()

grafik

I tried this approach to apply some margin on the right hand side of the figure:
ax.set_xlim(right=ax.get_xlim()[1]+1.0, auto=True)
it fixes the runtime error at least!

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@QuLogicQuLogicQuLogic left review comments

@tacaswelltacaswelltacaswell approved these changes

@ksundenksundenksunden approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
v3.7.2
Development

Successfully merging this pull request may close these issues.

6 participants
@stefmolin@ksunden@timhoffm@tacaswell@mrgransky@QuLogic

[8]ページ先頭

©2009-2025 Movatter.jp