Skip to content

plt.contour levels parameter don't work as intended if receive a single int #11913

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
eisterman opened this issue Aug 22, 2018 · 5 comments · Fixed by #11917
Closed

plt.contour levels parameter don't work as intended if receive a single int #11913

eisterman opened this issue Aug 22, 2018 · 5 comments · Fixed by #11917
Assignees
Milestone

Comments

@eisterman
Copy link

Bug report

Bug summary

The official documentation (https://matplotlib.org/api/_as_gen/matplotlib.pyplot.contour.html) says that the parameter levels of the pyplot.contour function is an integer will be calculated and shown a number of contours equal to the number passed as a parameter.
The reality of the facts, however, is that the outline associated with the past value is plotted.

Code for reproduction

I used the contour demo example from https://matplotlib.org/gallery/images_contours_and_fields/contour_demo.html#contour-demo adding the levels parameter as int.

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
# the original demo had 2 here, but so most of the values would have been less than 5
Z = (Z1 - Z2) * 6

plt.contour(X, Y, Z, levels=5)
plt.show()

Actual outcome

Output_bug_1

Expected outcome

According to official documentation I should expect 5 outlines and not the boundary associated with the value 5.
Right_outcome_1

The expected output was obtained by modifying the penultimate line in:

plt.contour(X, Y, Z, levels=np.linspace(np.min(Z),np.max(Z),7))

Matplotlib version

  • Operating system: Arch Linux
  • Matplotlib version: 2.2.3
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.7.0
  • Other libraries: numpy

All libraries have been installed via the official ArchLinux repository

@jklymak
Copy link
Member

jklymak commented Aug 22, 2018

Yeah, this is a bit funky. It works fine if you do: plt.contour(X, Y, Z, 5). So if you specify levels as a kwarg, it assumes you have entered the actual levels you want contoured. Its debatable if this is desirable or not - I'd vote for it being undesirable, and levels=5 should behave as you expected it should (i.e. the same as if 5 was passed in as a positional argument), but maybe the original authors had a reason for this behaviour.

I would say that levels=[5] should only make one contour.

@jklymak jklymak added this to the v3.1 milestone Aug 22, 2018
@jklymak
Copy link
Member

jklymak commented Aug 22, 2018

Milestoning 3.1, since this behaviour has been present since at least 2.0.2

@tacaswell
Copy link
Member

I think @efiring changed some of this for 3.0 already.

@jklymak
Copy link
Member

jklymak commented Aug 22, 2018

Well, yes. Its worse (?) on master:

Traceback (most recent call last):
  File "testCont.py", line 15, in <module>
    plt.contour(X, Y, Z, levels=5)
  File "/Users/jklymak/matplotlib/lib/matplotlib/pyplot.py", line 2544, in contour
    __ret = gca().contour(*args, data=data, **kwargs)
  File "/Users/jklymak/matplotlib/lib/matplotlib/__init__.py", line 1763, in inner
    return func(ax, *args, **kwargs)
  File "/Users/jklymak/matplotlib/lib/matplotlib/axes/_axes.py", line 6209, in contour
    contours = mcontour.QuadContourSet(self, *args, **kwargs)
  File "/Users/jklymak/matplotlib/lib/matplotlib/contour.py", line 887, in __init__
    kwargs = self._process_args(*args, **kwargs)
  File "/Users/jklymak/matplotlib/lib/matplotlib/contour.py", line 1499, in _process_args
    x, y, z = self._contour_args(args, kwargs)
  File "/Users/jklymak/matplotlib/lib/matplotlib/contour.py", line 1569, in _contour_args
    self._contour_level_args(z, args)
  File "/Users/jklymak/matplotlib/lib/matplotlib/contour.py", line 1255, in _contour_level_args
    if len(self.levels) > 1 and np.min(np.diff(self.levels)) <= 0.0:
TypeError: len() of unsized object

@efiring
Copy link
Member

efiring commented Aug 22, 2018

I see where the problem is.

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

Successfully merging a pull request may close this issue.

5 participants