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

MNT: simplify valid tick logic#12158

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

Conversation

jklymak
Copy link
Member

@jklymakjklymak commentedSep 18, 2018
edited
Loading

PR Summary

This is a much scaled back first-step PR for#12105.

The logic for deciding whether or not to draw a tick was rather convoluted, and depended on the size of a pixel. This PR simply changes the test for whether a tick is in the view limit to one that depends on a relative tolerance to take up floating point slack (likenp.allclose, but for an interval). The relevant code is intransforms.inverval_contains.

See also#11004

This passes all previous testsexcept for thetest_axes/specgram_* tests.

These had a tick at 0 before becuase 0 was within half a pixel of the minimimum view limit of 0.2. Clearly this tick should not be drawn, and the half a pixel slop was far too large. Worse, if the figure was widened in interactive mode, the tick would disappear:

importnumpyasnpimportmatplotlib.pyplotaspltfig,ax=plt.subplots(dpi=100,figsize=(4,2))ax.set_xlim([0.2,500])plt.show()

figure_1a

figure_1b

With this PR, the tick is never drawn (because 0<0.2).

Another minimal example (w/o resizing)

import matplotlib.pyplot as pltfig, ax = plt.subplots()ax.set_ylim(0, 1.199)fig.savefig('boo100.png', dpi=100)fig.savefig('boo200.png', dpi=200)

Before

100 dpi

boo100

200 dpi

boo200

After

100 dpi

boo100

200 dpi

As above...

PR Checklist

  • Has Pytest style unit tests
  • Code isFlake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@jklymakjklymak added this to thev3.1 milestoneSep 19, 2018
@jklymak
Copy link
MemberAuthor

Ping@efiring

if tick is None:
continue
# NB: always update labels and position to avoid issues like #9397
tick.update_position(loc)
tick.set_label1(label)
tick.set_label2(label)
if not mtransforms.interval_contains(interval_expanded, loc):
try:
loct = self.get_transform().transform(loc)
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if it really makes a performance difference, but AFAICStransform() works on numpy arrays. So this could be pulled out of the loop and calculated in one go. Well, except for theAssertionError - when does that occur?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

We still have to do the loop, so can probably keep as-is for now.

I think the Assertion Error happened in CI, possibly get_transform returned None for some wacky axis.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Yeah its from the doc build:gallery/scales/custom_scale.py.

Exception occurred:  File "/home/circleci/project/lib/matplotlib/transforms.py", line 1436, in transform    assert not np.ma.is_masked(res)  # just to be on the safe sideAssertionError

The custom scale uses masks, and transforms.transform doesn't like it.

The previous implementation didn't call the transform, but this one does so that we can do the tolerance checking in log-scale rather than data space.

Copy link
Member

Choose a reason for hiding this comment

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

Are we sure that there are still any ticks on that example when we hit this?

@@ -2892,7 +2892,7 @@ def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
return vmin, vmax


def interval_contains(interval, val):
def interval_contains(interval, val, rtol=1e-10):
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like so as to not break downstream users relying on this being exact, the default should bertol=0

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@eric-wieser you probably understand the numerical issues better than me, but is this comparison ever "exact"?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, comparison is always exact. The danger is when you make assumptions about rounding in operations prior to the comparison, but that's for the caller to decide.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

OK, done...

