Obtener colores individuales de un mapa de colores en matplotlib

Resuelto LondonRob asked hace 10 años • 9 respuestas

Si tienes un mapa de colores cmap , por ejemplo:

cmap = matplotlib.cm.get_cmap('Spectral')

¿Cómo se puede obtener un color particular entre 0 y 1, donde 0 es el primer color del mapa y 1 es el último color del mapa?

Idealmente, podría obtener el color medio en el mapa haciendo:

>>> do_some_magic(cmap, 0.5) # Return an RGBA tuple
(0.1, 0.2, 0.3, 1.0)
LondonRob avatar Aug 20 '14 22:08 LondonRob
Aceptado

Puede hacer esto con el código a continuación, y el código en su pregunta en realidad estaba muy cerca de lo que necesitaba, todo lo que tiene que hacer es llamar al cmapobjeto que tiene.

import matplotlib

cmap = matplotlib.cm.get_cmap('Spectral')

rgba = cmap(0.5)
print(rgba) # (0.99807766255210428, 0.99923106502084169, 0.74602077638401709, 1.0)

Para valores fuera del rango [0.0, 1.0] devolverá el color inferior y superior (respectivamente). Este, de forma predeterminada, es el color mínimo y máximo dentro del rango (es decir, 0,0 y 1,0). Este valor predeterminado se puede cambiar con cmap.set_under()y cmap.set_over().

Para números "especiales" como np.nany np.infel valor predeterminado es usar el valor 0.0, esto se puede cambiar usando cmap.set_bad()de manera similar a debajo y encima como se indicó anteriormente.

Finalmente, puede ser necesario que normalice sus datos para que se ajusten al rango [0.0, 1.0]. Esto se puede hacer matplotlib.colors.Normalizesimplemente como se muestra en el pequeño ejemplo a continuación, donde los argumentos vmindescriben vmaxqué números deben asignarse a 0,0 y 1,0 respectivamente.

import matplotlib

norm = matplotlib.colors.Normalize(vmin=10.0, vmax=20.0)

print(norm(15.0)) # 0.5

También está disponible un normalizador logarítmico ( matplotlib.colors.LogNorm ) para rangos de datos con una gran variedad de valores.

(Gracias a Joe Kington y tcaswell por sus sugerencias sobre cómo mejorar la respuesta).

Ffisegydd avatar Aug 20 '2014 15:08 Ffisegydd

Para obtener un valor entero de rgba en lugar de un valor flotante, podemos hacer

rgba = cmap(0.5,bytes=True)

Entonces, para simplificar el código según la respuesta de Ffisegydd, el código sería así:

#import colormap
from matplotlib import cm

#normalize item number values to colormap
norm = matplotlib.colors.Normalize(vmin=0, vmax=1000)

#colormap possible values = viridis, jet, spectral
rgba_color = cm.jet(norm(400),bytes=True) 

#400 is one of value between 0 and 1000
amaliammr avatar Mar 04 '2018 02:03 amaliammr

Una vez me encontré con una situación similar en la que necesitaba "n" no. de colores de un mapa de colores para poder asignar cada color a mis datos. He compilado un código para esto en un paquete llamado " mycolorpy ". Puedes instalarlo usando:

pip install mycolorpy

Luego puedes hacer:

from mycolorpy import colorlist as mcp
import numpy as np

Ejemplo: para crear una lista de 5 cadenas hexadecimales de cmap "invierno"

color1=mcp.gen_color(cmap="winter",n=5)
print(color1)

Producción:

['#0000ff', '#0040df', '#0080bf', '#00c09f', '#00ff80']

Otro ejemplo para generar 16 listas de colores desde cmap bwr:

color2=mcp.gen_color(cmap="bwr",n=16)
print(color2)

Producción:

['#0000ff', '#2222ff', '#4444ff', '#6666ff', '#8888ff', '#aaaaff', '#ccccff', '#eeeeff', '#ffeeee', '#ffcccc', '#ffaaaa', '#ff8888', '#ff6666', '#ff4444', '#ff2222', '#ff0000']

