Skip to content

contourf with custom colormap #16629

Closed
Closed

Description

@Skillmon

Bug report

Using a custom colormap created with LinearSegmentedColormap.from_list, contourf doesn't seem to use the correct colours for every value.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap


def color_grid(xx, classes):
    x = xx.ravel()
    Z = np.zeros(x.shape)
    dx = (x.max() - x.min())/classes
    for i in range(classes):
        Z[(i * dx <= x) & ((i + 1) * dx >= x)] = i
    return Z.reshape(xx.shape)


colors = ['b',
          'r',
          'm',
          'c',
          'g',
          'xkcd:orange',
          'xkcd:peach',
          'xkcd:bright pink',
          'xkcd:crimson']


xx, yy = np.meshgrid(np.arange(0, 10, 0.02), np.arange(0, 10, 0.02))
fig, sub = plt.subplots(len(colors)-1, 1)

for i, ax in enumerate(sub.flatten()):
    cm = LinearSegmentedColormap.from_list('foo', colors[0:i+2], i+2)
    Z = color_grid(xx, i+2)
    ax.contourf(xx, yy, Z, cmap=cm)
plt.show()

Actual outcome

mwe

Expected outcome

I expected the colours to be correctly picked, meaning an increasing number of different colours in each subplot from top to bottom with each bar in a row roughly the same size (since that's what Z should look like).

Matplotlib version

  • Operating system: Arch Linux
  • Matplotlib version: 3.1.3
  • Matplotlib backend (print(matplotlib.get_backend())): PGF with PDF output, GTK3Agg
  • Python version: 3.8.1
  • Other libraries: numpy

Installed from Arch Linux repositories.

Activity

  1. Skillmon commented on Mar 3, 2020

    @Skillmon
    Author

    Oh, and even with levels=i+2 the colours aren't set reliably.

  2. ImportanceOfBeingErnest commented on Mar 3, 2020

    @ImportanceOfBeingErnest
    Member

    There is a beating of two different discretisations, the manual one and the one from contour, right?

    So if you create an image plot, i.e. replace ax.contourf(xx, yy, Z, cmap=cm) by ax.imshow(Z, aspect="auto", cmap=cm) it will show the expected colors

    image

    If using a contour plot, the contours will only be at the discretization levels if exactly those levels are chosen when calling it (else it wouldn't know about that explicit desire).

    ax.contourf(xx, yy, Z, levels=np.linspace(0,Z.max(),i+2+1), cmap=cm)
    

    image

    Closing this, as there is no bug apparent here, but feel free to discuss further if I'm misunderstanding.

  3. Skillmon commented on Mar 3, 2020

    @Skillmon
    Author

    Well, I only used that data to simplify the MWE, in my actual use case I'm trying to visualise the results of an SVM. And I beg you pardon but if I have data with $n$ distinct $Z$ values and say there will be $n$ levels, the results of contourf should show $n$ differently coloured areas.

  4. ImportanceOfBeingErnest commented on Mar 3, 2020

    @ImportanceOfBeingErnest
    Member

    The colored areas are in between the levels. So to get n colors one needs n+1 levels. But if an integer, the levels argument will only determine an approximate number, provided by the output of a MaxNLocator. See issue #12729 and PR #16534 for the corresponding docstring fix.

  5. Skillmon commented on Mar 3, 2020

    @Skillmon
    Author

    Ok, specifying as a list does work, still I find the behaviour with levels=<int> weird when $Z$ has exactly $n$ distinct levels.

  6. timhoffm commented on Mar 3, 2020

    @timhoffm
    Member

    Just as a remark, a similar plot can be created in a single axes using a horizontal bar chart:
    See https://matplotlib.org/gallery/lines_bars_and_markers/horizontal_barchart_distribution.html

  7. ImportanceOfBeingErnest commented on Mar 3, 2020

    @ImportanceOfBeingErnest
    Member

    The reason for this is that you rarely want some odd levels like

    image

    but rather some nice levels like

    image

  8. Skillmon commented on Mar 3, 2020

    @Skillmon
    Author

    @timhoffm this is just an oversimplification for the sake of an MWE, I need contourf as it is used to show the class borders of an SVM.

  9. Skillmon commented on Mar 3, 2020

    @Skillmon
    Author

    @ImportanceOfBeingErnest Thank you very much for your patience with me and the explanations where I misunderstood the documentation. Everything seems clear to me now :)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions