Reputation: 163
I've been working on some data plotting functioning for python and one such tool I need for my research is a set of difference charts to compare the changes between two sets of data.
I'm now at the point where I want to plot my data and I was looking into creating custom color maps to handle the diverging data, however all of my plots such far are either ignoring specific steps in my gradient, or the colors are being repeated for my low values.
Here's an example plot that was generated:
And the code for both my custom color map, as well as the plotting:
diffmap_17 = ["#FF0000", "#F81318", "#F12731", "#EB3B4A", "#EB5C66", "#EB7D82", "#EB9E9E", "#F1BEBE", "#F8DEDE", "#FFFFFF", "#DDDCFD", "#BCB9FB", "#9B96FA", "#6A6CFA", "#3A43FA", "#1D21FC", "#0000FF"]
diffmap_17_colormap = matplotlib.colors.ListedColormap(diffmap_17)
contour_levels = [-20, -10, -5, -2, -1, -0.75, -0.5, -0.25, -0.1, 0.0, 0.1, 0.25, 0.5, 0.75, 1, 2, 5, 10, 20]
cs = m.contourf(x,y,data,contour_levels,cmap=diffmap_17_colormap) #plot total
My goal is to have the color map have the zero point be white, and then diverge outward (Reds negative, blues positive). For the time being, I'm employing a standard colormap, however using a custom one would be preferred moving forward.
Any help would be greatly appreciated. Thanks!
Upvotes: 2
Views: 1618
Reputation: 339180
The problem is that the colors are chosen from the colormap by dividing the range between the minimum and maximum values into equal parts. Since most levels lie very close to each other, they fall into the same range and thus have the same color.
The easiest solution is not to use a colormap, but a plot where each of the levels gets its color from the colorlist. In this case you may provide the list of colors directly to the contourf
plot.
plt.contourf(x,y,data,contour_levels,colors=diffmap_17)
Note, that because you have 19 levels your list would then need 18 colors (I therefore added one).
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors
x, y= np.meshgrid(np.linspace(-3,3), np.linspace(-3,3))
r = np.sqrt(x**2+y**2)
data = np.tan((r*0.7-1.5))*1.3
diffmap_17 = ["#FF0000", "#F81318", "#F12731", "#EB3B4A", "#EB5C66", "#EB7D82",
"#EB9E9E", "#F1BEBE", "#F8DEDE", "#FFFFFF", "#DDDCFD", "#BCB9FB",
"#9B96FA", "#6A6CFA", "#3A43FA", "#1D21FC", "#0000FF", "#0000ce"]
contour_levels = [-20, -10, -5, -2, -1, -0.75, -0.5, -0.25, -0.1, 0.0,
0.1, 0.25, 0.5, 0.75, 1, 2, 5, 10, 20]
cs = plt.contourf(x,y,data,contour_levels,colors=diffmap_17)
plt.colorbar(cs)
plt.show()
If you want to use a colormap instead, you would need to provide a normalization instance together with the colormap. A matplotlib.colors.BoundaryNorm
would chose the colors according to the list of boundaries supplied to it, which would be the list of levels for the contour plot.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors
x, y= np.meshgrid(np.linspace(-3,3), np.linspace(-3,3))
r = np.sqrt(x**2+y**2)
data = np.tan((r*0.7-1.5))*1.3
diffmap_17 = ["#FF0000", "#F81318", "#F12731", "#EB3B4A", "#EB5C66", "#EB7D82",
"#EB9E9E", "#F1BEBE", "#F8DEDE", "#FFFFFF", "#DDDCFD", "#BCB9FB",
"#9B96FA", "#6A6CFA", "#3A43FA", "#1D21FC", "#0000FF", "#0000ce"]
diffmap_17_colormap = matplotlib.colors.ListedColormap(diffmap_17)
contour_levels = [-20, -10, -5, -2, -1, -0.75, -0.5, -0.25, -0.1, 0.0,
0.1, 0.25, 0.5, 0.75, 1, 2, 5, 10, 20]
norm = matplotlib.colors.BoundaryNorm(contour_levels, diffmap_17_colormap.N)
cs = plt.contourf(x,y,data,contour_levels,cmap=diffmap_17_colormap, norm=norm)
plt.colorbar(cs)
plt.show()
The output plot is the same as above.
Upvotes: 2