Skip to content
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

Better choice of offset-text. #5785

Merged
merged 5 commits into from May 11, 2016

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Jan 2, 2016

The axis offset text is chosen as follows:

xlims => offsettext
123, 189 => 0
12341, 12349 => 12340
99999.5, 100010.5 => 100000 # (also a test for #5780)
99990.5, 100000.5 => 100000
1233999, 1234001 => 1234000

(and the same for negative limits).

See #5755.

@tacaswell tacaswell added this to the next major release (2.0) milestone Jan 2, 2016
@WeatherGod
Copy link
Member

I have some test cases from a while back when I last tried to come up with a better offset text logic. These test cases really helped explore the possible edge cases in that attempt. You might find it useful (the test data, that is, not the code): https://gist.github.com/WeatherGod/272f4022bf7a8ca12ff4

@anntzer
Copy link
Contributor Author

anntzer commented Jan 6, 2016

Thanks @WeatherGod, I incorporated them in the test suite and slightly changed the algorithm. Now, the main condition of whether to use the offset is whether there are two common significant digits at the beginning of every label (allowing for negative labels as discussed above, I think that's the main questionable choice remaining).

@anntzer
Copy link
Contributor Author

anntzer commented Jan 6, 2016

(hum, the failing test seems to work for me (and doesn't involve offset texts))

@@ -159,6 +159,49 @@ def test_SymmetricalLogLocator_set_params():
nose.tools.assert_equal(sym.numticks, 8)


def test_ScalarFormatter_offset_value():
Copy link
Member

Choose a reason for hiding this comment

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

This needs an @cleanup decorator

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As it is, the @cleanup decorator doesn't support generative tests. I'll write an patch for that first.

Copy link
Member

Choose a reason for hiding this comment

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

Awesome. That is something that has driven me crazy a couple of times. I have dealt with it by putting the decorator on the called function and creating all of the figures/axes in that function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See #5809.

@WeatherGod
Copy link
Member

Huh, never seen this error before: "RuntimeError: In set_text: could not load glyph". Also, this branch needs rebasing.

@anntzer
Copy link
Contributor Author

anntzer commented Jan 27, 2016

Rebased. I cannot reproduce the glyph-loading errors locally.

abs_min, abs_max = sorted([abs(float(lmin)), abs(float(lmax))])
# Only use offset if there are at least two ticks and every tick has
# the same sign.
if lmin == lmax or lmin <= 0 <= lmax:
Copy link
Member

Choose a reason for hiding this comment

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

Can move this section above the absolute values to short-circuit a little earlier.

self._set_orderOfMagnitude(d)
self._set_format(vmin, vmax)

def _set_offset(self, range):
# offset of 20,001 is 20,000, for example
def _compute_offset(self):

Choose a reason for hiding this comment

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

I fully agree that renaming this method was really needed; the new name actually reflects the purpose of the function.

Copy link
Member

Choose a reason for hiding this comment

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

Contra my reluctance to change the public API at all, changing anything with a leading _ is fair game.

@efiring
Copy link
Member

efiring commented May 2, 2016

This is failing the two tests in which left==right. It's not clear to me whether the problem is in the algorithm, or in the tests.

The axis offset text is chosen as follows:

xlims => offsettext
123, 189 => 0
12341, 12349 => 12340
99999.5, 100010.5 => 100000 # (also a test for matplotlib#5780)
99990.5, 100000.5 => 100000
1233999, 1234001 => 1234000

(and the same for negative limits).

See matplotlib#5755.
Tests cases courtesy of @WeatherGod.  Slightly improved numerical
accuracy.
@anntzer
Copy link
Contributor Author

anntzer commented May 2, 2016

The test failure was probably masked at some point by the misuse of a generative test. Anyways, this comes down to a policy choice for the left == right case. I guess that "by continuity", we should just let the offset be equal to the single value in that case (say the values were x-eps and x+eps, then it would be normal for x (rounded to ~eps) to be the offset, so we should keep that as eps->0).
Thoughts?

@efiring
Copy link
Member

efiring commented May 2, 2016

The present algorithm is giving (1, 1, 1) and (123, 123, 120) as left, right, offset. Nonsingular is expanding the actual left, right ranges to (0.999, 1.001) and (122.877, 123.123). So the test cases with left==right are not really special cases. Either we like what the algorithm does, or we don't. I still don't completely understand what the algorithm's criteria are, but the results at least look reasonable, so I would be inclined to just change the tests to match. Maybe the tests should actually be changed to use the values provided by the present implementation of nonsingular rather than feeding in equal numbers, since otherwise a change to nonsingular would cause this test to fail for reasons not related to the algorithm it is testing.

@anntzer
Copy link
Contributor Author

anntzer commented May 2, 2016

OK, now I remember what I did: an offset text is used if it "saves" at least two significant digits, i.e. if the length of the (low, high) range is no more than a hundredth of the largest power of ten below high. So yes, the (1, 1, 1) and (123, 123, 120) outputs are expected given the effect of nonsingular. I rewrote the tests (still using equal left and right for now because using different left and right is basically already tested) and rebased on master.

@WeatherGod
Copy link
Member

This is looking good to me. Were there any remaining concerns? Do we need to update any documentation about the improved offset text algorithm?

@anntzer
Copy link
Contributor Author

anntzer commented May 2, 2016

I can add a snippet like "The default offset-text choice was changed to only use significant digits that are common to all ticks (e.g. 1231..1239 -> 1230, instead of 1231), except when they straddle a relatively large multiple of a power of ten in which case that multiple is chosen (e.g. 1999..2001->2000)." Looks good?

@efiring
Copy link
Member

efiring commented May 2, 2016

@anntzer Yes, adding that explanation would be good.

@anntzer
Copy link
Contributor Author

anntzer commented May 2, 2016

Done.

@dopplershift
Copy link
Contributor

Looks like the only failure on AppVeyor was spurious. Anyone with proper permissions wanna restart the appveyor run so this can go green and be merged?

@efiring
Copy link
Member

efiring commented May 11, 2016

I don't see a way to restart just one appveyor test, so I triggered the whole set of checks.

@dopplershift
Copy link
Contributor

dopplershift commented May 11, 2016

If you have permissions, you can log into AppVeyor and re-run the build. Unfortunately, it doesn't key off of GitHub permissions; those permissions are managed manually by whoever owns the AppVeyor project (looks like @mdboom )

@efiring efiring merged commit 4e1792b into matplotlib:master May 11, 2016
efiring added a commit that referenced this pull request May 11, 2016
@efiring
Copy link
Member

efiring commented May 11, 2016

Backported to v2.x as beb08c8.

@anntzer anntzer deleted the better-offsettext-choice branch May 11, 2016 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants