使用Matplotlib具有多个颜色图的单个pcolormesh [英] Single pcolormesh with more than one colormap using Matplotlib

查看:351
本文介绍了使用Matplotlib具有多个颜色图的单个pcolormesh的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个GUI,其中有一些记录(事物")和字段的实时时间点"数据.记录基于字段是可比较的,但是字段不一定是相关的(至少不是相同比例).对于我最终的GUI,我希望主页是一个热图(实际上是一堆基于列(字段)的一维热图,然后,如果单击其中一个,它将提供时间序列历史记录和一些其他图表. /p>

无论如何,我在这里想要得到的初始热度图就是我想要的方式.到目前为止,我可以从Matplotlib中获取pcolormesh,从本质上显示基于字段的单个一维热图,方法是对其进行黑客攻击,然后根据列的百分位数进行热映射,然后在顶部添加实际值的文本.

但是,正如我所说,字段不一定是相关的,我希望能够为每个字段使用单独的颜色图.例如:说字段3和4在质量上与一个字段相关另一个,但不是0-3字段-因此,最好将其映射为说绿色"颜色网格而不是冷色".

到目前为止,这是我的代码,并生成了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()

结果:

我没有运气试图为单独的字段获取多个颜色图.

解决方案

每个色目图都有一个与之关联的色图.为了在一张图中使用多个颜色图,因此我看到以下选项:

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

I'm creating a GUI where there is live 'point in time' data for several records ("things") and fields. records are comparable based on field, but fields are not necessarily related (at least not on same scale). For my eventual GUI, I want to have the main page be a heatmap (really a bunch of 1-D heatmaps based on columns (fields), then if you click on one it will give a time series history and some other charts.

Anyway, what I'm after here, is trying to get the initial heatmap to show the way I want. As of now I can get the pcolormesh from Matplotlib to essentially show individual 1-D heatmaps based on field by hacking it and heatmapping based on percentile of column, and then adding text of the actual value on top.

But, as I said, fields are not necessarily related, and I would like to be able to have individual colormaps for each field. For example: say Fields 3 and 4 are qualitatively related to one another, but not to Fields 0-3 - so it would be nice to have those mapped to say the 'greens' colormesh rather than 'coolwarm'.

Here is my code so far and resulting 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()

And the result:

I've had no luck trying to get multiple colormaps for separate fields.

解决方案

Each colormesh plot has one colormap associated to it. In order to use several colormaps in one diagram, I therefore see the following options:

  1. Individual rectangles: Don't use pcolormesh but draw individual rectangles in the color of your liking.
  2. Create your custom colormap which incorporates different colormaps within different ranges. E.g. values from 0 to 0.4 are mapped to colors from one colormap and values from 0.4 to 1 to colors from another colormap. This may then look like:

    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. Mask the arrays and plot several pcolormesh plots. The following example shows how this might then look like:

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

这篇关于使用Matplotlib具有多个颜色图的单个pcolormesh的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