mapa de colores no lineal, matplotlib

¿Hay mapas de colores o hay una forma sencilla de transformar un mapa de colores de matplotlib para proporcionar un rango de color mucho mayor cerca de 0,5 y uno más pequeño en los extremos? Estoy creando un grupo de subplots, una de las cuales tiene valores de color de aproximadamente 10 veces más que las otras, por lo que sus valores dominan y el rest de las plots se ven iguales. Para un ejemplo simple digamos que tenemos:

import numpy as np import matplotlib.pyplot as plt x = np.linspace(1,10,10) y = np.linspace(1,10,10) t1 = np.random.normal(2,0.3,10) t2 = np.random.normal(9,0.01,10) t2_max = max(t2) plt.figure(figsize=(22.0, 15.50)) p = plt.subplot(1,2,1) colors = plt.cm.Accent(t1/t2_max) p.scatter(x, y, edgecolors=colors, s=15, linewidths=4) p = plt.subplot(1,2,2) colors = plt.cm.Accent(t2/t2_max) p.scatter(x, y, edgecolors=colors, s=15, linewidths=4) plt.subplots_adjust(left=0.2) cbar_ax = plt.axes([0.10, 0.15, 0.05, 0.7]) sm = plt.cm.ScalarMappable(cmap=plt.cm.Accent, norm=plt.Normalize(vmin=0, vmax=t2_max)) sm._A = [] cbar = plt.colorbar(sm,cax=cbar_ax) plt.show() 

Hay mucha más variación en t1 que en t2, sin embargo, la variación no se puede ver debido a los altos valores de t2. Lo que quiero es un mapa que proporcionará un gradiente de color más grande alrededor de la media de t1 sin transformar los datos en sí. He encontrado una solución aquí http://protracted-matter.blogspot.co.nz/2012/08/nonlinear-colormap-in-matplotlib.html pero no puedo hacer que funcione para mis diagtwigs de dispersión.

EDITAR: De la respuesta a continuación, la clase se puede modificar para tomar números negativos y límites fijos.

 import numpy as np import matplotlib.pyplot as plt x = y = np.linspace(1, 10, 10) t1mean, t2mean = -6, 9 sigma1, sigma2 = .3, .01 t1 = np.random.normal(t1mean, sigma1, 10) t2 = np.random.normal(t2mean, sigma2, 10) class nlcmap(object): def __init__(self, cmap, levels): self.cmap = cmap self.N = cmap.N self.monochrome = self.cmap.monochrome self.levels = np.asarray(levels, dtype='float64') self._x = self.levels self.levmax = self.levels.max() self.levmin = self.levels.min() self.transformed_levels = np.linspace(self.levmin, self.levmax, len(self.levels)) def __call__(self, xi, alpha=1.0, **kw): yi = np.interp(xi, self._x, self.transformed_levels) return self.cmap(yi / (self.levmax-self.levmin)+0.5, alpha) tmax = 10 tmin = -10 #the choice of the levels depends on the data: levels = np.concatenate(( [tmin, tmax], np.linspace(t1mean - 2 * sigma1, t1mean + 2 * sigma1, 5), np.linspace(t2mean - 2 * sigma2, t2mean + 2 * sigma2, 5), )) levels = levels[levels <= tmax] levels.sort() print levels cmap_nonlin = nlcmap(plt.cm.jet, levels) fig, (ax1, ax2) = plt.subplots(1, 2) ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4) ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4) fig.subplots_adjust(left=.25) cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7]) #for the colorbar we map the original colormap, not the nonlinear one: sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, norm=plt.Normalize(vmin=tmin, vmax=tmax)) sm._A = [] cbar = fig.colorbar(sm, cax=cbar_ax) #here we are relabel the linear colorbar ticks to match the nonlinear ticks cbar.set_ticks(cmap_nonlin.transformed_levels) cbar.set_ticklabels(["%.2f" % lev for lev in levels]) plt.show() 

Su enlace proporciona una buena solución para el mapa de colores. Edité un poco, pero contenía todo lo necesario. Debe seleccionar algunos niveles razonables para su mapa de colores no lineal. Usé dos rangos centrados alrededor de los valores medios, entre +- 4 la desviación estándar de su muestra. al cambiarlo a otro número, obtendrá un gradiente local diferente en el color alrededor de los dos valores medios.

