Cree su propio mapa de colores usando matplotlib y trace la escala de colores
Tengo el siguiente problema: quiero crear mi propio mapa de colores (rojo-mezcla-violeta-mezcla-azul) que se asigne a valores entre -2 y +2 y quiero usarlo para colorear puntos en mi gráfico. La trama debería entonces tener la escala de colores a la derecha.
Así es como creo el mapa hasta ahora. Pero no estoy muy seguro si mezcla los colores.
cmap = matplotlib.colors.ListedColormap(["red","violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)
De esa manera asigno los colores a los valores.
colors = itertools.cycle([m.to_rgba(1.22), ..])
Luego lo trazo:
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
Mis problemas son:
1. No puedo trazar la escala de colores.
2. No estoy completamente seguro de si mi escala crea una escala de colores continua (suave).
Dado que los métodos utilizados en otras respuestas parecen bastante complicados para una tarea tan sencilla, aquí hay una nueva respuesta:
En lugar de ListedColormap
, que produce un mapa de colores discreto, puedes usar LinearSegmentedColormap
. Esto se puede crear fácilmente a partir de una lista utilizando el from_list
método.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = zip(*np.random.rand(30,3)*4-2)
norm=plt.Normalize(-2,2)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","violet","blue"])
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
De manera más general, si tiene una lista de valores (p. ej. [-2., -1, 2]
) y colores correspondientes (p. ej. ["red","violet","blue"]
), de modo que el n
enésimo valor debe corresponder al n
enésimo color, puede normalizar los valores y proporcionarlos como tuplas al from_list
método.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = zip(*np.random.rand(30,3)*4-2)
cvals = [-2., -1, 2]
colors = ["red","violet","blue"]
norm=plt.Normalize(min(cvals),max(cvals))
tuples = list(zip(map(norm,cvals), colors))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
Hay un ejemplo ilustrativo de cómo crear mapas de colores personalizados aquí . La cadena de documentación es esencial para comprender el significado de
cdict
. Una vez que lo tengas en tu haber, puedes usar algo cdict
como este:
cdict = {'red': ((0.0, 1.0, 1.0),
(0.1, 1.0, 1.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 0.0, 0.0)), # blue
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),
(0.1, 0.0, 0.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 1.0, 0.0)) # blue
}
Aunque el cdict
formato ofrece mucha flexibilidad, encuentro que, para gradientes simples, su formato es bastante poco intuitivo. Aquí hay una función de utilidad para ayudar a generar mapas de colores lineales segmentados simples:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
[c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()
Por cierto, elfor-loop
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
traza un punto por cada llamada a plt.plot
. Esto funcionará para una pequeña cantidad de puntos, pero será extremadamente lento para muchos puntos. plt.plot
Sólo puede dibujar en un color, pero plt.scatter
puede asignar un color diferente a cada punto. Éste plt.scatter
es el camino a seguir.
Si desea automatizar la creación de un mapa de colores divergente personalizado que se usa comúnmente para gráficos de superficie , este módulo combinado con el método @unutbu funcionó bien para mí.
def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
'''
low and high are colors that will be used for the two
ends of the spectrum. they can be either color strings
or rgb color tuples
'''
c = mcolors.ColorConverter().to_rgb
if isinstance(low, basestring): low = c(low)
if isinstance(high, basestring): high = c(high)
return make_colormap([low, c('white'), 0.5, c('white'), high])
Los valores alto y bajo pueden ser nombres de colores de cadena o tuplas rgb. Este es el resultado usando la demostración del gráfico de superficie :