Skip to content

Allow colorbar.ax.set_ylim to set the colorbar limits? #13948

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
ImportanceOfBeingErnest opened this issue Apr 13, 2019 · 12 comments
Closed

Allow colorbar.ax.set_ylim to set the colorbar limits? #13948

ImportanceOfBeingErnest opened this issue Apr 13, 2019 · 12 comments

Comments

@ImportanceOfBeingErnest
Copy link
Member

ImportanceOfBeingErnest commented Apr 13, 2019

Bug report

Bug summary

Coming from this stackoverflow question I was wondering if it would be useful to allow the limits of the colorbar axes to be used for restricting the range of colors to be shown in the colorbar. I.e.

colorbar.ax.set_ylim(-2, 8) 

Code for reproduction

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

x = np.linspace(-2,8)

mima = np.max((np.abs(x.min()), np.abs(x.max())))
norm = mcolors.Normalize(-mima, +mima)

sc = plt.scatter(x,x, c=x, cmap = 'seismic', norm=norm)

cb = plt.colorbar(sc, orientation="horizontal")
cb.ax.set_xlim(x.min(), x.max())

plt.margins(x=0)
plt.savefig("test.png", bbox_inches="tight")
plt.show()

Actual outcome

test

Expected outcome

test

@jklymak
Copy link
Member

jklymak commented Apr 13, 2019

What’s supposed to happen if limits are set smaller? Also what version are you using above?

@timhoffm
Copy link
Member

On master, your code produces

grafik

It seems, you have used cb.ax.set_xlim.

I don't know what the suggested way of working with colorbar is right now. However, manipulating xlim/ylim of the underlying axes seems too low level. Probably. Colorbar should have a dedicated method for the effect you want to achieve.

@jklymak
Copy link
Member

jklymak commented Apr 13, 2019

You can't do this just by changing the x-limit of the underlying axes because the colorbar is represented by a QuadMesh, and the whole quadmesh will still get shown regardless of the underlying xlim.

Its totally possible to add this extra API, but I'm skeptical whether its worth the substantial complexity, versus just truncating the colormap.

@ImportanceOfBeingErnest
Copy link
Member Author

ImportanceOfBeingErnest commented Apr 13, 2019

Yes, that's cb.ax.set_xlim, sorry. Corrected the code.

I ran this with master (fetched ~2 weeks ago, 3.0.2.post2051+g628ab4e23).
I think when limits are smaller, it should just behave as usual axes, limiting what's shown in the axes. Possibly via the usual clip_box?
I suppose the more interesting question is, what should happen if limits are larger? That could be up for debate, but I would be open for it to either show the complete colormap (due to the norm going from -8 to 8) or to show white (due to the mappable array being limited between -2 and 8).

@jklymak
Copy link
Member

jklymak commented Apr 14, 2019

If anyone takes this up please remember that the colorbars also have the extend arrows on the end. This would have to interact with those properly.

However I’ll again say that I’m not sure the API complexity needed is worth it.

@efiring
Copy link
Member

efiring commented Apr 15, 2019

I share @jklymak's skepticism about cost/benefit ratio for this. Colorbars are already pretty complicated.

@spalato
Copy link

spalato commented Nov 20, 2019

Supporting this change.
Condiser the following motivating example:

import matplotlib.pyplot as plt

x = np.linspace(-10, 10)
y = np.linspace(-10, 10)

z = np.exp(-0.5*(x[:,np.newaxis]**2/10.0+y[np.newaxis,:]**2/2.0)) 
noise = 0.1*np.random.randn(*z.shape)
z += noise

lim = np.max(np.abs(z))

plt.pcolormesh(x, y, z, vmin=-lim, vmax=lim, cmap="RdBu_r")
plt.colorbar(ax=None)

index

In this image, a diverging colormap is used to differentiate positive and negative values. The negative values are due to some noise.

The colorbar falsely conveys the information that the lower limit of the data is comparable to its upper limit. It also requires lots of unnecessary space, which is often a problem in real contexts.

Using set_clim shifts the white color to the center of the new range, defeating the purpose of the diverging colormap.

I share @jklymak's skepticism about cost/benefit ratio for this. Colorbars are already pretty complicated.

I couldn't find any simple workaround, short of rebuilding a custom colormap.

@ImportanceOfBeingErnest
Copy link
Member Author

I think people aknowledge the problem, but there is no definitive solution to it. Possible solutions are:

  1. Change the limits of the colormap (this issue)
  2. Allow for a normalization that cuts the colormap (Enh: DivergingNorm Fair #15333)
  3. Provide a colorbar factory (as discussed on discourse)

The discourse thread also contains workarounds using solutions 2. and 3. Those should allow users to get the desired functionality.
The remaining question here is whether a solution should be incorporated into matplotlib, and if so, which one.

@jklymak
Copy link
Member

jklymak commented Nov 20, 2019

I strongly disagree that the colorbar falsely conveys that there is just as much negative as positive data in the above plot. That’s the image’s job. The colorbar shown above shows me quite clearly that a properly centred diverging colormap has been used, and indicates the range that has been assigned to each side of zero. the data shows me that most of the data is greater than zero. If the ranges were assymetric I’d need to search around for zero to make sure it was properly zeroed (you may or may not be surprised by how many people don’t bother to centre diverging colormaps) and then I’d need to squint to make sure the colorscale for the two signs is symmetric.

@AdityaSavara
Copy link

While I actually would prefer this feature, my understanding is that somebody could convey what was desired by making a custom color map. I believe that's what is discussed here: https://stackoverflow.com/questions/41916204/specify-boundaries-on-matplotlib-colorbar

@QuLogic QuLogic modified the milestones: v3.3.0, v3.4.0 May 7, 2020
@QuLogic QuLogic modified the milestones: v3.4.0, v3.5.0 Jan 27, 2021
@jklymak
Copy link
Member

jklymak commented Jun 3, 2021

This is mostly closed by #20054, but there should be tests if we decide to keep this as a "feature"...

@QuLogic QuLogic modified the milestones: v3.5.0, v3.6.0 Sep 25, 2021
@jklymak
Copy link
Member

jklymak commented Oct 12, 2021

This was closed by #20054.

@jklymak jklymak closed this as completed Oct 12, 2021
@QuLogic QuLogic modified the milestones: v3.6.0, v3.5.0 Oct 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants