5

I am trying to produce a matplotlib contourf plot that has all values under a specified value in white (including zero) and that has all nan values (representing missing data) in black. I can't seem to get the nan values to be a different color then the under/zero values.A simplified example of the problem is:

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

# Generate some random data for a contour plot
Z = np.random.rand(10,10)
Z[0:3,0:3] = np.nan # some bad values for set_bad
Z[0:3,7:10] = 0 # some zero values for set_under
x = np.arange(10)
y = np.arange(10)
X,Y = np.meshgrid(x, y)

# Mask the bad data:
Z_masked = np.ma.array(Z,mask=np.isnan(Z))

# Get the colormap and set the under and bad colors
colMap = cm.gist_rainbow
colMap.set_bad(color='black')
colMap.set_under(color='white')

# Create the contour plot
plt.figure(figsize=(10, 9))
contourPlot = plt.contourf(X,Y,Z_masked,cmap = colMap,vmin = 0.2)
plt.colorbar(contourPlot)
plt.show()

Using this I get the figure linked below, where both the nan values (bottom left) and zero values (bottom right) are white - I'm not sure why the nan values are not black.

buggy figure

Generated Figure

tacaswell
  • 84,579
  • 22
  • 210
  • 199
Shawn
  • 53
  • 1
  • 4

2 Answers2

3

Since the masked regions are not filled at all, you might simply set the background of the plot to the color you would want to attribute to the "bad" values, plt.gca().set_facecolor("black").

Complete example:

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

# Generate some random data for a contour plot
Z = np.random.rand(10,10)
Z[0:3,0:3] = np.nan # some bad values for set_bad
Z[0:3,7:10] = 0 # some zero values for set_under
x = np.arange(10)
y = np.arange(10)
X,Y = np.meshgrid(x, y)

# Mask the bad data:
Z_masked = np.ma.array(Z,mask=np.isnan(Z))

# Get the colormap and set the under and bad colors
colMap = cm.gist_rainbow
colMap.set_under(color='white')

# Create the contour plot
plt.figure(figsize=(10, 9))
plt.gca().set_facecolor("black")
contourPlot = plt.contourf(X,Y,Z_masked,cmap = colMap,vmin = 0.2)
plt.colorbar(contourPlot)
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
1

The key is the example pointed to by @ViníciusAguia that notes that contourf simply does not draw anything where the data is invalid. If you had flipped the black and white in your example it would have looked like it worked!

A way to get what you want is to set the facecolor on your axes to the color you want for 'bad':

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
plt.ion()

# Generate some random data for a contour plot
Z = np.random.rand(10,10)
Z[0:3,0:3] = np.nan # some bad values for set_bad
Z[0:3,7:10] = 0 # some zero values for set_under
x = np.arange(10)
y = np.arange(10)
X,Y = np.meshgrid(x, y)

# Mask the bad data:
Z_masked = np.ma.array(Z,mask=np.isnan(Z))

# Get the colormap and set the under and bad colors
colMap = cm.gist_rainbow
# this has no effect see last comment block in
# https://matplotlib.org/examples/pylab_examples/contourf_demo.html
# colMap.set_bad(color='black')
colMap.set_under(color='white')

# Create the contour plot
fig, ax = plt.subplots()
contourPlot = ax.contourf(X,Y,Z_masked,cmap = colMap,vmin = 0.2, extend='both')
fig.colorbar(contourPlot)
# This is effectively 'bad' for contourf
ax.set_facecolor('k')
plt.show()

enter image description here

tacaswell
  • 84,579
  • 22
  • 210
  • 199