-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
BUG: Contours with LogNorm #19856
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
I'm not sure what you feel the bug is. It would be better if you provided some data. Thanks! |
Oh I see you specified the bug in your code. I believe we use a LogLocator to determine the levels if you use a log norm. It's possible/likely this doesn't interact well with the nlevels argument. But it does provide equal decade levels, which is probably worth it. I am still not clear what you feel is wrong with the second plot because you didn't specify what levels you set. |
the levels are defined as an array, supposedly I'm defining 4 (= n-1, with n=5) of them levels = np.logspace(np.log10(data.min()), np.log10(data.max()), 5) I think the plot itself is what I want, but the colorbar is broken in that I only get on tick label, and the minor ticks don't make any sense to me. |
What do you think should happen? I guess the other labels not being labeled is bad, but otherwise the ticking seems ok to me. You have put five log-spaced levels with an arbitrary starting point. The minor ticks are just the normal minor ticks. Note that much of this will change in 3.5 with the colorbar axis overhaul; colorbar axes will behave like normal axes as far as possible. |
The ticking itself seems off to me because the pattern seen in minor ticks is offset from one level to an other. I'm not sure I'm making myself clear (second language, sorry), so I'll try an alternative phrasing as well:
Sounds like fixing this for the 3.4 branch only might be a waste of time then. I'm curious, what's the status of this overhaul ? |
The minor ticks are ticking out tenths of decades. Your major ticks are ticking out arbitrary spacing in log space. They are definitely not going to line up. |
Oh right, I guess I was expecting the minor ticks to magically retro-engineer my arbitrary spacing and line up somehow (not even sure how actually, there's no obvious generalization of decades that would work with arbitrary spacing)... What I actually want is to have more than one color per decade, maybe there's just something I'm missing here ? |
I would just manually set the level, but I'd start with integer decades for the min and max. |
So I tried to do just that and, for the specific example I used in the report, I find that this works as intended levels = np.concatenate(
[
10**n * np.arange(1, 10, dtype="float64")
for n in range(-2, 7)
]
) Thought this doesn't (labels in the colorbar are still missing) levels = np.concatenate(
[
10**n * np.arange(1, 10, dtype="float64")
for n in range(-2, 6) # <--- changed the upper boundary here
]
) Note that in both cases I'm reaching over the actual maximal value in the data (which is a little under 2e4) by at least one full decade, and I apparently need to add another one to get a sensible result, leading unused colors at the end of the cmap. |
Please provide a self-contained runnable script. Thanks! |
Here you go ! import matplotlib.pyplot as plt
import matplotlib.colors import LogNorm
import numpy as np
x, y = np.mgrid[1:10:0.1, 1:10:0.1]
data = np.abs(np.sin(x)*np.exp(y))
# CASE 0,a: leave norm unspecified, pass an int value to the `levels` keyword argument
# RESULT: works fine
fig, ax = plt.subplots()
im = ax.contourf(x, y, data, levels=4)
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug0a.png")
# CASE 0,b: specify a log norm, leave levels unspecified
# RESULT: works fine, but only one level is used per decade
fig, ax = plt.subplots()
im = ax.contourf(x, y, data, norm=LogNorm())
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug0b.png")
# CASE 1: pass an int value to the `levels` keyword argument
# RESULT: the argument is ignored
fig, ax = plt.subplots()
im = ax.contourf(x, y, data, norm=LogNorm(), levels=4)
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug1.png")
# CASE 2: construct arbitrary levels that don't match whole decades
# RESULT: major ticks' labels are not displayed, except for the second one
fig, ax = plt.subplots()
levels = np.logspace(np.log10(data.min()), np.log10(data.max()), 5)
im = ax.contourf(x, y, data, norm=LogNorm(), levels=levels)
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug2.png")
# CASE 3: construct arbitrary levels, matching whole decades
# RESULT: this one works fine, but the max value is more than one decade above the
# actual max value in the data, so the extreme colors in the colormap are not used.
levels = np.concatenate(
[
10**n * np.arange(1, 10, dtype="float64")
for n in range(-2, 7)
]
)
fig, ax = plt.subplots()
im = ax.contourf(x, y, data, norm=LogNorm(), levels=levels)
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug3.png")
# CASE 4: same as case 3, but max level is closer to global max in the data
# RESULT: colorbar labels are missing (except for the min value, 1e-2)
levels = np.concatenate(
[
10**n * np.arange(1, 10, dtype="float64")
for n in range(-2, 6) # <--- changed the upper boundary here
]
)
fig, ax = plt.subplots()
im = ax.contourf(x, y, data, norm=LogNorm(), levels=levels)
fig.colorbar(im, ax=ax)
plt.savefig("/tmp/mpl_logcontours_bug4.png") |
Thanks, thats super helpful. You are kind of reporting a couple of issues here:
it works fine, so I wonder if in
|
I'll make 1 as a good first issue, though it may have some back-combat issues that will need to be tested. |
@jklymak Shall I work on the 1st? Seems easy enough for me to begin! |
You can provide an arbitrary base to matplotlib/lib/matplotlib/ticker.py Lines 879 to 881 in 612cfae
This will (probably) also show the ticks, which seems to be removed by: matplotlib/lib/matplotlib/ticker.py Lines 1073 to 1075 in 612cfae
and matplotlib/lib/matplotlib/ticker.py Lines 1081 to 1082 in 612cfae
|
Bug report
Bug summary
Contour plots don't interact nicely with
matplotlib.colors.LogNorm
.Likely related to #19748
Code for reproduction
Expected outcome
The experience should be comparable with what happens when the norm isn't specified: the
levels
kwarg should be usable in both cases.I note that the output from the first snippet is consistent with the case where neither
levels
ornorm
are specified, and is correct in that case, so it's definetely not completely broken and I hope the fix is somewhat straightforward.I'm happy to take a look at the source and see if I can come up with an easy patch, but I'm not sure when I'll have time to dive in there myself. Any piece advice from maintainers or contributors is more than welcome !
Matplotlib version
import matplotlib; print(matplotlib.__version__)
): 3.4.1print(matplotlib.get_backend())
):module://ipykernel.pylab.backend_inline
I installed matplotlib using pip.
The text was updated successfully, but these errors were encountered: