Skip to content

plt.contour with all NaNs fails assertion in _contour.cpp #14124

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
shoyer opened this issue May 4, 2019 · 6 comments · Fixed by #25334
Closed

plt.contour with all NaNs fails assertion in _contour.cpp #14124

shoyer opened this issue May 4, 2019 · 6 comments · Fixed by #25334
Labels
Good first issue Open a pull request against these issues if there are no active ones! topic: contour
Milestone

Comments

@shoyer
Copy link

shoyer commented May 4, 2019

Bug report

Bug summary

Passing an array with all NaN values into pyplot.contour() causes the following assertion to fail in QuadContourGenerator::init_cache_levels:
https://github.com/matplotlib/matplotlib/blob/v3.0.3/src/_contour.cpp#L1317-L1318

This is actually triggered by a test-case in the xarray test suite, but I imagine it hasn't been noticed (yet) because release builds of matplotlib typically disable assertion checks.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

x = np.array([[np.nan, np.nan], [np.nan, np.nan]])
plt.contour(x)

Actual outcome

Failed assertion (see referenced line above, tracked down with gdb)

Expected outcome

I would expect to see the empty plot (and long lists of warnings) that are currently shown if assertions are disabled:
image

Matplotlib version

  • Operating system: Linux
  • Matplotlib version: 3.0.3
  • Matplotlib backend (print(matplotlib.get_backend())): agg
  • Python version: 3.6

Python, matplotlib, etc are installed from source

@efiring
Copy link
Member

efiring commented Jun 2, 2019

@ianthomas23 would you like to look at this? It sounds like maybe more early-stage argument checking is needed.

@ianthomas23
Copy link
Member

The assertions in _contour.cpp are to help with debugging, in particularly to identify when the C++ code is called with strange arguments. In this example a C++ QuadContourGenerator object is created for a 2D array of NaNs and then it is asked to contour a z level of NaN. The C++ code will walk through the 2D array looking for contours at the NaN level, not find any and return an empty contour set.

The C++ assertion is a distraction here, although it did help to identify the problem. For an array of NaNs there is no point in ever accessing the C++ contouring code as there are no contours to find. A better approach would be for the python code (contour.py) to identify that the z array is all NaNs early on and never call the C++ code.

There is a question of policy here. When trying to contour an array of NaNs, do we (1) report a warning and return a valid but empty contour set, or (2) raise an exception instead?

@efiring
Copy link
Member

efiring commented Jun 6, 2019

I think the prevailing policy, and a good one, is to return empty but valid objects, like this:

In [5]: plt.plot([np.nan], [np.nan])
[<matplotlib.lines.Line2D at 0x120171cf8>]

@timhoffm
Copy link
Member

timhoffm commented Jul 21, 2019

The current behavior as of master is to spit out a lot of warnings, but actually draw the figure (original example from above):

In [5]: plt.contour(x)                                                                     
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1498: UserWarning: Warning: converting a masked element to nan.
  self.zmax = float(z.max())
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1499: UserWarning: Warning: converting a masked element to nan.
  self.zmin = float(z.min())
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1144: RuntimeWarning: invalid value encountered in less
  under = np.nonzero(lev < self.zmin)[0]
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1146: RuntimeWarning: invalid value encountered in greater
  over = np.nonzero(lev > self.zmax)[0]
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1175: RuntimeWarning: invalid value encountered in greater
  inside = (self.levels > self.zmin) & (self.levels < self.zmax)
/home/tim/dev/matplotlib/lib/matplotlib/contour.py:1175: RuntimeWarning: invalid value encountered in less
  inside = (self.levels > self.zmin) & (self.levels < self.zmax)
/home/tim/anaconda3/envs/mpl-old/bin/ipython:5: UserWarning: No contour levels were found within the data range.
  import sys
Out[4]: <matplotlib.contour.QuadContourSet at 0x7ff370747c18>

So, basically as desired. However the number of warnings could be reduced.

Implementing just one warning will be cumbersome. Either you follow the original code path but prevent all the above warnings when they occur. Or you break early, but then you have to make sure, you still get a valid QuadContourSet (leaving out parts of __init__ can lead to some attributes not being defined).

@tacaswell tacaswell added this to the v3.2.0 milestone Jul 21, 2019
@tacaswell tacaswell modified the milestones: v3.2.0, needs sorting Sep 10, 2019
@oscargus
Copy link
Member

Now there are fewer warnings:

/local/data1/matplotlib/lib/matplotlib/contour.py:1459: UserWarning: Warning: converting a masked element to nan.
  self.zmax = float(z.max())
/local/data1/matplotlib/lib/matplotlib/contour.py:1460: UserWarning: Warning: converting a masked element to nan.
  self.zmin = float(z.min())
<ipython-input-1-1b8de0dba6a5>:5: UserWarning: No contour levels were found within the data range.

Probably few enough to add a smoke test so that it doesn't break again and close this issue.

@oscargus oscargus added Good first issue Open a pull request against these issues if there are no active ones! topic: contour labels Dec 15, 2022
@oscargus
Copy link
Member

Marking as good first issue as it is only to create a test (using the original code above) that catches the warnings. Not sure how the catch-and-match-logic behaves with three warnings though.

Make sure to add a comment like:

# Smoke test for gh#14124

in the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good first issue Open a pull request against these issues if there are no active ones! topic: contour
Projects
None yet
7 participants