Cree su propio mapa de colores usando matplotlib y trace la escala de colores

Resuelto Trollbrot asked hace 11 años • 4 respuestas

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).

Trollbrot avatar May 30 '13 18:05 Trollbrot
Aceptado

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_listmé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()

ingrese la descripción de la imagen aquí


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 nenésimo valor debe corresponder al nenésimo color, puede normalizar los valores y proporcionarlos como tuplas al from_listmé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()

ingrese la descripción de la imagen aquí

ImportanceOfBeingErnest avatar Oct 16 '2017 20:10 ImportanceOfBeingErnest

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 cdictcomo 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 cdictformato 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()

ingrese la descripción de la imagen aquí


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.plotSólo puede dibujar en un color, pero plt.scatterpuede asignar un color diferente a cada punto. Éste plt.scatteres el camino a seguir.

unutbu avatar May 30 '2013 12:05 unutbu

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 : ingrese la descripción de la imagen aquí

Steven C. Howell avatar Jun 07 '2015 01:06 Steven C. Howell