-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[ENH]: Allow override of contour level autoscaling #23778
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 agree that at the very least this should be an option. I think the original 3.0 "feature" to provide a contour that wasn't asked for is of pretty dubious value |
What ever we do to Looking at the code around matplotlib/lib/matplotlib/contour.py Lines 1161 to 1167 in 7c6a74c
Looking at the blame, this originally came in via #8719 (mpl2.1) to fix #7486 which crashed rather than continuing on if there was no data in the levels. It is probably worth revisiting given subsequent work on the Python side management around contouring and pulling contourpy out. I'm nominally in favor of changing this warning to say "and we will plot to contours in the future" and changing the default behavior, but we can not trade the current behavior for bringing back a crash ;) The user-side work around is to in your batch processing check the limits and do not call contour if nothing is in range. attn @ianthomas23 |
I can confirm that the "unwanted" contours were not present in 2.X (2.0.2, at least). My code has been running on python 2.7 (matplotlib 2.0.2) for years without any unwanted contours, but they appeared today when testing my code with python 3.10 (matplotlib 3.5.3). After struggling a bit, my attempted workaround was something close to what you said:
However, this workaround fails when the axes are only displaying a subset of the full array. For example, my |
That does track as we added it is 2.1. I do not think we are doing any clipping in x/y internally and are always considering the full data passed in so I assume you are doing the sub-selection? I would do something like def contour_safe(data, levels):
return np.any(data.max() > levels) & np.any(data.min() < levels)
if contour_safe(trimmed_data, levels):
ax.contour(..., trimmed_data, levels, ...) rather than trying to cache it. If you have this through out your code base, it might be worth writing a helper like def fixed_contour(...):
if contour_safe(...):
return plt.contour(...) (but that does require absorbing the type instability). Hopefully you can find-and-replace to victory of plt.contour -> fixed_contour. This approach should also be back and forward compatible. Did you have any other big surprises jumping from 2.0 -> 3.5 (effectively 6 feature releases!)? https://www.youtube.com/watch?v=LTMguK-XJEo might be of interest as well.... |
I'll take a look. I can't offhand think of any reason why the contouring itself needs it to be this way, and I have a vague recollection that it is the interaction with the colorbar which makes it more complicated. But that is a recollection from |
Looking into this, I think we are absolutely fine to remove the overriding of We should probably add a check for no levels specified by the user for a There are problems with the use of |
Problem
In Matplotlib 3, when using a list of values for the
levels
argument incontour()
, the list of values is overridden in the case that all requested levels fall outside the data range. While this may be desirable for casually browsing data when the user is unfamiliar with the data range, it causes serious problems for batch applications where the user legitimately intends to use their list of levels but does not know whether every input array will produce contours.Example:
The above prints
[0.0]
whendata
is an array of values ranging from 0 to 50 (i.e., the requested contour level of 100 is outside the data range). As a result, the plot contains erroneous contours around near-zero values, presumably due to floating point precision.This is a consequence of the change described here (https://matplotlib.org/stable/api/prev_api_changes/api_changes_3.0.0.html?highlight=contour%20levels):
Proposed solution
Add a kwarg to
contour()
that overrides the autoscaling behavior. When the kwarg is set, it would trigger a flag in_process_contour_level_args()
(https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/contour.py):The text was updated successfully, but these errors were encountered: