简体   繁体   English

根据值在 Seaborn 分组条形图中设置调色板

[英]Set color-palette in Seaborn Grouped Barplot depending on values

I have a dataframe with positive and negative values from three kind of variables.我有一个 dataframe 具有来自三种变量的正值和负值。

    labels  variable    value
0   -10e5        nat     -38
1     2e5        nat      50
2    10e5        nat      16
3   -10e5        agr     -24
4     2e5        agr      35
5    10e5        agr      26
6   -10e5        art     -11
7     2e5        art      43
8    10e5        art      20

when values are negative I want the barplot to follow the color sequence:当值为负时,我希望条形图遵循颜色序列:

n_palette = ["#ff0000","#ff0000","#00ff00"]

Instead when positive I want it to reverse the palette:相反,当正面时,我希望它反转调色板:

p_palette = ["#00ff00","#00ff00","#ff0000"]

I've tried this:我试过这个:

palette = ["#ff0000","#ff0000","#00ff00",
           "#00ff00","#00ff00","#ff00",
           "#00ff00","#00ff00","#ff00"]

ax = sns.barplot(x=melted['labels'], y=melted['value'], hue = melted['variable'],
                 linewidth=1,
                 palette=palette)

But I get the following output:但我得到以下 output:

在此处输入图像描述

what I'd like is the first two bars of the group to become green and the last one red when values are positive.我想要的是该组的前两个条变为绿色,当值为正时,最后一个变为红色。

You seem to want to do the coloring depending on a criterion on two columns.您似乎想根据两列的标准进行着色。 It seems suitable to add a new column which uniquely labels that criterion.似乎适合添加一个唯一标记该标准的新列。

Further, seaborn allows the palette to be a dictionary telling exactly which hue label gets which color.此外,seaborn 允许调色板成为字典,准确地告诉 label 获得哪种颜色。 Adding barplot(..., order=[...]) would define a fixed order.添加barplot(..., order=[...])将定义一个固定的顺序。

Here is some example code:这是一些示例代码:

from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd
from io import StringIO

data_str = '''    labels  variable    value
0   -10e5        nat     -38
1     2e5        nat      50
2    10e5        nat      16
3   -10e5        agr     -24
4     2e5        agr      35
5    10e5        agr      26
6   -10e5        art     -11
7     2e5        art      43
8    10e5        art      20
'''
melted = pd.read_csv(StringIO(data_str), delim_whitespace=True, dtype={'labels': str})
melted['legend'] = np.where(melted['value'] < 0, '-', '+')
melted['legend'] = melted['variable'] + melted['legend']
palette = {'nat-': "#ff0000", 'agr-': "#ff0000", 'art-': "#00ff00",
           'nat+': "#00ff00", 'agr+': "#00ff00", 'art+': "#ff0000"}

ax = sns.barplot(x=melted['labels'], y=melted['value'], hue=melted['legend'],
                 linewidth=1, palette=palette)
ax.axhline(0, color='black')
plt.show()

sns.barplot 着色取决于积极性

PS: To remove the legend: ax.legend_.remove() . PS:要删除图例: ax.legend_.remove() Or to have a legend with multiple columns: ax.legend(ncol=3) .或者有一个多列的图例: ax.legend(ncol=3)

A different approach, directly with the original dataframe, is to create two bar plots: one for the negative values and one for the positive.直接使用原始 dataframe 的另一种方法是创建两个条形图:一个用于负值,一个用于正值。 For this to work well, it is necessary that the 'labels' column (the x= ) is explicitly made categorical.为了使其正常工作,有必要将“标签”列( x= )明确设为分类。 Also adding pd.Categorical(..., categories=['nat', 'agr', 'art']) for the 'variable' column could fix an order.还为 'variable' 列添加pd.Categorical(..., categories=['nat', 'agr', 'art'])可以修复订单。

This will generate a legend with the labels twice with different colors.这将生成一个带有两次不同 colors 的标签的图例。 Depending on what you want, you can remove it or create a more custom legend.根据您的需要,您可以将其删除或创建更自定义的图例。 An idea is to add the labels under the positive and on top of the negative bars:一个想法是在正面下方和负面栏顶部添加标签:

sns.set()
melted = pd.read_csv(StringIO(data_str), delim_whitespace=True, dtype={'labels': str})
palette_pos = {'nat': "#00ff00", 'agr': "#00ff00", 'art': "#ff0000"}
palette_neg = {'nat': "#ff0000", 'agr': "#ff0000", 'art': "#00ff00"}
melted['labels'] = pd.Categorical(melted['labels'])
ax = sns.barplot(data=melted[melted['value'] < 0], x='labels', y='value', hue='variable',
                 linewidth=1, palette=palette_neg)
sns.barplot(data=melted[melted['value'] >= 0], x='labels', y='value', hue='variable',
            linewidth=1, palette=palette_pos, ax=ax)
ax.legend_.remove()
ax.axhline(0, color='black')
ax.set_xlabel('')
ax.set_ylabel('')
for bar_container in ax.containers:
    label = bar_container.get_label()
    for p in bar_container:
        x = p.get_x() + p.get_width() / 2
        h = p.get_height()
        if not np.isnan(h):
            ax.text(x, 0, label + '\n\n' if h < 0 else '\n\n' + label, ha='center', va='center')
plt.show()

绘制 sns.barplot 两次

Still another option involves sns.catplot() which could be clearer when a lot of data is involved:还有一个选项涉及sns.catplot()当涉及大量数据时可能会更清楚:

sns.set()
melted = pd.read_csv(StringIO(data_str), delim_whitespace=True, dtype={'labels': str})
melted['legend'] = np.where(melted['value'] < 0, '-', '+')
melted['legend'] = melted['variable'] + melted['legend']
palette = {'nat-': "#ff0000", 'agr-': "#ff0000", 'art-': "#00ff00",
           'nat+': "#00ff00", 'agr+': "#00ff00", 'art+': "#ff0000"}
g = sns.catplot(kind='bar', data=melted, col='labels', y='value', x='legend',
                 linewidth=1, palette=palette, sharex=False, sharey=True)
for ax in g.axes.flat:
    ax.axhline(0, color='black')
    ax.set_xlabel('')
    ax.set_ylabel('')
plt.show()

猫图与 di

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM