Skip to content

Contour kills Python #7486

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
godaygo opened this issue Nov 19, 2016 · 13 comments
Closed

Contour kills Python #7486

godaygo opened this issue Nov 19, 2016 · 13 comments
Labels
Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
Milestone

Comments

@godaygo
Copy link

godaygo commented Nov 19, 2016

Matplotlib kills Python with:

plt.contour( [[1]], [[1]], [[1]])

Matplotlib 1.5.3
Python 3.5.2
Windows 10

@tacaswell tacaswell added this to the 2.0.1 (next bug fix release) milestone Nov 20, 2016
@tacaswell tacaswell added Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues new-contributor-friendly labels Nov 20, 2016
@tacaswell
Copy link
Member

00:06 $ ipython
Python 3.5.2 |Continuum Analytics, Inc.| (default, Jul  2 2016, 17:53:06) 
Type "copyright", "credits" or "license" for more information.

IPython 5.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import matplotlib.pyplot as plt

In [2]: plt.ion()

In [3]: plt.contour( [[1]], [[1]], [[1]])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-b799b0b3bd2d> in <module>()
----> 1 plt.contour( [[1]], [[1]], [[1]])

/home/tcaswell/src/p/matplotlib/lib/matplotlib/pyplot.py in contour(*args, **kwargs)
   2777         ax.hold(hold)
   2778     try:
-> 2779         ret = ax.contour(*args, **kwargs)
   2780     finally:
   2781         ax.hold(washold)

/home/tcaswell/src/p/matplotlib/lib/matplotlib/__init__.py in inner(ax, *args, **kwargs)
   1878                     warnings.warn(msg % (label_namer, func.__name__),
   1879                                   RuntimeWarning, stacklevel=2)
-> 1880             return func(ax, *args, **kwargs)
   1881         pre_doc = inner.__doc__
   1882         if pre_doc is None:

/home/tcaswell/src/p/matplotlib/lib/matplotlib/axes/_axes.py in contour(self, *args, **kwargs)
   5810             self.cla()
   5811         kwargs['filled'] = False
-> 5812         contours = mcontour.QuadContourSet(self, *args, **kwargs)
   5813         self.autoscale_view()
   5814         return contours

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in __init__(self, ax, *args, **kwargs)
   1419         are described in QuadContourSet.contour_doc.
   1420         """
-> 1421         ContourSet.__init__(self, ax, *args, **kwargs)
   1422 
   1423     def _process_args(self, *args, **kwargs):

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in __init__(self, ax, *args, **kwargs)
    862 
    863         self._process_args(*args, **kwargs)
--> 864         self._process_levels()
    865 
    866         if self.colors is not None:

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in _process_levels(self)
   1202         # The following attributes are no longer needed, and
   1203         # should be deprecated and removed to reduce confusion.
-> 1204         self.vmin = np.amin(self.levels)
   1205         self.vmax = np.amax(self.levels)
   1206 

/home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/fromnumeric.py in amin(a, axis, out, keepdims)
   2395     else:
   2396         return _methods._amin(a, axis=axis,
-> 2397                             out=out, **kwargs)
   2398 
   2399 

/home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/_methods.py in _amin(a, axis, out, keepdims)
     27 
     28 def _amin(a, axis=None, out=None, keepdims=False):
---> 29     return umr_minimum(a, axis, None, out, keepdims)
     30 
     31 def _sum(a, axis=None, dtype=None, out=None, keepdims=False):

ValueError: zero-size array to reduction operation minimum which has no identity

In [4]: %debug
> /home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/_methods.py(29)_amin()
     27 
     28 def _amin(a, axis=None, out=None, keepdims=False):
---> 29     return umr_minimum(a, axis, None, out, keepdims)
     30 
     31 def _sum(a, axis=None, dtype=None, out=None, keepdims=False):

ipdb> u
> /home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/fromnumeric.py(2397)amin()
   2395     else:
   2396         return _methods._amin(a, axis=axis,
-> 2397                             out=out, **kwargs)
   2398 
   2399 

ipdb> u
> /home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py(1204)_process_levels()
   1202         # The following attributes are no longer needed, and
   1203         # should be deprecated and removed to reduce confusion.
-> 1204         self.vmin = np.amin(self.levels)
   1205         self.vmax = np.amax(self.levels)
   1206 

ipdb> self.levels
array([], dtype=float64)
ipdb> 

I do not get it to kill python, but get the above exception (with numpy 1.11, might be different from OP).

The issues here seems to be that when we try to find the levels we prune them to levels inside of the data range via

# For line contours, drop levels outside the data range.
        return lev[(lev > zmin) & (lev < zmax)]

in mpl.contour.CountourSet._autolev

which if the data is singular results in no levels and hence the issue.

The specific work here is to:

  • adapt _autolev to do something 'sensible' in the singular case. Probably we should return 2 levels using our standard expand_non_singular method?

This is a very limited change (so new-contributor friendly), but might require careful thought about what it should do in the singular case, hence medium difficulty.

@tacaswell
Copy link
Member

@godaygo Thanks for reporting this!

@efiring
Copy link
Member

efiring commented Nov 20, 2016

@tacaswell, I don't see any point in making levels--contouring is fundamentally impossible without a single cell, which requires at least a 2x2. I think the thing to do raise a ValueError early on if any input array has a dimension less than 2.

@WeatherGod
Copy link
Member

This may be numpy-specific. I think we ran into a similar error recently in
plot_surface() when trying to broadcast empty arrays, or something like
that. I agree that a ValueError should be raised if the resulting X/Y
domain shape is less than 2x2.

On Sun, Nov 20, 2016 at 1:30 AM, Eric Firing notifications@github.com
wrote:

@tacaswell https://github.com/tacaswell, I don't see any point in
making levels--contouring is fundamentally impossible without a single
cell, which requires at least a 2x2. I think the thing to do raise a
ValueError early on if any input array has a dimension less than 2.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#7486 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AARy-DS06MbkE6i650u1MY-1tyyZsBUtks5q_-jwgaJpZM4K3UbL
.

@tacaswell
Copy link
Member

You get the same exception with a uniform field

In [7]: x, y = np.meshgrid(np.linspace(0, 1, 5), np.linspace(0, 1, 7))

In [8]: x.shape
Out[8]: (7, 5)

In [9]: plt.contour(x, y, np.ones_like(x))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-9-4b654997b57e> in <module>()
----> 1 plt.contour(x, y, np.ones_like(x))

/home/tcaswell/src/p/matplotlib/lib/matplotlib/pyplot.py in contour(*args, **kwargs)
   2777         ax.hold(hold)
   2778     try:
-> 2779         ret = ax.contour(*args, **kwargs)
   2780     finally:
   2781         ax.hold(washold)

/home/tcaswell/src/p/matplotlib/lib/matplotlib/__init__.py in inner(ax, *args, **kwargs)
   1878                     warnings.warn(msg % (label_namer, func.__name__),
   1879                                   RuntimeWarning, stacklevel=2)
-> 1880             return func(ax, *args, **kwargs)
   1881         pre_doc = inner.__doc__
   1882         if pre_doc is None:

/home/tcaswell/src/p/matplotlib/lib/matplotlib/axes/_axes.py in contour(self, *args, **kwargs)
   5810             self.cla()
   5811         kwargs['filled'] = False
-> 5812         contours = mcontour.QuadContourSet(self, *args, **kwargs)
   5813         self.autoscale_view()
   5814         return contours

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in __init__(self, ax, *args, **kwargs)
   1419         are described in QuadContourSet.contour_doc.
   1420         """
-> 1421         ContourSet.__init__(self, ax, *args, **kwargs)
   1422 
   1423     def _process_args(self, *args, **kwargs):

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in __init__(self, ax, *args, **kwargs)
    862 
    863         self._process_args(*args, **kwargs)
--> 864         self._process_levels()
    865 
    866         if self.colors is not None:

/home/tcaswell/src/p/matplotlib/lib/matplotlib/contour.py in _process_levels(self)
   1202         # The following attributes are no longer needed, and
   1203         # should be deprecated and removed to reduce confusion.
-> 1204         self.vmin = np.amin(self.levels)
   1205         self.vmax = np.amax(self.levels)
   1206 

/home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/fromnumeric.py in amin(a, axis, out, keepdims)
   2395     else:
   2396         return _methods._amin(a, axis=axis,
-> 2397                             out=out, **kwargs)
   2398 
   2399 

/home/tcaswell/mc3/envs/dd35/lib/python3.5/site-packages/numpy/core/_methods.py in _amin(a, axis, out, keepdims)
     27 
     28 def _amin(a, axis=None, out=None, keepdims=False):
---> 29     return umr_minimum(a, axis, None, out, keepdims)
     30 
     31 def _sum(a, axis=None, dtype=None, out=None, keepdims=False):

ValueError: zero-size array to reduction operation minimum which has no identity

Erroring on non-sensible sized arrays in a different issue

@godaygo
Copy link
Author

godaygo commented Nov 20, 2016

I'm using numpy 1.11.2+mkl from Gohlke, and I start script from Windows cmd (if it helps),
and plt.contour([[1]]) is also enough to kill Python on my computer.
carsh

@tacaswell yes I have the same traceback
... ValueError: zero-size array to reduction operation minimum which has no identity

@QuLogic QuLogic modified the milestones: 2.0.1 (next bug fix release), 2.0.2 (next bug fix release) May 3, 2017
@cgohlke
Copy link
Contributor

cgohlke commented May 3, 2017

For sake of completeness: the segfault on Windows is at _contour.cpp#L1225. The modulo operation i % _chunk_size is undefined when _chunk_size == 0.

Call Stack:

>	_contour.cp36-win_amd64.pyd!QuadContourGenerator::init_cache_grid(const numpy::array_view<bool const ,2> & mask) Line 1225	C++
 	_contour.cp36-win_amd64.pyd!QuadContourGenerator::QuadContourGenerator(const numpy::array_view<double const ,2> & x, const numpy::array_view<double const ,2> & y, const numpy::array_view<double const ,2> & z, const numpy::array_view<bool const ,2> & mask, bool corner_mask, long chunk_size) Line 376	C++
 	_contour.cp36-win_amd64.pyd!PyQuadContourGenerator_init(PyQuadContourGenerator * self, _object * args, _object * kwds) Line 58	C++
 	python36.dll!type_call(_typeobject * type, _object * args, _object * kwds) Line 916	C

Locals:

-		this	0x000001c10a45c940 {_x={m_arr=0x000001c10c0c9120 {ob_base={ob_refcnt=2 ob_type=multiarray.cp36-win_amd64.pyd!0x00007ffd78b21c80 {...} } } ...} ...}	QuadContourGenerator *
+		_x	{m_arr=0x000001c10c0c9120 {ob_base={ob_refcnt=2 ob_type=multiarray.cp36-win_amd64.pyd!0x00007ffd78b21c80 {...} } } ...}	numpy::array_view<double const ,2>
+		_y	{m_arr=0x000001c10c0c90d0 {ob_base={ob_refcnt=2 ob_type=multiarray.cp36-win_amd64.pyd!0x00007ffd78b21c80 {...} } } ...}	numpy::array_view<double const ,2>
+		_z	{m_arr=0x000001c10c0c9080 {ob_base={ob_refcnt=4 ob_type=multiarray.cp36-win_amd64.pyd!0x00007ffd78b21c80 {...} } } ...}	numpy::array_view<double const ,2>
		_nx	1	long
		_ny	1	long
		_n	1	long
		_corner_mask	true	bool
		_chunk_size	0	long
		_nxchunk	1	long
		_nychunk	1	long
		_chunk_count	1	long
+		_cache	0x000001c10ad73a70 {0}	unsigned int *
+		_parent_cache	{_nx=1 _x_chunk_points=1 _y_chunk_points=1 ...}	ParentCache
		i	0	long
		j	0	long
+		mask	{m_arr=0x0000000000000000 <NULL> m_shape=0x00007ffd934499d0 {_contour.cp36-win_amd64.pyd!__int64 numpy::zeros[3]} {...} ...}	const numpy::array_view<bool const ,2> &
		quad	0	long

@ianthomas23
Copy link
Member

I'll submit a PR to deal with the i % _chunk_size undefined when _chunk_size == 0 in the C++ code. But isn't this a separate problem to that reported by OP?

@cgohlke
Copy link
Contributor

cgohlke commented May 3, 2017

But isn't this a separate problem to that reported by OP?

Modulo by zero is the immediate cause of the crash reported by OP.

@ianthomas23
Copy link
Member

@cgohlke Discussions between @tacaswell, @efiring and @WeatherGod are all about contouring with zero levels, showing stack traces in the python code before any of the C++ is called. Hence there are two separate issues.

@tacaswell
Copy link
Member

@ianthomas23 Is there a PR for the _chunk_size ==0 issues?

@ianthomas23
Copy link
Member

@tacaswell No, not yet. I hope to write one soon.

dstansby added a commit that referenced this issue Jun 14, 2017
BUG: handle empty levels array in contour, closes #7486
@QuLogic QuLogic modified the milestones: 2.1 (next point release), 2.0.3 (next bug fix release) Jun 14, 2017
@ianthomas23
Copy link
Member

@tacaswell It turns out that the _chunk_size == 0 issue was fixed in March by PR #8227.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
Projects
None yet
Development

No branches or pull requests

7 participants