Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Added support for providing 1 or 2 extra colours to the contour routines to easily specify the under and over colors. #2002

Merged
merged 3 commits into from May 21, 2013

Conversation

Projects
None yet
3 participants
Member

pelson commented May 14, 2013

I had a question from a colleague the other day about being able to specify the under and over colors of a contour.

The solution was:

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(12).reshape(3, 4)

colors = ['red', 'yellow', 'pink', 'blue', 'black']
levels = [2, 4, 8, 10]

cs = plt.contourf(data, colors=colors[1:-1], levels=levels, extend='both')
plt.colorbar()
cs.cmap.set_under(colors[0])
cs.cmap.set_over(colors[-1])
cs.changed()

plt.show()

This PR makes the lines:

cs.cmap.set_under(colors[0])
cs.cmap.set_over(colors[-1])
cs.changed()

redundant.

If the user specifies n_colors = n_levels + n_extends then the appropriate set_under and set_over behaviour kicks in.

This change also fixes a bug with contour (i.e. not contourf) and its handling of extend:

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(12).reshape(3, 4)
colors = ['red', 'yellow', 'pink', 'blue', 'black']
levels = [2, 4, 8]
cs = plt.contour(data, colors=colors, levels=levels, extend='both')
plt.colorbar()
plt.show()

Results in:

  ...
  File "matplotlib/colorbar.py", line 777, in _mesh
    y = self._uniform_y(self._central_N())
  File "matplotlib/colorbar.py", line 714, in _uniform_y
    automin = automax = 1. / (N - 1.)
ZeroDivisionError: float division by zero

For the record, this PR is a functional change. The test results image before the code changes in this PR look like:

before

Compare this with the result image in this PR: https://github.com/matplotlib/matplotlib/pull/2002/files#diff-1

@pelson pelson Added support for providing 1 or 2 extra colours to the contour routi…
…nes to easily specify the under and over colors.
a736819
Member

pelson commented May 15, 2013

@efiring - I would really value your input on this given how much knowledge you have of the contour code.

@efiring efiring and 1 other commented on an outdated diff May 15, 2013

lib/matplotlib/contour.py
- cmap = colors.ListedColormap(self.colors, N=ncolors)
+
+ # Handle the case where colors are given for the extended
+ # parts of the contour.
+ given_colors = self.colors
+ extend_min = self.extend in ['min', 'both']
+ extend_max = self.extend in ['max', 'both']
+ use_set_under_over = False
+ # if we are extending the lower end, and we've been given enough colors
+ # then skip the first color in the resulting cmap.
+ total_levels = ncolors + int(extend_min) + int(extend_max)
+ if len(self.colors) == total_levels and any([extend_min, extend_max]):
+ use_set_under_over = True
+ if extend_min:
+ given_colors = given_colors[1:]
+
@efiring

efiring May 15, 2013

Owner

It is not clear why you don't need to clip the end off of given_colors in the extend_max case--I think you do, but I haven't looked closely.
Instead of making a new variable, given_colors, and then chopping off one or both ends, you could generate slice indices:

i0, i1 = 0, None

Then inside the "extended" block:

if extend_min:
    i0 = 1
if extend_max:
    i1 = -1

Then in ListedColormap, use self.colors[i0:i1]

@pelson

pelson May 17, 2013

Member

Nice suggestion.

We don't need to index the colors off the top because passing N through to ListedColormap truncates the colors for us.

Owner

efiring commented May 15, 2013

Overall, this seems like a nice change, making the interface more intuitive.

Member

pelson commented May 17, 2013

Thanks @efiring - I've added that suggestion.

@efiring efiring commented on an outdated diff May 17, 2013

lib/matplotlib/contour.py
@@ -864,7 +864,29 @@ def __init__(self, ax, *args, **kwargs):
ncolors = len(self.levels)
if self.filled:
ncolors -= 1
- cmap = colors.ListedColormap(self.colors, N=ncolors)
+ i0, i1 = 0, None
+ # Handle the case where colors are given for the extended
+ # parts of the contour.
+ extend_min = self.extend in ['min', 'both']
+ extend_max = self.extend in ['max', 'both']
+ use_set_under_over = False
+ # if we are extending the lower end, and we've been given enough
+ # colors then skip the first color in the resulting cmap.
+ total_levels = ncolors + int(extend_min) + int(extend_max)
+ if len(self.colors) == total_levels and \
@efiring

efiring May 17, 2013

Owner

Style police citation: no trailing backslash, please.

@efiring efiring and 1 other commented on an outdated diff May 17, 2013

lib/matplotlib/contour.py
+ i0, i1 = 0, None
+ # Handle the case where colors are given for the extended
+ # parts of the contour.
+ extend_min = self.extend in ['min', 'both']
+ extend_max = self.extend in ['max', 'both']
+ use_set_under_over = False
+ # if we are extending the lower end, and we've been given enough
+ # colors then skip the first color in the resulting cmap.
+ total_levels = ncolors + int(extend_min) + int(extend_max)
+ if len(self.colors) == total_levels and \
+ any([extend_min, extend_max]):
+ use_set_under_over = True
+ if extend_min:
+ i0 = 1
+
+ cmap = colors.ListedColormap(self.colors[i0:i1], N=ncolors)
@efiring

efiring May 17, 2013

Owner

So, you really don't need i1 after all. I suggest eliminating it in favor of None, and adding to the comment above the reason why you don't need to chop the top.

@pelson

pelson May 17, 2013

Member

Have done. Thanks @efiring.

Member

pelson commented May 20, 2013

I think this is now good to go.

Owner

efiring commented May 20, 2013

Doesn't it need a change to the contourf docstring and some mention in api changes? Sorry I didn't mention these before--I assumed you were just holding off on them because you were unsure as to whether the actual change would be acceptable.

Member

pelson commented May 21, 2013

There's a python3.3 test failiure on travis (not a result of this change). Other than that, the tests are passing, so when you're happy @efiring, please press merge 😉

@mdboom mdboom added a commit that referenced this pull request May 21, 2013

@mdboom mdboom Merge pull request #2002 from pelson/contour_levels_with_colors
Added support for providing 1 or 2 extra colours to the contour routines to easily specify the under and over colors.
355b056

@mdboom mdboom merged commit 355b056 into matplotlib:master May 21, 2013

1 check failed

default The Travis CI build failed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment