使用Matplotlib

时间:2017-05-03 13:26:14

标签: python matplotlib heatmap colormap

我创建了一个GUI,其中有实时的时间点'几个记录("事物")和字段的数据。记录可以根据字段进行比较,但字段不一定相关(至少不是相同的比例)。对于我最终的GUI,我希望主页面是热图(实际上是一堆基于列(字段)的1-D热图,然后如果你点击一个,它将给出时间序列历史和其他一些图表。 / p>

无论如何,我在这之后,正试图让初始热图显示出我想要的方式。到目前为止,我可以从Matplotlib获得pcolormesh,基本上通过基于列的百分位数进行黑客攻击和热映射来显示基于字段的单个1-D热图,然后在顶部添加实际值的文本。

但是,正如我所说,字段不一定相关,我希望能够为每个字段设置单独的色彩映射。例如:说字段3和4与一个字段定性相关另一个,但不是字段0-3 - 所以如果映射到这些绿色'那将是很好的。 colormesh而不是' coolwarm'。

到目前为止,这是我的代码,结果是pcolormesh / heatmap:

import pandas as pd
import matplotlib.pyplot as plt

def DFPercentiles(df,bycols=True):
    p=pd.DataFrame(index=df.index,columns=df.columns)
    if bycols!=True:
        for j in df.index:
            for i in df.columns:
                p.loc[j,i]=(df.loc[j,i]-min(df.loc[j,:]))/(max(df.loc[j,:])-min(df.loc[j,:]))
    else:
        for i in df.index:
            for j in df.columns:
                p.loc[i,j]=(df.loc[i,j]-min(df.loc[:,j]))/(max(df.loc[:,j])-min(df.loc[:,j]))
    return p

def Heatmap(df,figsize='auto'):
    if figsize=='auto':
        figsize=[shape(df)[1],shape(df)[0]/2]
    fig=figure(figsize=figsize)
    pdf=array(DFPercentiles(df,bycols=True)).astype(float)[::-1]
    plt.pcolormesh(pdf,cmap=cm.coolwarm,alpha=0.8)
    plt.yticks(arange(0.5,len(df)),df.index[::-1])
    plt.xticks(arange(0.5,len(df.columns)),df.columns)
    for y in range(df.shape[0]):
        for x in range(df.shape[1]):
            plt.text(x + 0.5, y + 0.5, '%.3f' % df[::-1].iloc[y, x],
                     horizontalalignment='center',
                     verticalalignment='center',
                     )
    return plt

hmap=Heatmap(mydf)
hmap.show()

结果:

Multiple 1-D heatmaps on one pcolormesh, but can't get multiple colormaps

我没有运气试图为不同的字段获取多个色彩映射。

2 个答案:

答案 0 :(得分:1)

每个colormesh图都有一个与之关联的色彩图。为了在一个图表中使用多个色图,我看到以下选项:

  1. 个别矩形: 不要使用pcolormesh,而是以您喜欢的颜色绘制单个矩形。
  2. 创建自定义色彩映射,其中包含不同范围内的不同色彩映射。例如。从0到0.4的值映射到一个颜色映射的颜色,值从0.4到1映射到另一个颜色映射的颜色。这可能看起来像:

    import matplotlib.pyplot as plt
    import matplotlib.colors
    import numpy as np
    
    x,y = np.meshgrid(range(4), range(4))
    z = np.array([[0.2,.3,.95],[.5,.76,0.4],[.3,.1,.6]]).astype(float)
    mask= np.array([[1,0,0],[1,0,0],[1,1,1]]).astype(float)
    Z = z + mask
    
    c2 = plt.cm.Greens(np.linspace(0,1,128))
    c1 = plt.cm.coolwarm(np.linspace(0,1,128))
    cols = np.vstack((c1, c2))
    cmap=matplotlib.colors.LinearSegmentedColormap.from_list("q", cols)
    
    fig, ax=plt.subplots()
    ax.pcolormesh(x,y,Z, vmin=0, vmax=2, cmap=cmap)
    
    plt.show()
    
  3. 掩码数组并绘制几个pcolormesh图。以下示例显示了这可能如何:

        import matplotlib.pyplot as plt
        import numpy as np
        import numpy.ma as ma
    
        x,y = np.meshgrid(range(4), range(4))
        z = np.array([[1,1.3,3],[2.2,2.8,1.8],[3,1,3]]).astype(float)
        mask= np.array([[1,0,0],[1,0,0],[1,1,1]]).astype(bool)
        z1 = np.copy(z)
        z1[mask] = np.nan
    
        z2 = np.copy(z)
        z2[~mask] = np.nan
    
        fig, ax=plt.subplots()
        ax.pcolormesh(x,y,ma.masked_invalid(z1), vmin=1, vmax=3, cmap="coolwarm")
        ax.pcolormesh(x,y,ma.masked_invalid(z2), vmin=1, vmax=3, cmap="Greens")
    
        plt.show()
    
  4. enter image description here

