-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Incorrect placement of Colorbar ticks using LogNorm #12155
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
Comments
That looks like the 'log' scale did not get propogated to the color bar axex correctly. If you do |
If you mean |
I do have problems reproducing this. I ran the following in the current development version import matplotlib
print(matplotlib.__version__) # 3.0.0rc1.post326+g521b60a77
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.ticker import LogLocator, LogFormatterSciNotation as LogFormatter
import numpy as np
x,y = np.ogrid[-4:4:31j,-4:4:31j]
z = np.exp(-x**2-y**2)
fig, ax = plt.subplots()
norm = mcolors.LogNorm(z.min(), z.max())
im = ax.pcolormesh(z, norm=norm)
im.set_norm(norm)
locator = LogLocator()
formatter = LogFormatter()
cbar = fig.colorbar(im, ax=ax,norm=norm)
cbar.locator = locator
cbar.formatter = formatter
cbar.update_normal(im)
plt.show() and this is the result which looks expected:
|
I will see if I can reproduce it outside the NeXpy context. The reason I posted is that this specific code has been untouched since Matplotlib v1.5, and it has worked without problem up until v2.2.3. I was hoping someone could point to the changes in the Matplotlib API that are likely to be relevant. |
Sorry this broke for you. Colorbar tick handling has definitely changed, though the outward facing API should not have. The most intrusive PR would be #9903 but there were a couple of others. OTOH this PR works with log scales, as @ImportanceOfBeingErnest points out above, so its hard to tell what broke for (downstream package developers can subscribe to https://mail.python.org/mailman/listinfo/matplotlib-devel for updates on matplotlib release candidates - 3.0 rc1 was released 11 Aug. ) Thanks! |
I don't know if this is helpful or not, but looking at the API changes, I added a colorbar with the
I still can't work out why it doesn't show up in the code example by @ImportanceOfBeingErnest but it does suggest that the underlying LogNorm instance is fine. For some reason, adding |
I've managed to produce a simple example demonstrating the problem. It turns out that the issue shows up if you make a plot with a linear color scale first and then transform it to a log scale. import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogLocator, LogFormatter
import numpy as np
x,y = np.ogrid[-4:4:31j,-4:4:31j]
z = 120000*np.exp(-x**2-y**2)
fig, ax = plt.subplots()
im = ax.imshow(z)
cbar = fig.colorbar(im)
norm = LogNorm(z.min(), z.max())
im.set_norm(norm)
cbar.set_norm(norm)
cbar.locator = LogLocator()
cbar.formatter = LogFormatter()
cbar.update_normal(im)
plt.show() |
An immediate solution is to use
instead. |
@rayosborn OK, thats great. Thanks. The issue is that before #9903 the colorbar drawing logic was all linear, and the log-space ticks were drawn by hand. This made automatic scaling of the colorbar cumbersome. However, it did allow you to simply change the locator and formatter in place, because the axes was always linear. I had no idea people would change the locator in place, but its not an unreasonable thing to do (switching the norm from linear to logarithmic). However, the axes now has no way of knowing that it is now a logarithmic axes because it doesn't check the norm again. As @ImportanceOfBeingErnest says above, you can do:
or
I'm not sure what a "good" solution for 3.0.x is for this. I guess at draw time we could call |
Thanks for giving such quick feedback. NeXpy has a checkbox for switching between linear and log scales, which we use all the time when looking for features on different intensity scales. It looks like replacing |
What do you do to change the intensity scale? If I do the following, it all seems to work fine, but maybe I'm misunderstanding. You shouldn't have to play around w/ shrink after you have initially made the colorbar. norm = LogNorm(z.min(), z.max())
im.set_norm(norm)
cbar.set_norm(norm)
cbar.update_normal(im)
cbar.config_axis()
# display in here, and then user changes zmax:
norm = LogNorm(z.min(), z.max()*10)
im.set_norm(norm)
cbar.set_norm(norm)
cbar.update_normal(im)
cbar.config_axis() |
To reproduce the shrinking: import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
x,y = np.ogrid[-4:4:31j,-4:4:31j]
z = 120000*np.exp(-x**2-y**2)
fig, ax = plt.subplots()
im = ax.imshow(z)
cbar = fig.colorbar(im)
# nopw change the data and scale
z*=1000
im.set_data(z)
norm = LogNorm(z.min(), z.max())
im.set_norm(norm)
cbar.set_norm(norm)
cbar.update_normal(im)
cbar.config_axis()
plt.show() |
Huh. That’s a very strange bug. I’ll check it out soon. |
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
x,y = np.ogrid[-4:4:31j,-4:4:31j]
z = 120000*np.exp(-x**2-y**2)
fig, ax = plt.subplots()
im = ax.imshow(z)
cbar = fig.colorbar(im)
norm = LogNorm(z.min(), z.max())
im.set_norm(norm)
cbar.set_norm(norm)
cbar.update_normal(im)
cbar.config_axis()
# display in here, and then user changes zmax * and* zmin...
norm = LogNorm(z.min() * 1000, z.max() * 1000)
im.set_norm(norm)
cbar.set_norm(norm)
cbar.update_normal(im)
cbar.config_axis()
plt.show() |
Fix in #12159 now fixes the above as well. Needs a test I guess... |
I think #12159 fixes this, but I guess I think if a GUI is going to change so much of the colorbar, it should indeed call That it used to work before is because we drew colorbars ticks by hand, basically. That it doesn't work now is that colorbars behave more like a normal axes and let the normal tick creation do its thing. Note that |
Bug report
Bug summary
After upgrading to Matplotlib v3.0.0, the tick marks on the colorbar are no longer placed correctly when using a matplotlib.colors.LogNorm normalization.
Code for reproduction
The code is embedded in a class defined within the NeXpy application, but uses standard Matplotlib function calls. Here are the relevant extracted lines:
Actual outcome
In Matplotlib v3.0.0, I get:

Expected outcome
In Matplotlib v2.2.3, I get:

Matplotlib version
I got the same result when using conda to install v3.0.0 or pip to install the latest development version.
The text was updated successfully, but these errors were encountered: