pandas seaborn 热图图中的离散图例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38836154/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 01:45:37  来源:igfitidea点击:

Discrete legend in seaborn heatmap plot

pythonpandasmatplotlibseaborn

提问by user308827

I am using the data present here to construct this heat map using seaborn and pandas.

我正在使用此处提供的数据使用 seaborn 和 pandas 构建此热图。

Code:

代码:

    import pandas
    import seaborn.apionly as sns

    # Read in csv file
    df_trans = pandas.read_csv('LUH2_trans_matrix.csv')

    sns.set(font_scale=0.8)
    cmap = sns.cubehelix_palette(start=2.8, rot=.1, light=0.9, as_cmap=True)
    cmap.set_under('gray')  # 0 values in activity matrix are shown in gray (inactive transitions)
    df_trans = df_trans.set_index(['Unnamed: 0'])
    ax = sns.heatmap(df_trans, cmap=cmap, linewidths=.5, linecolor='lightgray')

    # X - Y axis labels
    ax.set_ylabel('FROM')
    ax.set_xlabel('TO')

    # Rotate tick labels
    locs, labels = plt.xticks()
    plt.setp(labels, rotation=0)
    locs, labels = plt.yticks()
    plt.setp(labels, rotation=0)

    # revert matplotlib params
    sns.reset_orig()

As you can see from csv file, it contains 3 discrete values: 0, -1 and 1. I want a discrete legend instead of the colorbar. Labeling 0 as A, -1 as B and 1 as C. How can I do that?

正如您从 csv 文件中看到的那样,它包含 3 个离散值:0、-1 和 1。我想要一个离散图例而不是颜色条。将 0 标记为 A,将 -1 标记为 B,将 1 标记为 C。我该怎么做?

采纳答案by heenenee

Well, there's definitely more than one way to accomplish this. In this case, with only three colors needed, I would pick the colors myself by creating a LinearSegmentedColormapinstead of generating them with cubehelix_palette. If there were enough colors to warrant using cubehelix_palette, I would define the segments on colormap using the boundariesoption of the cbar_kwsparameter. Either way, the ticks can be manually specified using set_ticksand set_ticklabels.

嗯,肯定有不止一种方法可以实现这一点。在这种情况下,只需要三种颜色,我会通过创建一个LinearSegmentedColormap而不是生成它们来自己选择颜色cubehelix_palette。如果有足够的颜色来保证使用cubehelix_palette,我将使用参数boundaries选项定义颜色图上的段cbar_kws。无论哪种方式,都可以使用set_ticks和手动指定刻度set_ticklabels

The following code sample demonstrates the manual creation of LinearSegmentedColormap, and includes comments on how to specify boundaries if using a cubehelix_paletteinstead.

以下代码示例演示了 的手动创建LinearSegmentedColormap,并包含有关如何在使用 时指定边界的注释cubehelix_palette

import matplotlib.pyplot as plt
import pandas
import seaborn.apionly as sns
from matplotlib.colors import LinearSegmentedColormap

sns.set(font_scale=0.8)
dataFrame = pandas.read_csv('LUH2_trans_matrix.csv').set_index(['Unnamed: 0'])

# For only three colors, it's easier to choose them yourself.
# If you still really want to generate a colormap with cubehelix_palette instead,
# add a cbar_kws={"boundaries": linspace(-1, 1, 4)} to the heatmap invocation
# to have it generate a discrete colorbar instead of a continous one.
myColors = ((0.8, 0.0, 0.0, 1.0), (0.0, 0.8, 0.0, 1.0), (0.0, 0.0, 0.8, 1.0))
cmap = LinearSegmentedColormap.from_list('Custom', myColors, len(myColors))

ax = sns.heatmap(dataFrame, cmap=cmap, linewidths=.5, linecolor='lightgray')

# Manually specify colorbar labelling after it's been generated
colorbar = ax.collections[0].colorbar
colorbar.set_ticks([-0.667, 0, 0.667])
colorbar.set_ticklabels(['B', 'A', 'C'])

# X - Y axis labels
ax.set_ylabel('FROM')
ax.set_xlabel('TO')

# Only y-axis labels need their rotation set, x-axis labels already have a rotation of 0
_, labels = plt.yticks()
plt.setp(labels, rotation=0)

plt.show()

Heatmap using red, green, and blue as colors with a discrete colorbar

使用红色、绿色和蓝色作为具有离散颜色条的颜色的热图

回答by Esostack

Here's a simple solution based on the other answers that generalizes beyond 3 categories and uses a dict (vmap) to define the labels.

这是一个基于其他答案的简单解决方案,它概括了 3 个类别并使用 dict (vmap) 来定义标签。

import seaborn as sns
import numpy as np

# This just makes some sample 2D data and a corresponding vmap dict with labels for the values in the data
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
vmap = {i: chr(65 + i) for i in range(len(np.ravel(data)))}
n = len(vmap)

print(vmap)

cmap = sns.color_palette("deep", n)
ax = sns.heatmap(data, cmap=cmap)