except AssertionError:
loct = None
continue
if ((loct is None) or
Copy link
Member

Choose a reason for hiding this comment

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

Cantransform() returnNone? Otherwise we do not need theloct is None check here.

@jklymakjklymak mentioned this pull requestNov 5, 2018
6 tasks
@@ -2906,10 +2906,39 @@ def interval_contains(interval, val):
Returns
-------
bool
Returns true if given val is within the interval.
Returns true if given val is within the interval (with tolerance)
Copy link
Contributor

Choose a reason for hiding this comment

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

this one says nothing about tolerance

jklymak reacted with thumbs up emoji
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Fixed!

@tacaswell
Copy link
Member

We should make sure this does not break wcsaxes (attn@astrofrog )

# some scales might make them, so we need this try/except.
loct = None
continue
if not mtransforms.interval_contains_close(inter, loct):
Copy link
Contributor

@anntzeranntzerJan 3, 2019
edited
Loading

Choose a reason for hiding this comment

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

Do you have examples where we needinterval_contains_close and notinterval_contains here? Why couldn't thelocators be in charge of making sure whatever they return is in the interval and adjusting the values if needed (except for those outside the interval needed for classic mode)?

I don't really like the idea of hardcoding the 1e-10 tolerance here when it's something that can clearly(?) be avoided.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Hah, we currently have a 1/2-pixel tolerance! Surely1e-10 * interval is preferable?

The problem with limits is when people compute them.

On my machine:

3.51-1.51 == 2.0FalseIn [17]: abs(3.51-1.51- 2.0) < 1e-10Out[17]: True

Copy link
Contributor

@anntzeranntzerJan 3, 2019
edited
Loading

Choose a reason for hiding this comment

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

I guess it doesn't make things worse, but at least let's keep interval_contains_close private?

The point is that the Locator API should say something like the following to implementers (including 3rd party locators):

You may return tick values inside or outside of the axis bounds, but any value outside of the bounds (with no tolerance) will be dropped (except in "classic" mode, where we will keep the first outside value on either side).

and the locator classes are the one which should do something like

xmin, xmax = ...ticks = ...if xmin - tol < ticks[0] < xmin: ticks[0] = xmin

(or ticks[1] if that's the one corresponding to xmin).
i.e. the locator displaces the tick to match xmin if it's just below xmin.

But I guess that can wait.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

The issue with locators is that some uses want the bracketing ticks, unfortunately, for contour for instance... We could fix/change that as well, but beyond this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed it's beyond this PR.
The design above does not preclude bracketing ticks.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@anntzer did you really wantinterval_contains_close to be private? I actually think its useful to take into account floating point slop, but don't feel strongly about it.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, it feels like a hack while waiting for locators to be fixed, but I'm not going to insist on it.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Okey doke - done!

FIX: make contains_close private
@jklymakjklymakforce-pushed themnt-simplify-validtick branch from227bed5 to01d7455CompareJanuary 4, 2019 17:08
Copy link
Member

@timhoffmtimhoffm left a comment
edited
Loading

Choose a reason for hiding this comment

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

This looks ok by itself.

Not merging yet because of@tacaswell's concern with respect to wcsaxes. Can someone confirm, that this is not breaking them?

@astrofrog
Copy link
Contributor

I'm checking it and will report back shortly

Copy link
Contributor

@astrofrogastrofrog left a comment

Choose a reason for hiding this comment

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

This works fine with WCSAxes (all tests, including image tests, pass), in part because we do all the tick drawing ourselves.

@timhoffmtimhoffm merged commitd23bcea intomatplotlib:masterJan 8, 2019
@timhoffm
Copy link
Member

timhoffm commentedJan 8, 2019
edited
Loading

@astrofrog Thanks for testing.

@jklymak
Copy link
MemberAuthor

Yes, thanks all!

@jklymakjklymak deleted the mnt-simplify-validtick branchJanuary 8, 2019 19:00
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@tacaswelltacaswelltacaswell left review comments

@eric-wiesereric-wiesereric-wieser left review comments

@astrofrogastrofrogastrofrog approved these changes

@anntzeranntzeranntzer approved these changes

@timhoffmtimhoffmtimhoffm approved these changes

Assignees
No one assigned
Projects
None yet
Milestone
v3.1.0
Development

Successfully merging this pull request may close these issues.

6 participants
@jklymak@tacaswell@astrofrog@timhoffm@eric-wieser@anntzer

[8]ページ先頭

©2009-2025 Movatter.jp