Title: Enh better colorbar axes by jklymak · Pull Request #20054 · matplotlib/matplotlib · GitHub
Open Graph Title: Enh better colorbar axes by jklymak · Pull Request #20054 · matplotlib/matplotlib
X Title: Enh better colorbar axes by jklymak · Pull Request #20054 · matplotlib/matplotlib
Description: PR Summary Redo of #18900 because GitHub was mad at me. PR is exactly the same... closes #19543 and many other annoyances PR Summary This is a relatively major re-arrangement of how we create colorbars. This will simplify making colorbars for other norms if the norms are created with a scale. It also allows more normal manipulation of the colorbar axes. There are some negative consequences as well. Issue Currently most colorbars are drawn as a pcolormesh on a hidden axes. When extend='both'/'upper'/'lower' it makes the axes longer by a proportion extendlen and draws the extend regions by distorting the upper and/or lower cell of the pcolormesh. This is great, except it means that all the usual tick locators need to have special cases that do not continue drawing the ticks into the region of the axis that has the extend triangles. We do that now with a few piecemeal wrapper classes: _ColorbarAutoLocator(ticker.MaxNLocator), _ColorbarAutoMinorLocator(ticker.AutoMinorLocator), etc. Needless to say that is clunky. The scale used for the colorbar also has to nicely invert past vmin and vmax for the triangles to be drawn properly, despite the fact these regions are only meant for over/under colors that you wouldn't necessarily expect an arbitrary norm to be able to handle. Proposal The proposed solution here is to draw the main pcolor ("solid") on a full axes that goes from vmin to vmax, and draw the extend triangles ("extends") as patches appended to the end of that axes. They are drawn in axes space, so the scale of the axes and the limits of the axes no longer matter. The problem with this approach is that all the sizing and placement of axes is with an axes that is the size of the solid and the extends. i.e. if shrink=1 the whole axes, including the extends, is the height (or width) of the parent axes. The solution proposed here is to draw the solid on an inset_axes that is shrunk from the parent axes if there are extends. Pros: The visible axis labels are all on the "inner" axes and no longer require weird wrappers around the tick Locators. Any scale can be used, and the user can set the scale manually as they like. The initial scale is chosen from the norm, if it has one, or chosen to be linear. the user can change the min and max of the axes if they like. We sometimes get requests for this if the user wants to zoom in on some part of the colormap. I think the code is simpler, but I wrote it so YMMV Cons: manual axes placement is not the main colorbar axes object any more: The biggest con is that for cax = fig.add_axes([0.1, 0.1, 0.8, 0.07]) cb = fig.colorbar(im, cax=cax) the axes object we create is new so that cb.ax is no longer cax. In fact cax == cb.ax.parent_axes. So this breaks cases where the user hoped to do things to cax after it was created. Of course they can access cb.ax. This failed one test where we did cax.tick_params. We can pass these through as we find them (I did already for tick_params). However, this also means that cax.xaxis points to an axis we make invisible now, and won't do anything (again cb.ax.xaxis points to the right thing.) I will argue this breakage is worth it. Doing random things to cax failed much of the time anyway, whereas the new object stored on cb.ax should be much more robust. Unfortunately, however, I cannot think of a reasonable way to deprecate this. Slight change in visibility of lines with extends This is an obscure one, but lines are now partly cut off if they are drawn on the edge of the colorbar and there is an extend. The test that broke this didn't appear to have a reasonable reason to have an extend in that case anyhow (see contour_colorbar.png, and contour_manual_colors_and_levels.png) Other changes: There seemed to have been a bug in colorbar widths with extends before, where they ended up a bit narrower than the colorbars without extends. This can be seen in double_cbar.png and a few other tests. If there is only one extend, the new axes is offset from the center. This means that the label (which is attached to the inner_axes) is now offset as well. We could move it (by placing the label logic all on the parent), but I'm not convinced that it doesn't look better to let it move down and be centred on the spine. (Also double_cbar.png) I ditched the private _internal.classic_mode for the colorbars. It doesn't change that many tests, and it needlessly complicates the Locator code to keep it around. Test: fig, ax = plt.subplots(1, 2, constrained_layout=True) pc = ax[0].pcolormesh(np.arange(100).reshape(10, 10)+1) cb = fig.colorbar(pc, ax=ax[0], extend='both') cb.ax.set_yscale('log') pc = ax[1].pcolormesh(np.arange(100).reshape(10, 10)+1) cb = fig.colorbar(pc, ax=ax[1], extend='both') cb.ax.set_ylim([20, 90]) plt.show() Before After PR Checklist Has pytest style unit tests (and pytest passes). Is Flake 8 compliant (run flake8 on changed files to check). New features are documented, with examples if plot related. Documentation is sphinx and numpydoc compliant (the docs should build without error). Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all). New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there). API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
Open Graph Description: PR Summary Redo of #18900 because GitHub was mad at me. PR is exactly the same... closes #19543 and many other annoyances PR Summary This is a relatively major re-arrangement of how we create colo...
X Description: PR Summary Redo of #18900 because GitHub was mad at me. PR is exactly the same... closes #19543 and many other annoyances PR Summary This is a relatively major re-arrangement of how we create colo...
Opengraph URL: https://github.com/matplotlib/matplotlib/pull/20054
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:a4ff327f-7924-f7b9-1550-dbed675e2458 |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | 82AC:1F816D:102416D:1615BA8:6A5224DD |
| html-safe-nonce | 2ddb0df3eb90c2357fcfe42aed58161e576aaea31ceb43258a575527a4c418ce |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4MkFDOjFGODE2RDoxMDI0MTZEOjE2MTVCQTg6NkE1MjI0REQiLCJ2aXNpdG9yX2lkIjoiNjgyNTM0MjUyNTY5MzM3MTYxMyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | d71fedd614fc7de61f5470aea9206bc54de56085e3ed1e920783b4fb43e8c38f |
| hovercard-subject-tag | pull_request:622085040 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/matplotlib/matplotlib/pull/20054/files |
| twitter:image | https://avatars.githubusercontent.com/u/1562854?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/1562854?s=400&v=4 |
| og:image:alt | PR Summary Redo of #18900 because GitHub was mad at me. PR is exactly the same... closes #19543 and many other annoyances PR Summary This is a relatively major re-arrangement of how we create colo... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/matplotlib/matplotlib git https://github.com/matplotlib/matplotlib.git |
| octolytics-dimension-user_id | 215947 |
| octolytics-dimension-user_login | matplotlib |
| octolytics-dimension-repository_id | 1385122 |
| octolytics-dimension-repository_nwo | matplotlib/matplotlib |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1385122 |
| octolytics-dimension-repository_network_root_nwo | matplotlib/matplotlib |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 7aed05249554b889eb33d002851a973eebcc7e91 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width