8000 Change colorbar for contour to have the proper axes limits... by jklymak · Pull Request #13506 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Change colorbar for contour to have the proper axes limits... #13506

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

Merged
merged 7 commits into from
May 19, 2019

Conversation

jklymak
Copy link
Member
@jklymak jklymak commented Feb 24, 2019

PR Summary

We've changed colorbars to mostly behave like other axes, so for instance, print(cbar.ax.get_ylim()) actually returns the axes limits of the colorbar.

However, that did not work for colorbars made with contour, which were still normalized with limits between 0 and 1. Now this axes are normalized between vmin and vmax for the colorbar (not necessarily the vmin and vmax of the colormap norm, a subtlety that confused me for a while).

This closes #13494 because that example would now simply read:

cbar.ax.axhline(desired_cbar_yvalue, color='r', linewidth=5)

rather than normalizing that between 0 and 1.

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

@jklymak jklymak force-pushed the fix-colorbar-on-contour branch 2 times, most recently from 963bc27 to 9ad0d94 Compare February 24, 2019 23:36
@jklymak jklymak changed the title [WIP] Change colorbar for contour to have the proper axes limits... Change colorbar for contour to have the proper axes limits... Feb 24, 2019
@jklymak jklymak force-pushed the fix-colorbar-on-contour branch from 3bc20eb to 982616c Compare February 25, 2019 00:46
@wsoofi
Copy link
wsoofi commented Feb 25, 2019

Thanks for doing this!

@jklymak
Copy link
Member Author
jklymak commented Feb 25, 2019

@wsoofi. Thanks, It was your PR that inspired the need for it. It’s really not good to have the colorbar behave differently for different mappables but there were some subtleties that needed some work.

Copy link
Member
@dstansby dstansby left a comment

Choose a reason for hiding this comment

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

Looks 👍 , I'm just not quite sure what a bit of code is doing.

were made children of the normal axes tickers.

This version of Matplotlib extends that to mappables made by contours, and
allows the axes to run between the lesser the lowest boundary in the contour
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
allows the axes to run between the lesser the lowest boundary in the contour
allows the axes to run between the lowest boundary in the contour

@jklymak jklymak force-pushed the fix-colorbar-on-contour branch from 190e9cb to 4e0d077 Compare February 25, 2019 14:56
@jklymak
Copy link
Member Author
jklymak commented Feb 25, 2019

@dstansby, thanks fixed. The except happens when the norm doesn't have an inverse, i.e in the tests for BoundaryNorm.

@jklymak jklymak added this to the v3.2.0 milestone Feb 25, 2019
@jklymak jklymak requested a review from efiring April 12, 2019 02:22
@efiring
Copy link
Member
efiring commented Apr 20, 2019

It doesn't work with contour, which means our test framework is missing something critical. With ipython --pylab on your branch:

z = np.arange(24).reshape(4, 6)
cs = contourf(z, levels=[2, 4, 6, 10, 20])
plt.colorbar()
plt.savefig('contour_jk.png')

yields the following incorrect colorbar:
contour_jk
It should look like this (with master):
contour_default

We also need to test the following:

plt.clf(); cs = contourf(z, levels=[2, 4, 6, 10, 20])
plt.colorbar(spacing='proportional')
plt.savefig('contour_proportional.png')

which yields this (correct) result with master:
contour_proportional
Your version of this is almost imperceptibly different from the master version, but there is a difference.

I suspect there are quite a few other cases that will need to be tested.

@jklymak
Copy link
Member Author
jklymak commented Apr 21, 2019

Ok I guess the logic I had assumed proportional was true. Im not sure I get the other case It’s like we are treating the contours as categories, which seems strange to me.

@efiring
Copy link
Member
efiring commented Apr 21, 2019

An example of where this is useful is in contouring bottom topography with contourf. One might want contour levels at 0, 50, 100, 250, 500, 1000, 2000, 5000. Yes, in a sense each interval is a category that gets a color. The interval boundaries need to be labeled, and each interval in the colorbar has to be large enough so that the labels don't collide. Hence the 'uniform' option, in which each interval gets the same space on the colorbar.

@jklymak
Copy link
Member Author
jklymak commented Apr 21, 2019

Thanks @efiring, I think I fixed this. I'll add tests as well!

@jklymak jklymak force-pushed the fix-colorbar-on-contour branch from 6281da5 to 7d190d3 Compare April 21, 2019 04:37
@jklymak jklymak force-pushed the fix-colorbar-on-contour branch from 7d190d3 to 7b3ea96 Compare April 21, 2019 14:31
@jklymak
Copy link
Member Author
jklymak commented Apr 21, 2019

Test added. Not sure if there should be more...

@@ -578,13 +580,11 @@ def _reset_locator_formatter_scale(self):
"""
self.locator = None
self.formatter = None
if (isinstance(self.norm, colors.LogNorm)
and self._use_auto_colorbar_locator()):
Copy link
Member

Choose a reason for hiding this comment

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

Why can that be left out?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we want the axes to be logarithmic in this case, but I agree its open to interpretation:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

z = np.arange(24).reshape(4, 6) + 1
z = np.power(2, z)
fig, axs = plt.subplots(1, 2, constrained_layout=True)
ax = axs[0]
cs = ax.contourf(z, levels=np.power(10., [1, 2, 6.5, 10] ), norm=mcolors.LogNorm())
fig.colorbar(cs, ax=ax, spacing='proportional')
ax = axs[1]
cs = ax.contourf(z, levels=np.power(10, [1, 2, 6.5, 10]), norm=mcolors.LogNorm())
fig.colorbar(cs, ax=ax, spacing='uniform')

plt.show()

With this change:

Figure_1

Without this change:

Figure_1Wrong

Before this PR:

Figure_1Old

Copy link
Member

Choose a reason for hiding this comment

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

👍 Looks reasonable.

@@ -578,13 +580,11 @@ def _reset_locator_formatter_scale(self):
"""
self.locator = None
self.formatter = None
if (isinstance(self.norm, colors.LogNorm)
and self._use_auto_colorbar_locator()):
Copy link
Member

Choose a reason for hiding this comment

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

👍 Looks reasonable.

@jklymak
Copy link
Member Author
jklymak commented May 18, 2019

ping @efiring, or anyone else interested in colorbars

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0