Hay un cuaderno de Python con ejemplos de uso para visualizar mejor esto.

Supongamos que desea generar una lista de colores a partir de un cmap que esté normalizado a unos datos determinados. Puedes hacerlo usando:

a=random.randint(1000, size=(200))
a=np.array(a)
color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a)
plt.scatter(a,a,c=color1)

Producción: ingrese la descripción de la imagen aquí

También puedes invertir el color usando:

color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a,reverse=True)
plt.scatter(a,a,c=color1)

Producción: ingrese la descripción de la imagen aquí

Binod avatar Sep 30 '2021 17:09 Binod

Tenía precisamente este problema, pero necesitaba que las tramas secuenciales tuvieran un color muy contrastante. También estaba haciendo gráficos con una subtrama común que contenía datos de referencia, por lo que quería que la secuencia de colores fuera consistentemente repetible.

Inicialmente intenté simplemente generar colores al azar, resembrando el RNG antes de cada gráfico. Esto funcionó bien (comentado en el código a continuación), pero podría generar colores casi indistinguibles. Quería colores muy contrastantes, idealmente tomados de un mapa de colores que contenga todos los colores.

Podría tener hasta 31 series de datos en un solo gráfico, así que dividí el mapa de colores en esa cantidad de pasos. Luego seguí los pasos en un orden que asegurara que no regresaría al vecindario de un color determinado muy pronto.

Mis datos están en una serie de tiempo muy irregular, por lo que quería ver los puntos y las líneas, donde el punto tuviera el color "opuesto" de la línea.

Teniendo en cuenta todo lo anterior, era más fácil generar un diccionario con los parámetros relevantes para trazar las series individuales y luego expandirlo como parte de la llamada.

Aquí está mi código. Quizás no sea bonito, pero sí funcional.

from matplotlib import cm
cmap = cm.get_cmap('gist_rainbow')  #('hsv') #('nipy_spectral')

max_colors = 31   # Constant, max mumber of series in any plot.  Ideally prime.
color_number = 0  # Variable, incremented for each series.

def restart_colors():
    global color_number
    color_number = 0
    #np.random.seed(1)

def next_color():
    global color_number
    color_number += 1
    #color = tuple(np.random.uniform(0.0, 0.5, 3))
    color = cmap( ((5 * color_number) % max_colors) / max_colors )
    return color

def plot_args():  # Invoked for each plot in a series as: '**(plot_args())'
    mkr = next_color()
    clr = (1 - mkr[0], 1 - mkr[1], 1 - mkr[2], mkr[3])  # Give line inverse of marker color
    return {
        "marker": "o",
        "color": clr,
        "mfc": mkr,
        "mec": mkr,
        "markersize": 0.5,
        "linewidth": 1,
    }

Mi contexto es JupyterLab y Pandas, así que aquí hay un código de trama de muestra:

restart_colors()  # Repeatable color sequence for every plot

fig, axs = plt.subplots(figsize=(15, 8))
plt.title("%s + T-meter"%name)

# Plot reference temperatures:
axs.set_ylabel("°C", rotation=0)
for s in ["T1", "T2", "T3", "T4"]:
    df_tmeter.plot(ax=axs, x="Timestamp", y=s, label="T-meter:%s" % s, **(plot_args()))

# Other series gets their own axis labels
ax2 = axs.twinx()
ax2.set_ylabel(units)

for c in df_uptime_sensors:
    df_uptime[df_uptime["UUID"] == c].plot(
        ax=ax2, x="Timestamp", y=units, label="%s - %s" % (units, c), **(plot_args())
    )

fig.tight_layout()
plt.show()

Puede que la trama resultante no sea el mejor ejemplo, pero se vuelve más relevante cuando se amplía de forma interactiva. tiempo de actividad + T-metro

BobC avatar Jan 16 '2021 00:01 BobC