Bug in contourf or BoundaryNorm?

Hi matplotlib users,

I believe the normalization behaviour is wrong for contourf at least when using a BoundaryNorm. In the script below I am using the same norm to plot the same data using contourf and pcolormesh. The color should change around an x value of 0.15 but it is shifted somewhat for contourf. I do realize that the pcolormesh is in principle shifted a little - but with a grid spacing of 0.001 that should not matter. Please see the example script below.

Best regards,

Jesper

“”"

Test inconsistent normalization behaviour for matplotlib

“”"

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.colors import from_levels_and_colors

Make custom colormap and norm

levs = [0.0, 0.1, 0.2]

cols = [[0.00392156862745098, 0.23137254901960785, 0.07450980392156863], [0.00392156862745098, 0.49019607843137253, 0.15294117647058825]]

extend = ‘neither’

cmap, norm = from_levels_and_colors(levs, cols, extend)

Setup testdata

a = np.arange(0.05, 0.15, 0.001, dtype=np.float_)

a, b = np.meshgrid(a, a)

plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False)

plt.savefig(‘contourf.png’)

plt.clf()

plt.pcolormesh(a, b, a, norm=norm, cmap=cmap, antialiased=False)

plt.savefig(‘pcolormesh.png’)

Jesper,

Regardless of whether you specify a colormap and norm, if you want contourf
to calculate contours at particular levels
then you need to specify those levels. If you don't then contourf will
choose the levels for you, and in your case these are chosen to be
[0.045 0.06 0.075 0.09 0.105 0.12 0.135 0.15 ]
which is why you see the color transition at x=0.105.

To fix this, change your contourf line from
plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False)
to
plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False, levels=levs)
and you will get exactly what you want.

Ian

···

On 28 March 2014 12:56, Jesper Larsen <jesper.webmail@...287...> wrote:

I believe the normalization behaviour is wrong for contourf at least when
using a BoundaryNorm. In the script below I am using the same norm to plot
the same data using contourf and pcolormesh. The color should change around
an x value of 0.15 but it is shifted somewhat for contourf. I do realize
that the pcolormesh is in principle shifted a little - but with a grid
spacing of 0.001 that should not matter. Please see the example script
below.

Best regards,
Jesper

"""
Test inconsistent normalization behaviour for matplotlib
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import from_levels_and_colors

# Make custom colormap and norm
levs = [0.0, 0.1, 0.2]
cols = [[0.00392156862745098, 0.23137254901960785, 0.07450980392156863],
[0.00392156862745098, 0.49019607843137253, 0.15294117647058825]]
extend = 'neither'
cmap, norm = from_levels_and_colors(levs, cols, extend)

# Setup testdata
a = np.arange(0.05, 0.15, 0.001, dtype=np.float_)
a, b = np.meshgrid(a, a)0
plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False)
plt.savefig('contourf.png')
plt.clf()
plt.pcolormesh(a, b, a, norm=norm, cmap=cmap, antialiased=False)
plt.savefig('pcolormesh.png')

Hi Ian

Thanks for your reply and help. I see your point. I guess it is only the BoundaryNorm where it would make sense to have contourf use the boundary levels from the norm. In my real problem described by the above example I have long forgotten the levs variable when I arrive at the contourf point. I will therefore instead just use levels=norm.boundaries.

Best regards,

Jesper

···

2014-03-28 15:17 GMT+01:00 Ian Thomas <ianthomas23@…287…>:

On 28 March 2014 12:56, Jesper Larsen <jesper.webmail@…287…> wrote:

I believe the normalization behaviour is wrong for contourf at least when using a BoundaryNorm. In the script below I am using the same norm to plot the same data using contourf and pcolormesh. The color should change around an x value of 0.15 but it is shifted somewhat for contourf. I do realize that the pcolormesh is in principle shifted a little - but with a grid spacing of 0.001 that should not matter. Please see the example script below.

Best regards,

Jesper

“”"

Test inconsistent normalization behaviour for matplotlib

“”"

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.colors import from_levels_and_colors

Make custom colormap and norm

levs = [0.0, 0.1, 0.2]

cols = [[0.00392156862745098, 0.23137254901960785, 0.07450980392156863], [0.00392156862745098, 0.49019607843137253, 0.15294117647058825]]

extend = ‘neither’

cmap, norm = from_levels_and_colors(levs, cols, extend)

Setup testdata

a = np.arange(0.05, 0.15, 0.001, dtype=np.float_)

a, b = np.meshgrid(a, a)0

plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False)

plt.savefig(‘contourf.png’)

plt.clf()

plt.pcolormesh(a, b, a, norm=norm, cmap=cmap, antialiased=False)

plt.savefig(‘pcolormesh.png’)

Jesper,

Regardless of whether you specify a colormap and norm, if you want contourf to calculate contours at particular levels
then you need to specify those levels. If you don’t then contourf will choose the levels for you, and in your case these are chosen to be

[0.045 0.06 0.075 0.09 0.105 0.12 0.135 0.15 ]

which is why you see the color transition at x=0.105.

To fix this, change your contourf line from
plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False)

to
plt.contourf(a, b, a, norm=norm, cmap=cmap, antialiased=False, levels=levs)

and you will get exactly what you want.

Ian