Nota
Haga clic aquí para descargar el código de ejemplo completo
Creando mapas de colores en Matplotlib #
Matplotlib tiene una serie de mapas de colores integrados accesibles a través de
matplotlib.colormaps
. También hay bibliotecas externas como
palettable que tienen muchos mapas de colores adicionales.
Sin embargo, a menudo queremos crear o manipular mapas de colores en Matplotlib. Esto se puede hacer usando la clase ListedColormap
o
LinearSegmentedColormap
. Visto desde el exterior, ambas clases de mapa de colores asignan valores entre 0 y 1 a un grupo de colores. Sin embargo, existen ligeras diferencias, algunas de las cuales se muestran a continuación.
Antes de crear o manipular mapas de colores manualmente, primero veamos cómo podemos obtener mapas de colores y sus colores a partir de clases de mapas de colores existentes.
Obtener mapas de colores y acceder a sus valores #
Primero, obtener un mapa de colores con nombre, la mayoría de los cuales se enumeran en
Elección de mapas de colores en Matplotlib , se puede hacer usando matplotlib.colormaps
, que devuelve un objeto de mapa de colores. La longitud de la lista de colores utilizados internamente para definir el mapa de colores se puede ajustar a través de Colormap.resampled
. A continuación, usamos un valor modesto de 8, por lo que no hay muchos valores para mirar.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
viridis = mpl.colormaps['viridis'].resampled(8)
El objeto viridis
es invocable, que cuando se le pasa un valor flotante entre 0 y 1 devuelve un valor RGBA del mapa de colores:
print(viridis(0.56))
(0.122312, 0.633153, 0.530398, 1.0)
ListedColormap #
ListedColormap
almacenan sus valores de color en un .colors
atributo. Se puede acceder directamente a la lista de colores que componen el mapa de colores usando la colors
propiedad, o indirectamente llamando viridis
con una matriz de valores que coincidan con la longitud del mapa de colores. Tenga en cuenta que la lista devuelta tiene la forma de una matriz RGBA Nx4, donde N es la longitud del mapa de colores.
print('viridis.colors', viridis.colors)
print('viridis(range(8))', viridis(range(8)))
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))
viridis.colors [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
viridis(range(8)) [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
viridis(np.linspace(0, 1, 8)) [[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]]
El mapa de colores es una tabla de búsqueda, por lo que "sobremuestrear" el mapa de colores devuelve la interpolación del vecino más cercano (tenga en cuenta los colores repetidos en la lista a continuación)
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
viridis(np.linspace(0, 1, 12)) [[0.267004 0.004874 0.329415 1. ]
[0.267004 0.004874 0.329415 1. ]
[0.275191 0.194905 0.496005 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.212395 0.359683 0.55171 1. ]
[0.153364 0.497 0.557724 1. ]
[0.122312 0.633153 0.530398 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.288921 0.758394 0.428426 1. ]
[0.626579 0.854645 0.223353 1. ]
[0.993248 0.906157 0.143936 1. ]
[0.993248 0.906157 0.143936 1. ]]
LinearSegmentedColormap #
LinearSegmentedColormap
s no tienen un .colors
atributo. Sin embargo, todavía se puede llamar al mapa de colores con una matriz de enteros o con una matriz flotante entre 0 y 1.
copper = mpl.colormaps['copper'].resampled(8)
print('copper(range(8))', copper(range(8)))
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))
copper(range(8)) [[0. 0. 0. 1. ]
[0.17647055 0.1116 0.07107143 1. ]
[0.35294109 0.2232 0.14214286 1. ]
[0.52941164 0.3348 0.21321429 1. ]
[0.70588219 0.4464 0.28428571 1. ]
[0.88235273 0.558 0.35535714 1. ]
[1. 0.6696 0.42642857 1. ]
[1. 0.7812 0.4975 1. ]]
copper(np.linspace(0, 1, 8)) [[0. 0. 0. 1. ]
[0.17647055 0.1116 0.07107143 1. ]
[0.35294109 0.2232 0.14214286 1. ]
[0.52941164 0.3348 0.21321429 1. ]
[0.70588219 0.4464 0.28428571 1. ]
[0.88235273 0.558 0.35535714 1. ]
[1. 0.6696 0.42642857 1. ]
[1. 0.7812 0.4975 1. ]]
Creación de mapas de colores listados #
La creación de un mapa de colores es esencialmente la operación inversa de la anterior, donde proporcionamos una lista o matriz de especificaciones de color ListedColormap
para crear un nuevo mapa de colores.
Antes de continuar con el tutorial, definamos una función auxiliar que tome uno o más mapas de colores como entrada, cree algunos datos aleatorios y aplique los mapas de colores a un gráfico de imagen de ese conjunto de datos.
def plot_examples(colormaps):
"""
Helper function to plot data with associated colormap.
"""
np.random.seed(19680801)
data = np.random.randn(30, 30)
n = len(colormaps)
fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
constrained_layout=True, squeeze=False)
for [ax, cmap] in zip(axs.flat, colormaps):
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
fig.colorbar(psm, ax=ax)
plt.show()
En el caso más simple, podríamos escribir una lista de nombres de colores para crear un mapa de colores a partir de ellos.
cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
plot_examples([cmap])
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_001.png)
De hecho, esa lista puede contener cualquier especificación de color Matplotlib válida . Particularmente útiles para crear mapas de colores personalizados son las matrices numpy Nx4. Porque con la variedad de operaciones numéricas que podemos hacer en una matriz de este tipo, la carpintería de nuevos mapas de colores a partir de mapas de colores existentes se vuelve bastante sencilla.
Por ejemplo, supongamos que queremos hacer que las primeras 25 entradas de un mapa de colores "viridis" de 256 longitudes sean rosas por alguna razón:
viridis = mpl.colormaps['viridis'].resampled(256)
newcolors = viridis(np.linspace(0, 1, 256))
pink = np.array([248/256, 24/256, 148/256, 1])
newcolors[:25, :] = pink
newcmp = ListedColormap(newcolors)
plot_examples([viridis, newcmp])
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_002.png)
Podemos reducir el rango dinámico de un mapa de colores; aquí elegimos la mitad central del mapa de colores. Tenga en cuenta, sin embargo, que debido a que viridis es un mapa de colores listado, terminaremos con 128 valores discretos en lugar de los 256 valores que estaban en el mapa de colores original. Este método no interpola en el espacio de color para agregar nuevos colores.
viridis_big = mpl.colormaps['viridis']
newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 128)))
plot_examples([viridis, newcmp])
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_003.png)
y podemos concatenar fácilmente dos mapas de colores:
top = mpl.colormaps['Oranges_r'].resampled(128)
bottom = mpl.colormaps['Blues'].resampled(128)
newcolors = np.vstack((top(np.linspace(0, 1, 128)),
bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plot_examples([viridis, newcmp])
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_004.png)
Por supuesto, no necesitamos comenzar desde un mapa de colores con nombre, solo necesitamos crear la matriz Nx4 para pasar a ListedColormap
. Aquí creamos un mapa de colores que va del marrón (RGB: 90, 40, 40) al blanco (RGB: 255, 255, 255).
N = 256
vals = np.ones((N, 4))
vals[:, 0] = np.linspace(90/256, 1, N)
vals[:, 1] = np.linspace(40/256, 1, N)
vals[:, 2] = np.linspace(40/256, 1, N)
newcmp = ListedColormap(vals)
plot_examples([viridis, newcmp])
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_005.png)
Creación de mapas de color segmentados lineales #
La LinearSegmentedColormap
clase especifica mapas de colores utilizando puntos de anclaje entre los que se interpolan los valores RGB(A).
El formato para especificar estos mapas de colores permite discontinuidades en los puntos de anclaje. Cada punto de ancla se especifica como una fila en una matriz de la forma , donde es el ancla y
y son los valores del color a ambos lados del punto de ancla.[x[i] yleft[i] yright[i]]
x[i]
yleft[i]
yright[i]
Si no hay discontinuidades, entonces :yleft[i] == yright[i]
cdict = {'red': [[0.0, 0.0, 0.0],
[0.5, 1.0, 1.0],
[1.0, 1.0, 1.0]],
'green': [[0.0, 0.0, 0.0],
[0.25, 0.0, 0.0],
[0.75, 1.0, 1.0],
[1.0, 1.0, 1.0]],
'blue': [[0.0, 0.0, 0.0],
[0.5, 0.0, 0.0],
[1.0, 1.0, 1.0]]}
def plot_linearmap(cdict):
newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
rgba = newcmp(np.linspace(0, 1, 256))
fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
col = ['r', 'g', 'b']
for xx in [0.25, 0.5, 0.75]:
ax.axvline(xx, color='0.7', linestyle='--')
for i in range(3):
ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
ax.set_xlabel('index')
ax.set_ylabel('RGB')
plt.show()
plot_linearmap(cdict)
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_006.png)
Para hacer una discontinuidad en un punto de anclaje, la tercera columna es diferente a la segunda. La matriz para cada uno de "rojo", "verde", "azul" y, opcionalmente, "alfa" se configura como:
cdict['red'] = [...
[x[i] yleft[i] yright[i]],
[x[i+1] yleft[i+1] yright[i+1]],
...]
y para los valores pasados al mapa de colores entre x[i]
y x[i+1]
, la interpolación es entre yright[i]
y yleft[i+1]
.
En el siguiente ejemplo, hay una discontinuidad en rojo en 0,5. La interpolación entre 0 y 0,5 va de 0,3 a 1, y entre 0,5 y 1 va de 0,9 a 1. Tenga en cuenta que , y son superfluos para la interpolación porque (es decir, ) es el valor a la izquierda de 0, y ( es decir, ) es el valor a la derecha de 1, que están fuera del dominio de asignación de colores.red[0, 1]
red[2, 2]
red[0, 1]
yleft[0]
red[2, 2]
yright[2]
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_007.png)
Crear directamente un mapa de colores segmentado a partir de una lista #
El enfoque descrito anteriormente es muy versátil, pero ciertamente un poco engorroso de implementar. Para algunos casos básicos, el uso de
LinearSegmentedColormap.from_list
puede ser más fácil. Esto crea un mapa de colores segmentado con espacios iguales a partir de una lista de colores suministrada.
colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)
Si lo desea, los nodos del mapa de colores se pueden dar como números entre 0 y 1. Por ejemplo, se podría hacer que la parte rojiza ocupe más espacio en el mapa de colores.
![manipulación del mapa de colores](/stable/_images/sphx_glr_colormap-manipulation_008.png)
Referencias
En este ejemplo se muestra el uso de las siguientes funciones, métodos, clases y módulos:
Tiempo total de ejecución del script: (0 minutos 4.802 segundos)