2012-07-19 23 views
9

有可能用彩色线之间,以填补之间的连续颜色表填写:matplotlib:两行

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

它也可以使用连续的颜色表的一行:

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

对于两行之间的彩色填充使用连续颜色映射是否可能(并且相当容易)?例如,根据x(或基于另一组数据)中两行之间的差异,颜色填充可能会沿x变化。

回答

6

我找到了解决这个问题的办法。它建立在@Hooked的辉煌但是很冒险的solution上。你从很多小盒子中创建一个2D网格。这不是最快的解决方案,但它应该非常灵活(比应用imshow到补丁的解决方案更加灵活)。

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

结果是, enter image description here

+0

很好的例子,也许你可以添加你的'矩形()'函数,以便得到自洽的例子。谢谢 – Ger 2016-08-31 09:25:41

+0

谢谢@Ger,没有意识到我忘记了这一点,而'rect'实际上并不重要 – 2016-08-31 10:43:30

2

您的解决方案是伟大的,灵活!特别是2D情况非常好。如果函数的颜色kwargs可以接受x和y相同长度的数组,则可以将这样的特征添加到fill_between中。

下面是使用fill_between函数的一维情况的一个更简单的情况。它做同样的事情,但它使用梯形而不是矩形,结果更平滑。

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

enter image description here