matplotlib: relleno de mapa de colores continuo entre dos líneas

Es posible rellenar entre líneas con un color:

http://matplotlib.sourceforge.net/examples/pylab_examples/fill_between_demo.html

También es posible usar un mapa de colores continuo para una línea:

http://matplotlib.sourceforge.net/examples/pylab_examples/multicolored_line.html

¿Es posible (y razonablemente fácil) usar un mapa de colores continuo para el relleno coloreado entre dos líneas? Por ejemplo, el relleno de color puede cambiar a lo largo de x en función de la diferencia entre las dos líneas en x (o en función de otro conjunto de datos).

Encontré una solución a este problema. Se basa en la solución shiny pero intrépida de @Hooked. Usted crea una cuadrícula 2D archivada de un montón de cajas pequeñas. No es la solución más rápida, pero debería ser bastante flexible (más que las soluciones que se aplican directamente a los parches).

import numpy as np import pylab as plt #Plot a rectangle def rect(ax, x, y, w, h, c,**kwargs): #Varying only in x if len(c.shape) is 1: rect = plt.Rectangle((x, y), w, h, color=c, ec=c,**kwargs) ax.add_patch(rect) #Varying in x and y else: #Split into a number of bins N = c.shape[0] hb = h/float(N); yl = y for i in range(N): yl += hb rect = plt.Rectangle((x, yl), w, hb, color=c[i,:], ec=c[i,:],**kwargs) ax.add_patch(rect) #Fill a contour between two lines def rainbow_fill_between(ax, X, Y1, Y2, colors=None, cmap=plt.get_cmap("Reds"),**kwargs): plt.plot(X,Y1,lw=0) # Plot so the axes scale correctly dx = X[1]-X[0] N = X.size #Pad a float or int to same size as x if (type(Y2) is float or type(Y2) is int): Y2 = np.array([Y2]*N) #No colors -- specify linear if colors is None: colors = [] for n in range(N): colors.append(cmap(n/float(N))) #Varying only in x elif len(colors.shape) is 1: colors = cmap((colors-colors.min()) /(colors.max()-colors.min())) #Varying only in x and y else: cnp = np.array(colors) colors = np.empty([colors.shape[0],colors.shape[1],4]) for i in range(colors.shape[0]): for j in range(colors.shape[1]): colors[i,j,:] = cmap((cnp[i,j]-cnp[:,:].min()) /(cnp[:,:].max()-cnp[:,:].min())) colors = np.array(colors) #Create the patch objects for (color,x,y1,y2) in zip(colors,X,Y1,Y2): rect(ax,x,y2,dx,y1-y2,color,**kwargs) # Some Test data X = np.linspace(0,10,100) Y1 = .25*X**2 - X Y2 = X g = np.exp(-.3*(X-5)**2) #Plot fill and curves changing in x only fig, axs =plt.subplots(1,2) colors = g rainbow_fill_between(axs[0],X,Y1,Y2,colors=colors) axs[0].plot(X,Y1,'k-',lw=4) axs[0].plot(X,Y2,'k-',lw=4) #Plot fill and curves changing in x and y colors = np.outer(g,g) rainbow_fill_between(axs[1],X,Y1,Y2,colors=colors) axs[1].plot(X,Y1,'k-',lw=4) axs[1].plot(X,Y2,'k-',lw=4) plt.show() 

El resultado es, introduzca la descripción de la imagen aquí

¡Su solución es excelente y flexible! En particular el caso 2D es muy bonito. Tal característica podría agregarse a fill_between tal vez si los colores kwargs de la función aceptaran una matriz de la misma longitud de x e y?

Aquí hay un caso más simple para el caso 1D usando la función fill_between . Hace lo mismo, pero al usar trapecios en lugar de rectangularjs, el resultado es más suave.

 import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np from scipy.stats import norm # Select a color map cmap = mpl.cm.bwr # Some Test data npts = 100 x = np.linspace(-4, 4, npts) y = norm.pdf(x) z = np.sin(2 * x) normalize = mpl.colors.Normalize(vmin=z.min(), vmax=z.max()) # The plot fig = plt.figure() ax = fig.add_axes([0.12, 0.12, 0.68, 0.78]) plt.plot(x, y, color="gray") for i in range(npts - 1): plt.fill_between([x[i], x[i+1]], [y[i], y[i+1]], color=cmap(normalize(z[i]))) cbax = fig.add_axes([0.85, 0.12, 0.05, 0.78]) cb = mpl.colorbar.ColorbarBase(cbax, cmap=cmap, norm=normalize, orientation='vertical') cb.set_label("Sin function", rotation=270, labelpad=15) plt.show() 

introduzca la descripción de la imagen aquí