答案 1 :(得分:1)

实施@ImportanceOfBeingErnest解决方案

使用色彩图堆叠来创建地图的自定义色彩映射。基本上我的函数现在采用([列列],乘数,颜色映射的元组)并堆叠独特的颜色映射并将百分位数据分组以匹配各个颜色映射(端点很难避免着色重叠)。我可能没有超高效地实现它,但效果很好:

def DFPercentiles_hmapshift(df,bycols=True):
    p=pd.DataFrame(index=df.index,columns=df.columns)
    if bycols!=True:
        for j in df.index:
            for i in df.columns:
                pct=(df.loc[j,i]-min(df.loc[j,:]))/((max(df.loc[j,:])-min(df.loc[j,:]))*1.)
                pct=pct-(pct-0.5)*1./40 #have to rescale it to account for endpoints of cmaps
                p.loc[j,i]=pct
                #print '('+str(max(p.loc[j,:]))+', '+str(min(p.loc[j,:]))+')'

    else:
        for i in df.index:
            for j in df.columns:
                pct=(df.loc[i,j]-min(df.loc[:,j]))/((max(df.loc[:,j])-min(df.loc[:,j]))*1.)
                pct=pct-(pct-0.5)*1./40 #have to rescale it to account for endpoints of cmaps
                p.loc[i,j]=pct
                #print '('+str(max(p.loc[:,j]))+', '+str(min(p.loc[:,j]))+')'
    return p

def Heatmap(df,figsize='auto',ccmaps=[(['Default'],0,'coolwarm')]):
    if figsize=='auto':
        figsize=[shape(df)[1],shape(df)[0]/2]
    fig=figure(figsize=figsize)
    #pdf=array(DFPercentiles(df,bycols=True)).astype(float)[::-1]
    pdf=DFPercentiles_hmapshift(df,bycols=True)
    if len(ccmaps)==1:
        cmap=ccmaps[0][2]
    else:
        cmapl=[]
        for x in ccmaps:
            if x[1]!=0:
                for y in x[0]:
                    pdf[y]=pdf[y]+x[1]
            cmapl.append(getattr(plt.cm,x[2])(np.linspace(0,1,256,endpoint=False)+0.5/256.))
        pdf=np.divide(pdf,len(ccmaps))
        cs=np.vstack(cmapl)
        cmap=matplotlib.colors.LinearSegmentedColormap.from_list("custom",cs)
    pdf=array(pdf).astype(float)[::-1]
    plt.pcolormesh(pdf,cmap=cmap,alpha=0.8)
    plt.yticks(arange(0.5,len(df)),df.index[::-1])
    plt.xticks(arange(0.5,len(df.columns)),df.columns)
    for y in range(df.shape[0]):
        for x in range(df.shape[1]):
            plt.text(x + 0.5, y + 0.5, '%.3f' % df[::-1].iloc[y, x],
                     horizontalalignment='center',
                     verticalalignment='center',
                     )
    return plt

hmap=Heatmap(mydf,ccmaps=[(['Default'],0,'RdBu_r'),(['Field3','Field4'],1,'Greens'),
                     (['Field0'],2,'Greys')])
hmap.show()

为了美丽(好吧,这只是一个例子!)结果:

enter image description here