# Get the colorbar object from the Seaborn heatmap
colorbar = ax.collections[0].colorbar
# The list comprehension calculates the positions to place the labels to be evenly distributed across the colorbar
r = colorbar.vmax - colorbar.vmin
colorbar.set_ticks([colorbar.vmin + 0.5 * r / (n) + r * i / (n) for i in range(n)])
colorbar.set_ticklabels(list(vmap.values()))

enter image description here

在此处输入图片说明

回答by lanery

I find that a discretized colorbar in seaborn is much easier to create if you use a ListedColormap. There's no need to define your own functions, just add a few lines to basically customize your axes.

我发现如果您使用ListedColormap. 无需定义您自己的函数,只需添加几行即可基本自定义您的轴。

import pandas
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import ListedColormap


# Read in csv file
df_trans = pandas.read_csv('LUH2_trans_matrix.csv')

sns.set(font_scale=0.8)
# cmap is now a list of colors
cmap = sns.cubehelix_palette(start=2.8, rot=.1, light=0.9, n_colors=3)
df_trans = df_trans.set_index(['Unnamed: 0'])

# Create two appropriately sized subplots
grid_kws = {'width_ratios': (0.9, 0.03), 'wspace': 0.18}
fig, (ax, cbar_ax) = plt.subplots(1, 2, gridspec_kw=grid_kws)

ax = sns.heatmap(df_trans, ax=ax, cbar_ax=cbar_ax, cmap=ListedColormap(cmap),
                 linewidths=.5, linecolor='lightgray',
                 cbar_kws={'orientation': 'vertical'})

# Customize tick marks and positions
cbar_ax.set_yticklabels(['B', 'A', 'C'])
cbar_ax.yaxis.set_ticks([ 0.16666667, 0.5, 0.83333333])


# X - Y axis labels
ax.set_ylabel('FROM')
ax.set_xlabel('TO')

# Rotate tick labels
locs, labels = plt.xticks()
plt.setp(labels, rotation=0)
locs, labels = plt.yticks()
plt.setp(labels, rotation=0)

enter image description here

在此处输入图片说明

回答by jlarsch

The link provided by @Fabio Lamanna is a great start.

@Fabio Lamanna 提供的链接是一个很好的开始。

From there, you still want to set colorbar labels in the correct location and use tick labels that correspond to your data.

从那里,您仍然希望在正确的位置设置颜色条标签并使用与您的数据相对应的刻度标签。

assuming that you have equally spaced levels in your data, this produces a nice discrete colorbar:

假设您的数据中有等距的级别,这会产生一个很好的离散颜色条:

Basically, this comes down to turning off the seaborn colorbar and replacing it with a discretized colorbar yourself.

基本上,这归结为关闭 seaborn colorbar 并自己用离散化的 colorbar 替换它。

enter image description here

在此处输入图片说明

import pandas
import seaborn.apionly as sns
import matplotlib.pyplot as plt
import numpy as np
import matplotlib

def cmap_discretize(cmap, N):
    """Return a discrete colormap from the continuous colormap cmap.

        cmap: colormap instance, eg. cm.jet. 
        N: number of colors.

    Example
        x = resize(arange(100), (5,100))
        djet = cmap_discretize(cm.jet, 5)
        imshow(x, cmap=djet)
    """

    if type(cmap) == str:
        cmap = plt.get_cmap(cmap)
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
    colors_rgba = cmap(colors_i)
    indices = np.linspace(0, 1., N+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
    # Return colormap object.
    return matplotlib.colors.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

def colorbar_index(ncolors, cmap, data):

    """Put the colorbar labels in the correct positions
        using uique levels of data as tickLabels
    """

    cmap = cmap_discretize(cmap, ncolors)
    mappable = matplotlib.cm.ScalarMappable(cmap=cmap)
    mappable.set_array([])
    mappable.set_clim(-0.5, ncolors+0.5)
    colorbar = plt.colorbar(mappable)
    colorbar.set_ticks(np.linspace(0, ncolors, ncolors))
    colorbar.set_ticklabels(np.unique(data))


# Read in csv file
df_trans = pandas.read_csv('d:/LUH2_trans_matrix.csv')

sns.set(font_scale=0.8)
cmap = sns.cubehelix_palette(n_colors=3,start=2.8, rot=.1, light=0.9, as_cmap=True)
cmap.set_under('gray')  # 0 values in activity matrix are shown in gray (inactive transitions)
df_trans = df_trans.set_index(['Unnamed: 0'])

N = df_trans.max().max() - df_trans.min().min() + 1

f, ax = plt.subplots()
ax = sns.heatmap(df_trans, cmap=cmap, linewidths=.5, linecolor='lightgray',cbar=False)
colorbar_index(ncolors=N, cmap=cmap,data=df_trans)    

# X - Y axis labels
ax.set_ylabel('FROM')
ax.set_xlabel('TO')

# Rotate tick labels
locs, labels = plt.xticks()
plt.setp(labels, rotation=0)
locs, labels = plt.yticks()
plt.setp(labels, rotation=0)

# revert matplotlib params
sns.reset_orig()

bits and pieces recycled and adapted from hereand here

这里这里回收和改编的点点滴滴