Skip to content

Segmentation fault with tricontour #10167

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
AndreiSavici opened this issue Jan 4, 2018 · 10 comments
Closed

Segmentation fault with tricontour #10167

AndreiSavici opened this issue Jan 4, 2018 · 10 comments

Comments

@AndreiSavici
Copy link

AndreiSavici commented Jan 4, 2018

Bug report

Bug summary

When enough NaNs are in the data, tricontour and tricontourf would result in a segmentation fault.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

x,y=np.meshgrid(np.arange(10),np.arange(10))
z=x**2.+y**2.
z[x<y]=np.nan
fig,ax=plt.subplots()
ax.tricontourf(x.ravel(),y.ravel(),z.ravel())
#ax.tripcolor(x.ravel(),y.ravel(),z.ravel(),vmax=100,vmin=0)
plt.show()

Actual outcome

Segmentation fault (core dumped)

Expected outcome
tripcolor gets a nice picture, no segmentation fault.
Here is the picture if I use ax.contourf(x,y,z) instead:

image

Matplotlib version

  • Operating system: Ubuntu 17.04
  • Matplotlib version: 2.1.1+887.g2296775da.dirty
  • Matplotlib backend (print(matplotlib.get_backend())):Qt5Agg
  • Python version: 2.7.13 and 3.5.3
  • Jupyter version (if applicable):
  • Other libraries:

I've tried both the deb package installed matplotlib, and the one from source. Also observed on older RHEL7 machine.

When running through gdb, it point to:

Thread 1 "python3" received signal SIGSEGV, Segmentation fault.
TriContourGenerator::follow_interior (this=this@entry=0x555556666c40, contour_line=..., tri_edge=..., end_on_boundary=end_on_boundary@entry=false, level=@0x7fffffffcd10: -1e-13, 
    on_upper=on_upper@entry=false) at lib/matplotlib/tri/_tri.cpp:916
916	        if (!end_on_boundary && _interior_visited[visited_index])

@jklymak
Copy link
Member

jklymak commented Jan 6, 2018

I see this on my Mac as well.

Interestingly, you get the same segfault for masked values as well, which removes the excuse of "don't use NaN".

It does work if you trim the bad values from x, y, and z, so it seems that tricontour just doesn't like dealing w/ bad data points...

mport numpy as np
import matplotlib.pyplot as plt

x,y=np.meshgrid(np.arange(10),np.arange(10))
z=x**2.+y**2.
z[x<y]=np.nan
x = x.ravel()
y = y.ravel()
z = z.ravel()
ind = x>=y
fig,ax=plt.subplots()
ax.tricontourf(x[ind], y[ind], z[ind])
#ax.tripcolor(x.ravel(),y.ravel(),z.ravel(),vmax=100,vmin=0)
plt.show()

@tacaswell
Copy link
Member

attn @ianthomas23

@ianthomas23
Copy link
Member

tricontour and tricontourfexpect the z argument to be an array of finite values, so no np.nan or np.infvalues, and the array cannot be a numpy masked array. Evidently we need to add explicit checks for these and raise an exception instead of allowing a segmentation fault to occur.

There are two ways around this limitation. The first, as suggested by @jklymak, is to only triangulate the points with finite z values. An example code snippet for this, assuming x, y and z are 1D arrays is

point_mask = np.isfinite(z)  # Points to keep.
ax.tricontourf(x[point_mask], y[point_mask], z[point_mask])

The second approach is to use the set_mask method of the Triangulation object, which exists for just this sort of problem where you have a triangulation but want to exclude specific triangles from being rendered. For example

import matplotlib.tri as mtri
triang = mtri.Triangulation(x, y)  # Delaunay triangulation of all points.
point_mask = ~np.isfinite(z)   # Points to mask out.
tri_mask = np.any(point_mask[triang.triangles], axis=1)  # Triangles to mask out.
triang.set_mask(tri_mask)
ax.tricontourf(triang, z, levels=np.arange(0, 151, 25))

Unfortunately, having looked into this I've discovered that you need to specify the contour levels as there is a second bug that non-finite z values are not filtered out before the z limits are determined, leading to incorrect contour levels. This needs a second PR, but is very simple to fix.

@ianthomas23 ianthomas23 self-assigned this Jan 10, 2018
@AndreiSavici
Copy link
Author

Just keeping the finite values is not enough. Sometimes having nans is important. In my case it's an indication that I did not measure at some point. I cannot put some arbitrary number, such as 0, since I did not measure that arbitrary value. If I just get rid of the nans, the tricontourf will just interpolate in that region. See the script below:

import numpy as np
import matplotlib.pyplot as plt

x,y=np.meshgrid(np.arange(10),np.arange(10))
z=x**2.+y**2.
z[np.logical_and(x<y,x+y>10)]=np.nan
fig,ax=plt.subplots()
ax.contourf(x,y,z)
ax.set_title('contourf')
fig.savefig('contourf.png')
ok=np.isfinite(z)
fig,ax=plt.subplots()
ax.tricontourf(x[ok],y[ok],z[ok])
ax.set_title('tricontourf')
fig.savefig('tricontourf.png')

contourf
tricontourf

@jklymak
Copy link
Member

jklymak commented Jan 10, 2018

I think the second approach @ianthomas23 has provided seems good. It seems _process_args could be easily extended to do this book keeping?

@AndreiSavici
Copy link
Author

Much better with separate triangulation:

triangulation

maxred5532 added a commit to charlespetchsy/matplotlib that referenced this issue Mar 14, 2018
@tacaswell tacaswell modified the milestones: needs sorting, v3.1 Jul 20, 2018
@jklymak
Copy link
Member

jklymak commented Feb 27, 2019

@ianthomas23 did you have a chance to look into this more?

@ianthomas23
Copy link
Member

@jklymak No, I've been ignoring it. But you are right to ping me about it. I have a change in work situation at the end of March that should free up some time so that I can look at such things. I'll write a PR then.

@tacaswell tacaswell modified the milestones: v3.1.0, v3.1.1 Feb 28, 2019
@tacaswell
Copy link
Member

re-milestoned for the first 3.1.x bug-fix release.

ianthomas23 added a commit to ianthomas23/matplotlib that referenced this issue Apr 25, 2019
efiring added a commit that referenced this issue May 29, 2019
Gracefully handle non-finite z in tricontour (issue #10167)
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this issue Jun 10, 2019
ivanov added a commit that referenced this issue Jun 10, 2019
…040-on-v3.1.x

Backport PR #14040 on branch v3.1.x (Gracefully handle non-finite z in tricontour (issue #10167))
@efiring
Copy link
Member

efiring commented Jun 17, 2019

Closed by #14040.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants