Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Create a hidden colorbar on-the-fly to format imshow cursor data if no colorbar exists yet. #12473

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

Closed
wants to merge 1 commit into from

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Oct 10, 2018

PR Summary

Followup to #12459, which also works when no colorbar exists. Adds a second commit on top of #12459.

Made as a separate PR as it's a bit an ugly hack (optimally we'd factor out the formatter selection) but still proposing it as I think the behavior is quite nice.

I don't think it'd be a performance issue as we don't actually draw() the hidden figure -- it doesn't even have a renderer attached to it.

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 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

@anntzer anntzer added this to the v3.1 milestone Oct 10, 2018
@jklymak
Copy link
Member

jklymak commented Oct 10, 2018

Why don’t you just add a formatter to the artist? This API May be preferable anyways to using the colorbar formatter though that could be the default.

@anntzer
Copy link
Contributor Author

anntzer commented Oct 10, 2018

Because the correct Formatter depends on the Normalization subclass being used, and that logic currently only exists in the colorbar code (nowhere else does it say that LogNorm should use LogFormatter, etc.).

@jklymak
Copy link
Member

jklymak commented Oct 10, 2018

Can’t we refactor that somehow? Seems quite hacky that you have to create a colorbar to make this work.

@anntzer
Copy link
Contributor Author

anntzer commented Oct 10, 2018

The relationship between norms, scales, colorbars, locators and formatters has been discussed to death (although in a slightly deconstructed fashion) a few times e.g. in #7294 (#7294 (comment), #7294 (comment), ...); TLDR: I think Norms and Scales should be the same thing.
But I stared too many times at the colorbar code trying to refactor it and in the meantime this is the simplest I can do.

@jklymak
Copy link
Member

jklymak commented Oct 10, 2018

I think the relevant code for matching up the Norm and Formatter is just:

if format is None:
if isinstance(self.norm, colors.LogNorm):
self.formatter = ticker.LogFormatterSciNotation()
elif isinstance(self.norm, colors.SymLogNorm):
self.formatter = ticker.LogFormatterSciNotation(
linthresh=self.norm.linthresh)
else:
self.formatter = ticker.ScalarFormatter()

Can't we just make colorbar._get_formatter_(norm) and call here and in colorbar?

@anntzer
Copy link
Contributor Author

anntzer commented Oct 10, 2018

No, you also need to have an underlying axes that sets the locs for the formatter (that's list(ax.yaxis.iter_ticks()) in this PR), otherwise the formatter can't format the values (https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/ticker.py#L562).

@jklymak
Copy link
Member

jklymak commented Oct 10, 2018

You are right, but that seems quite unfortunate.

I think most places where self.axis.get_view_internal() is called could be changed to min/max(self.locs) if self.axis is None. Then all you'd have to do is manually set the view limits. I understand why we'd generally want to defer to the viewlimits, but its a shame to not allow the formatters to be independent of an axis if possible.

How does this work with lognorms anyways? The log formatter returns empty strings a lot of the time.

@jklymak
Copy link
Member

jklymak commented Oct 10, 2018

Oooh, does Formatter.create_dummy_axis help?

@timhoffm
Copy link
Member

Didn't have time to look at the code, but I agree with @jklymak that this sounds extremely hacky. If it's not simple to refactor: What happens if we do not implement this? Does something crash or do we just not have the output displayed?

@jklymak
Copy link
Member

jklymak commented Oct 11, 2018

import numpy as np
import matplotlib.pyplot as plt

import matplotlib.ticker as mticker

fmt = mticker.ScalarFormatter()
fmt.create_dummy_axis()
fmt.set_locs([0.01, 1000])

print('Scalar:', fmt(20))

fmt = mticker.LogFormatterSciNotation()
fmt.create_dummy_axis()
fmt.set_locs([0.01, 1000])

print('10:', fmt(10))
print('20:', fmt(20))
print('100:', fmt(100))
print('200:', fmt(200))

Gives:

Scalar: 20

10: $\mathdefault{10^{1}}$
20:
100: $\mathdefault{10^{2}}$
200:

As above, not sure you even ever want to LogFormatter, but maybe I'm misunderstanding how this works...

@anntzer
Copy link
Contributor Author

anntzer commented Oct 11, 2018

@jklymak Actually, you need to call fmt.axis.set_view_interval (instead of fmt.set_locs).

import numpy as np
import matplotlib.pyplot as plt

import matplotlib.ticker as mticker

fmt = mticker.ScalarFormatter()
fmt.create_dummy_axis()
fmt.axis.set_view_interval(0.01, 1000)

print('Scalar:', fmt(20))

fmt = mticker.LogFormatterSciNotation()
fmt.create_dummy_axis()
fmt.axis.set_view_interval(0.01, 1000)

print('10:', fmt(10))
print('20:', fmt(20))
print('100:', fmt(100))
print('200:', fmt(200))

gives

Scalar: 
False None 1.0
10: $\mathdefault{10^{1}}$
False None 2.0
20: $\mathdefault{2\times10^{1}}$
False None 1.0
100: $\mathdefault{10^{2}}$
False None 2.0
200: $\mathdefault{2\times10^{2}}$

(I guess I should add a \times -> x in strip_math... now added to #12459)

@timhoffm Then we just fallback on the old label string (which is much less useful): #12459 protects everything under a if self.colorbar anyways.

@jklymak
Copy link
Member

jklymak commented Feb 26, 2019

I still think we should create a dummy axis, not colorbar... Formatter.create_dummy_axis should be made to work, but I admit I haven't wrestled with it yet.

@jklymak jklymak modified the milestones: v3.1.0, v3.2.0 Feb 26, 2019
@anntzer
Copy link
Contributor Author

anntzer commented Feb 26, 2019

Perhaps(??) things will become easier after the followup PRs after format_ticks get handled.

@anntzer anntzer force-pushed the imshow-cursordata-2 branch from 56a5cc9 to f8463d7 Compare April 9, 2019 14:52
@anntzer anntzer force-pushed the imshow-cursordata-2 branch from f8463d7 to af18238 Compare April 30, 2019 15:44
@tacaswell tacaswell modified the milestones: v3.2.0, v3.3.0 Sep 4, 2019
@QuLogic QuLogic modified the milestones: v3.3.0, v3.4.0 May 2, 2020
@QuLogic QuLogic modified the milestones: v3.4.0, v3.5.0 Jan 22, 2021
@jklymak jklymak marked this pull request as draft March 27, 2021 19:17
@anntzer
Copy link
Contributor Author

anntzer commented Jan 2, 2022

Superseded by #20949.

@anntzer anntzer closed this Jan 2, 2022
@anntzer anntzer deleted the imshow-cursordata-2 branch January 2, 2022 15:00
@QuLogic QuLogic removed this from the v3.6.0 milestone Sep 9, 2022
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.

5 participants