Para la barra de colores, tu

  • O bien, deje los colores espaciados no linealmente con tags espaciadas linealmente.
  • tiene colores espaciados linealmente con tags espaciadas no linealmente.

El segundo permite una mayor resolución cuando se miran los datos, se ve mejor y se implementa a continuación:

 import numpy as np import matplotlib.pyplot as plt x = y = np.linspace(1, 10, 10) t1mean, t2mean = 2, 9 sigma1, sigma2 = .3, .01 t1 = np.random.normal(t1mean, sigma1, 10) t2 = np.random.normal(t2mean, sigma2, 10) class nlcmap(object): def __init__(self, cmap, levels): self.cmap = cmap self.N = cmap.N self.monochrome = self.cmap.monochrome self.levels = np.asarray(levels, dtype='float64') self._x = self.levels self.levmax = self.levels.max() self.transformed_levels = np.linspace(0.0, self.levmax, len(self.levels)) def __call__(self, xi, alpha=1.0, **kw): yi = np.interp(xi, self._x, self.transformed_levels) return self.cmap(yi / self.levmax, alpha) tmax = max(t1.max(), t2.max()) #the choice of the levels depends on the data: levels = np.concatenate(( [0, tmax], np.linspace(t1mean - 4 * sigma1, t1mean + 4 * sigma1, 5), np.linspace(t2mean - 4 * sigma2, t2mean + 4 * sigma2, 5), )) levels = levels[levels <= tmax] levels.sort() cmap_nonlin = nlcmap(plt.cm.jet, levels) fig, (ax1, ax2) = plt.subplots(1, 2) ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4) ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4) fig.subplots_adjust(left=.25) cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7]) #for the colorbar we map the original colormap, not the nonlinear one: sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, norm=plt.Normalize(vmin=0, vmax=tmax)) sm._A = [] cbar = fig.colorbar(sm, cax=cbar_ax) #here we are relabel the linear colorbar ticks to match the nonlinear ticks cbar.set_ticks(cmap_nonlin.transformed_levels) cbar.set_ticklabels(["%.2f" % lev for lev in levels]) plt.show() 

En el resultado, observe que las marcas de la barra de colores NO están equidistadas:

introduzca la descripción de la imagen aquí

Podrías usar LinearSegmentedColormap :

Con esto, necesita configurar una tabla de búsqueda de colores dentro de un diccionario, por ejemplo, ‘cdict’ a continuación.

 cdict = {'red': [(0.0, 0.0, 0.0), (0.15, 0.01, 0.01), (0.35, 1.0, 1.0), (1.0, 1.0, 1.0)], 'green': [(0.0, 0.0, 0.0), (1.0, 0.0, 1.0)], 'blue': [(0.0, 0.0, 1.0), (0.9, 0.01, 0.01), (1.0, 0.0, 1.0)]} 

Esto muestra las transiciones entre valores. He configurado el rojo para variar mucho en torno a los valores de t1/t2_max (0.15 a 0.35) y el azul para variar mucho en torno a los valores de t2/t2_max (0.9 a 1.0). El verde no hace nada. Recomiendo leer los documentos para ver cómo funciona esto. (Tenga en cuenta que esto podría automatizarse para variar automáticamente en función de sus valores). Luego modifiqué tu código para mostrar el gráfico:

 import matplotlib.colors as col my_cmap = col.LinearSegmentedColormap('my_colormap', cdict) plt.figure(figsize=(22.0, 15.50)) p = plt.subplot(1,2,1) colors = my_cmap(t1/t2_max) p.scatter(x, y, edgecolors=colors, s=15, linewidths=4) p = plt.subplot(1,2,2) colors = my_cmap(t2/t2_max) p.scatter(x, y, edgecolors=colors, s=15, linewidths=4) plt.subplots_adjust(left=0.2) cbar_ax = plt.axes([0.10, 0.15, 0.05, 0.7]) sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=t2_max)) sm._A = [] cbar = plt.colorbar(sm,cax=cbar_ax) plt.show() 

introduzca la descripción de la imagen aquí