[Matplotlib-users] getting extra colors in figure
Smit, Christine E. (GSFC-610.2)[TELOPHASE CORP]
christine.e.smit at nasa.gov
Fri Jul 22 14:24:08 EDT 2016
Hi! I’m trying to plot data using imshow and ending up with more colors
than I specify in the colormap. This is causing problems with a downstream
user who is machine reading images to determine approximate data values
based on colors. I think the issue has something to do with rounding
because many colors in the image are only slightly off from the colors I
specified. My plots have exactly one pixel per data value, so each pixel¹s
color should be exactly a color in the colormap.
Here is an example that replicates the issue:
----------------------------------
import numpy as np;
import matplotlib.pylab as plt
import matplotlib.colors as colors
from PIL import Image
import random
#######
# Create some simple data
#######
shape = (8,12)
npixels = shape[0]*shape[1]
data_min = 0.5
data_max = 11.5
data = np.reshape(np.linspace(data_min,data_max,npixels),shape)
# mask out a quarter of the pixels
mask = np.reshape([False]*npixels,shape)
half_width = int(shape[0]/2)
half_height = int(shape[1]/2)
mask[0:half_width,0:half_height] = True;
ma = np.ma.MaskedArray(data = data,mask = mask)
#######
# Create a color palette with three colors, one 'over' color, and one
'under' color
#######
# define some colors in hex
hex_colors = {
'red':'#ff0000',
'orange':"#ffa500",
'yellow': "#ffff00",
'green': "#00ff00",
'blue' : "#0000ff"
}
# Create the colormap
cmap =
colors.ListedColormap([hex_colors['orange'],hex_colors['yellow'],hex_colors
['green']])
cmap.set_under(color=hex_colors['red'])
cmap.set_over(color=hex_colors['blue'])
# Calculate boundaries between colors so we get some data in every color
thresholds = np.linspace(data_min+1,data_max-1,cmap.N+1)
norm = colors.BoundaryNorm(thresholds, cmap.N)
#######
# Make a plot. The aim here is to have one data point per pixel in the
output file with no
# decorators.
#######
# Step 1: turn off the frame
fig = plt.figure(frameon=False)
# Step 2: set the size of the image in inches to the number of data
points. Note: the size is
# specified width, height.
fig.set_size_inches(shape[1], shape[0])
# Step 3: create Axes
ax = plt.Axes(fig, [0., 0., 1., 1.])
# Step 4: turn off drawing axes
ax.set_axis_off()
# Step 5: add the axes to the figure
fig.add_axes(ax)
# Step 6: plot
ax.imshow(ma,
# Don't interpolate. There's no need to interpolate because we
have
# exactly as many data points as pixels.
interpolation='none',
# Use our 3-color (+1 above, +1 below) colormap
cmap=cmap,
# Use thresholds that will spread the data over all colors
norm=norm,
# Match image aspect ratio to axes
aspect='auto',
# Put ma[0,0] on the lower left
origin='lower',
# Lower left and upper right corners are at the edge of the image
extent=(0,1,0,1)
)
# Step 7: Save to file.
fig.savefig('out.png',
# Set dots per square inch (dpi) to 1. Since there is 1 data
point
# per inch, I should get an image with 1 data point for each
pixel.
dpi=1,
# Set transparent to True so the masked data is transparent.
transparent=True
)
#######
# Open the image and see what colors are inside. I expect to see 6 colors:
my 5 listed colors
# and 1 transparent color for the masked data.
#######
# Load the image
im = Image.open("out.png")
# Confirm that the image is the right size. Note: once again, the image
size is width, height
# while the data array is arranged height, width.
print "Image size(should be %d x %d): %d x %d\n" %( shape[1], shape[0],
im.size[0], im.size[1])
# Throw all the pixels, which are (red,green,blue,alpha) tuples, into a
list
pix = im.load()
all_pix = []
width = im.size[0]
for i in range(im.size[0]):
for j in range(im.size[1]):
all_pix.append(pix[i,j])
# Get a unique list of pixels
unique = list(set(all_pix))
unique.sort()
print "Unique pixels values in file:\n"
for u in unique:
print "%.2x %.2x %.2x (alpha - %.2x)" % (u[0],u[1],u[2], u[3])
print "\nNumber of unique colors (should be 6): %d" % len(unique)
----------------------------------
The output I get from this script is:
----------------------------------
Image size(should be 12 x 8): 12 x 8
Unique pixels values in file:
00 00 ff (alpha - ff)
00 fe 01 (alpha - ff)
00 ff 00 (alpha - ff)
01 00 00 (alpha - 01)
01 01 00 (alpha - 01)
02 02 00 (alpha - 02)
fd ff 00 (alpha - ff)
fe ff 00 (alpha - ff)
ff 01 00 (alpha - ff)
ff a5 00 (alpha - ff)
ff a6 00 (alpha - ff)
ff ff 00 (alpha - ff)
ff ff ff (alpha - 00)
Number of unique colors (should be 6): 13
----------------------------------
Note the weird colors that weren¹t in my colorbar. E.g. -
00 fe 01 (alpha - ff) --> close to 00 ff 00 (green)
01 00 00 (alpha - 00) --> close to transparent
ff a6 00 (alpha - ff) --> close to ff a5 00 (orange)
I am running Python 2.7.11 :: Anaconda 2.4.0 (64-bit) and matplotlib
version 1.4.3. I tried matplotlib 1.5 and it had the same issue.
Thanks.
Christine
More information about the Matplotlib-users
mailing list