【问题标题】:Coloring Matplotlib heatmap according to requirement根据要求着色 Matplotlib 热图
【发布时间】:2020-12-15 18:01:59
【问题描述】:

我创建了一个简单的 matplotlib 热图,其中如果单元格的值高于 2.3,则每个单元格将显示为红色或绿色。

现在,我想拥有它,而不是简单的红色或绿色 根据单元格的值与2.3 的差异程度,更深或更浅,例如1 的红色将比2.1 更深。

有没有办法做到这一点?到现在为止,我只能做到二进制,感谢this question

ax1 = fig.add_subplot(111)

a = np.array([[0.8, 2.4, 2.5, 3.9],
              [2.4, 0.0, 4.0, 1.0],
              [1.1, 2.4, 0.8, 4.3],
              [0.6, 0.0, 0.3, 0.0],
              [0.7, 1.7, 0.6, 2.6]])

cmap = matplotlib.colors.ListedColormap(['#ff3d3d', '#74ff52'])

bounds = [np.amin(a), 2.3, np.amax(a)]

norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)

ax1.imshow(a, interpolation='none', cmap=cmap, norm=norm)

【问题讨论】:

    标签: python python-3.x matplotlib


    【解决方案1】:

    LinearSegmentedColormap 可以从颜色列表创建连续的颜色图。它有助于在中间显式设置颜色(例如“黄色”)以创建区别。

    TwoSlopeNorm 可以精确定位中心的精确值。

    import matplotlib.pyplot as plt
    import matplotlib
    from matplotlib.ticker import MultipleLocator
    import numpy as np
    
    a = np.array([[0.8, 2.4, 2.5, 3.9],
                  [2.4, 0.0, 4.0, 1.0],
                  [1.1, 2.4, 0.8, 4.3],
                  [0.6, 0.0, 0.3, 0.0],
                  [0.7, 1.7, 0.6, 2.6]])
    cmap = matplotlib.colors.LinearSegmentedColormap.from_list('', ['#ff3d3d', 'yellow', '#74ff52'])
    norm = matplotlib.colors.TwoSlopeNorm(vcenter=2.3, vmin=a.min(), vmax=a.max())
    
    fig, ax = plt.subplots()
    img = ax.imshow(a, interpolation='none', cmap=cmap, norm=norm)
    ax.xaxis.set_major_locator(MultipleLocator(1))
    ax.yaxis.set_major_locator(MultipleLocator(1))
    plt.colorbar(img, ax=ax)
    plt.tight_layout()
    plt.show()
    

    左边是黄色作为中心颜色的例子,中间是白色,右边是没有明确设置中心颜色的例子。

    PS:如果中心值不在最小值和最大值之间,则整个图像将是红色或绿色。在这种情况下,您可以将规范创建为:

    bounds = sorted([2.3,  a.min(), a.max()])
    norm = matplotlib.colors.TwoSlopeNorm(vcenter=bounds[1], vmin=bounds[0], vmax=bounds[2])
    

    【讨论】:

    • 太棒了,非常感谢!只是一件小事:我尝试使用不同的数据数组、相同的行数和不同的值,但出现以下错误:vmin、vcenter 和 vmax 必须按升序排列。我如何对 vmin 和 vmax 进行排序以避免这种情况?
    • 好吧,对不起,我忘记了一个 0 并且中间值大于 vmax,我的错!万分感谢!这对我帮助很大!
    • 确实,当值不在两者之间时,我会发生如何处理,但您已经回答了这个问题。再次感谢!
    【解决方案2】:

    这是我使用 seaborn 库的解决方案。
    (最好在您的 PC 上安装 matplotlib 3.1.0,因为 matplotlib 3.1.1 在显示热图时可能会导致问题)。

    import seaborn 
    import numpy as np
    import matplotlib.pyplot as plt
    
    a = np.array([[0.8, 2.4, 2.5, 3.9],
                  [2.4, 0.0, 4.0, 1.0],
                  [1.1, 2.4, 0.8, 4.3],
                  [0.6, 0.0, 0.3, 0.0],
                  [0.7, 1.7, 0.6, 2.6]])
    
    #b = np.array([[1,2],[3,4]])
    minVal = np.amin(a)
    maxVal = np.amax(a)
    diffs = abs(2.3 - a)
    
    seaborn.heatmap(a, annot=True, linewidths=.5, square=True, vmin=np.amin(a), vmax=np.amax(a), cmap='RdYlGn')
    plt.figure()
    seaborn.heatmap(diffs, annot=True, linewidths=.5, square=True, vmin=np.amin(diffs), vmax=np.amax(diffs), cmap='Reds')
    

    第一个热图是您的原始“a”矩阵,如下所示:

    第二个热图表示 a 与 2.3 不同的值,如下所示:

    【讨论】:

    • 非常感谢您的帮助!这很好,但问题是我需要使用 MPL 来生成热图,因为稍后我将不得不保存图形,这是目前只有 MPL AFAIK 才有的功能
    • @JayK23 seaborn 只是 matplotlib 之上的一个接口。您可以在 seaborn 创建的绘图上简单地调用 plt.savefig()。您还可以使用任何 matplotlib 函数对 seaborn 绘图进行更改和添加额外内容。因此,您通常通过ax = sns.heatmap(...) 获取ax。或者提供一个已经创建的ax 作为 seaborn 函数 (sns.heatmap(..., ax=ax)) 的参数。
    • 我不知道这一点,因为我刚刚开始更深入地研究 MPL,但这会带来很多新的机会。我也在尝试对 seaborn 做同样的事情。非常感谢!
    猜你喜欢
    • 2014-01-21
    • 2020-11-24
    • 2012-08-06
    • 2019-10-17
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 2013-11-03
    相关资源
    最近更新 更多