I have an array with 3 set of values that I want to color:
- for values between 0 and 1 (
np.ma.masked_array(array, array > 1.)
) I want a gradient (cmap = cm.Greens
for example)
- for values equal to 2 (
np.ma.masked_array(array, array != 2.)
) I want the color to be red
- for values equal to 3 (
np.ma.masked_array(array, array != 3.)
) I want the color to be gray
Should I define a colormap for each set of values and then merge all of them into one colormap? If so how do I proceed?
On this website (http://scipy.github.io/old-wiki/pages/Cookbook/Matplotlib/Show_colormaps) I found that options like ListedColormap
or LinearSegmentedColormap
might be helpful but I don't really know how to use it to get what I want.
EDIT: I made that and it doesn't work because I don't know how to use ListedColormap
and LinearSegmentedColormap
to get what I want
from random import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib import cm
from matplotlib.colors import ListedColormap
n=11
tab = np.array([[random() for i in range(n)] for j in range(n)])
tab[1,2] = 2.
tab[3,4] = 2.
tab[5,6] = 3.
tab[7,8] = 3.
values1 = np.ma.masked_array(tab, tab > 1.)
values2 = np.ma.masked_array(tab, tab != 2.)
values3 = np.ma.masked_array(tab, tab != 3.)
colors1 = cm.Greens
colors2 = ListedColormap(['red'], 'indexed')
colors3 = ListedColormap(['gray'], 'indexed')
colors = np.vstack((colors1, colors2, colors3))
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)
print plt.imshow(tab, cmap = mycmap, interpolation="none")
A ListedColormap
is best be used for discrete values, while a LinearSegmentedColormap
is more easily created for continuous values. Especially, if an existent colormap shall be used, a LinearSegmentedColormap
is a good choice.
The LinearSegmentedColormap.from_list("name", colors)
expects a list of colors ,colors
(not a colormap!). This list can be created using an existent colormap, e.g. greens = cm.Greens(np.linspace(0,1, num=50))
with 50 colors from that map. For another color to cover the same range we can add the same number of colors, e.g. all being red or gray.
An example is below.
from random import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib import cm
n=11
tab = np.array([[random() for i in range(n)] for j in range(n)])
tab[1,2] = 2.
tab[3,4] = 2.
tab[5,6] = 3.
tab[7,8] = 3.
values1 = np.ma.masked_array(tab, tab > 1.)
values2 = np.ma.masked_array(tab, tab != 2.)
values3 = np.ma.masked_array(tab, tab != 3.)
# 50 values for later use from 0 to 1
greens = cm.Greens(np.linspace(0,1, num=50))
# 25 values for later use from 1 to 1.5
greensfill = cm.Greens(np.ones(25))
# 50 values red for later use from 1.5 to 2.5
red = [(1,0,0,1)]*len(greens)
# 50 values gray for later use from 2.5 to 3.5
gray = [(.5,.5,.5,1)]*len(greens)
colors = np.vstack((greens, greensfill, red, gray))
# in total we now have 175 colors in the colormap
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)
#we now map those 175 colors to the range between 0 and 3.5
im = plt.imshow(tab, cmap = mycmap, interpolation="none", vmin=0, vmax=3.5)
cb = plt.colorbar(im)
cb.set_ticks([0,1,2,3])
plt.show()
Here, the colors from the list are equally spaced in the final colormap.
An alternative could be to specify colors accompanied with the respective values.
colors = [(0, "white"), (1./3.5, "green"), (1.5/3.5, "green"),
(1.501/3.5, "red"), (2.5/3.5, "red"), (2.501/3.5, "gray"), (1, "gray") ]
mycmap = mcolors.LinearSegmentedColormap.from_list('my_colormap', colors)