I have a pandas.dataframe
that looks like this:
columns 0 1 2 3 4 5
A A A A B B
B B B C C D
D D E E F F
I want to plot this using pyplot.imshow()
, specifying the following colormap:
color_dict = {
"A": "#DA291E",
"B": "#83DF39",
"C": "#E8132d",
"D": "#008933",
"E": "#006CB3",
"F": "#52BFEC"
}
If I was plotting a bar
or a scatter
I could just call with the argumentcolor=a_list_of_colors
but this doesn't work with imshow()
.
Instead I need to call with a cmap
but as far as I understand it isn´t possible to create a cmap where a specific color is mapped to a value.
This means I need to create a colormap like this:
from matplotlib.colors import ListedColormap
_colors = ["#DA291E", "DA291E", "DA291E", "DA291E"
"#83DF39", "#83DF39", "#83DF39", "#83DF39", "#83DF39", #...and so on]
cmap = ListedColormap(_colors, name="custom_cmap")
But is there a better way to go about this?
I thought I could implement above method but for some reason it doesn't work and I can't seem to figure out why.
I begin by creating a color_list based on a long series
version of my df
above and then convert that list to a colormap:
color_list = list(series.map(color_dict))
custom_cmap = ListedColormap(color_list, name="custom_cmap")
The long series
basically looks like this:
A
A
A
A
B
B
B
B
B
C
#...and so on
The fifth element in my df
is B
and when I print custom_cmap.__dict__.colors[4]
I get #83DF39
which corresponds with the string value B
in my df
. So the mapping is correct.
The problem occurs when I call plt.imshow()
with cmap=custom_cmap
as it doesn´t follow the cmap
- some values get the wrong color.
My first thought was that I had messed up the order meaning that the color_list
didn´t follow the order of the df
but it does.
The df
above contains 18 values and the color_list does too. The last value in the df
is an F
which means that the last color in the color_list
should be #52BFEC
, which it is.
Adding more code.
# Begin by converting strings to any number since plt.imshow() needs numbers
float_dict = {
'A': 0.0,
'B': 1.0,
'C': 2.0,
'D': 3.0,
'E': 4.0,
'F': 5.0,
'G': 6.0,
'H': 7.0,
'I': 8.0
}
converted_series = series.map(float_dict).copy()
# Map each float to a specific color
color_dict = {
0.0: '#DA291E',
1.0: '#E7112d',
2.0: '#83CD39',
3.0: '#009934',
4.0: '#007AB3',
5.0: '#54BDEC',
6.0: '#000066',
7.0: '#DDDD11',
8.0: '#572B84',
}
# Create a cmap from a color list
color_list = list(converted_series.map(color_dict))
custom_cmap = ListedColormap(color_list, name="custom_cmap")
# Widen the series into a df
df = series_to_wide_df(converted_series, n_columns=8)
# Plot it
plt.imshow(df, cmap=custom_cmap, interpolation='none')
The result of above is seen in image below.
- Note that the data in this image is not the same the data in the
df
in the original post.
I tested a different color_dict
:
color_dict = {
0.0: '#FF0000',
1.0: '#FF0000',
2.0: '#FF0000',
3.0: '#FF0000',
4.0: '#FF0000',
5.0: '#000000',
6.0: '#000000',
7.0: '#000000',
8.0: '#000000'
}
But the colors still don't map correctly. With these colors, 1.0
, 2.0
, 6.0
, 7.0
and some 8.0
get the color red.