【问题标题】:Seaborn Barplot - Displaying ValuesSeaborn Barplot - 显示值
【发布时间】:2017-08-30 02:39:56
【问题描述】:

我希望了解如何在 Seaborn 中使用条形图来显示数据框中的值,而不是图表中的值

1) 我希望在数据框中显示一个字段的值,同时绘制另一个字段的值。例如,在下面,我正在绘制“tip”,但我想将“total_bill”的值放在每个条形上方的中心(即周五上方的 325.88, 周六以上1778.40等)

2) 有没有办法缩放条形的颜色,“total_bill”的最低值具有最亮的颜色(在本例中为星期五),而“total_bill”的最高值具有最暗的颜色。显然,当我进行缩放时,我会坚持使用一种颜色(即蓝色)。

谢谢!我敢肯定这很容易,但我很想念它..

虽然我看到其他人认为这是另一个(或两个)问题的重复,但我错过了如何使用不在图表中的值作为标签或阴影。怎么说呢,以total_bill为依据。很抱歉,但我无法根据这些答案弄清楚。

从下面的代码开始,

import pandas as pd
import seaborn as sns
%matplotlib inline
df=pd.read_csv("https://raw.githubusercontent.com/wesm/pydata-    book/master/ch08/tips.csv", sep=',')
groupedvalues=df.groupby('day').sum().reset_index()
g=sns.barplot(x='day',y='tip',data=groupedvalues)

我得到以下结果:

临时解决方案:

for index, row in groupedvalues.iterrows():
    g.text(row.name,row.tip, round(row.total_bill,2), color='black', ha="center")

shading 上,使用下面的示例,我尝试了以下操作:

import pandas as pd
import seaborn as sns
%matplotlib inline
df=pd.read_csv("https://raw.githubusercontent.com/wesm/pydata-book/master/ch08/tips.csv", sep=',')
groupedvalues=df.groupby('day').sum().reset_index()

pal = sns.color_palette("Greens_d", len(data))
rank = groupedvalues.argsort().argsort() 
g=sns.barplot(x='day',y='tip',data=groupedvalues)

for index, row in groupedvalues.iterrows():
    g.text(row.name,row.tip, round(row.total_bill,2), color='black', ha="center")

但这给了我以下错误:

AttributeError: 'DataFrame' 对象没有属性 'argsort'

所以我尝试了修改:

import pandas as pd
import seaborn as sns
%matplotlib inline
df=pd.read_csv("https://raw.githubusercontent.com/wesm/pydata-book/master/ch08/tips.csv", sep=',')
groupedvalues=df.groupby('day').sum().reset_index()

pal = sns.color_palette("Greens_d", len(data))
rank=groupedvalues['total_bill'].rank(ascending=True)
g=sns.barplot(x='day',y='tip',data=groupedvalues,palette=np.array(pal[::-1])[rank])

这让我有了

IndexError:索引 4 超出轴 0 的范围,大小为 4

【问题讨论】:

标签: python pandas matplotlib seaborn bar-chart


【解决方案1】:

适用于单个斧头或斧头矩阵(子图)

from matplotlib import pyplot as plt
import numpy as np

def show_values_on_bars(axs):
    def _show_on_single_plot(ax):        
        for p in ax.patches:
            _x = p.get_x() + p.get_width() / 2
            _y = p.get_y() + p.get_height()
            value = '{:.2f}'.format(p.get_height())
            ax.text(_x, _y, value, ha="center") 

    if isinstance(axs, np.ndarray):
        for idx, ax in np.ndenumerate(axs):
            _show_on_single_plot(ax)
    else:
        _show_on_single_plot(axs)

fig, ax = plt.subplots(1, 2)
show_values_on_bars(ax)

【讨论】:

  • 太棒了!知道如何自动更新 y 轴限制以为文本提供足够的空间吗?
  • 很好的解决方案...将第 8 行更改为:_y = p.get_y() + p.get_height() + (p.get_height() *0.01) 看起来会好一些
【解决方案2】:

matplotlib 3.4.0 中的新功能

现在有一个内置的Axes.bar_label 可以自动标记条形容器:

  • 对于单组条形图,传递单条形容器:

    ax = sns.barplot(x='day', y='tip', data=groupedvalues)
    ax.bar_label(ax.containers[0])
    

  • 对于多组条形图(使用hue),迭代多个条形容器:

    ax = sns.barplot(x='day', y='tip', hue='sex', data=df)
    for container in ax.containers:
        ax.bar_label(container)
    

更多细节:


按颜色排序的版本

有没有办法缩放条形的颜色,total_bill 的最小值具有最亮的颜色(在本例中为星期五),total_bill 的最大值具有最暗的颜色?

  1. 查找每个total_bill 值的排名:

    • 要么使用Series.sort_values

      ranks = groupedvalues.total_bill.sort_values().index
      # Int64Index([1, 0, 3, 2], dtype='int64')
      
    • 或者通过链接Series.sub来压缩Ernest的Series.rank版本:

      ranks = groupedvalues.total_bill.rank().sub(1).astype(int).array
      # [1, 0, 3, 2]
      
  2. 然后使用ranks重新索引调色板:

    palette = sns.color_palette('Blues_d', len(ranks))
    ax = sns.barplot(x='day', y='tip', palette=np.array(palette)[ranks], data=groupedvalues)
    

【讨论】:

  • 如果要显示的值与用于绘制轴的值不同,请使用ax.bar_label() 中的labels 参数。
  • 很棒的新功能
  • Matplotlib >= 3.4 适用于 Python >= 3.7 有关更多信息,请参阅 Matplotlib API changes
【解决方案3】:

让我们坚持链接问题 (Changing color scale in seaborn bar plot) 中的解决方案。您想使用 argsort 来确定用于条形着色的颜色顺序。在链接的问题中,argsort 应用于一个 Series 对象,它工作正常,而在这里你有一个 DataFrame。因此,您需要选择该 DataFrame 的一列来应用 argsort。

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

df = sns.load_dataset("tips")
groupedvalues=df.groupby('day').sum().reset_index()

pal = sns.color_palette("Greens_d", len(groupedvalues))
rank = groupedvalues["total_bill"].argsort().argsort() 
g=sns.barplot(x='day',y='tip',data=groupedvalues, palette=np.array(pal[::-1])[rank])

for index, row in groupedvalues.iterrows():
    g.text(row.name,row.tip, round(row.total_bill,2), color='black', ha="center")

plt.show()


第二次尝试也很好,唯一的问题是rank() 返回的排名从1 开始而不是零。所以必须从数组中减去 1。同样对于索引,我们需要整数值,所以我们需要将其转换为int
rank = groupedvalues['total_bill'].rank(ascending=True).values
rank = (rank-1).astype(np.int)

【讨论】:

    【解决方案4】:

    如果有人对标记水平条形图感兴趣,我将Sharon's answer修改如下:

    def show_values_on_bars(axs, h_v="v", space=0.4):
        def _show_on_single_plot(ax):
            if h_v == "v":
                for p in ax.patches:
                    _x = p.get_x() + p.get_width() / 2
                    _y = p.get_y() + p.get_height()
                    value = int(p.get_height())
                    ax.text(_x, _y, value, ha="center") 
            elif h_v == "h":
                for p in ax.patches:
                    _x = p.get_x() + p.get_width() + float(space)
                    _y = p.get_y() + p.get_height()
                    value = int(p.get_width())
                    ax.text(_x, _y, value, ha="left")
    
        if isinstance(axs, np.ndarray):
            for idx, ax in np.ndenumerate(axs):
                _show_on_single_plot(ax)
        else:
            _show_on_single_plot(axs)
    

    两个参数解释:

    h_v - 条形图是水平的还是垂直的。 "h" 代表水平条形图,"v" 代表垂直条形图。

    space - 值文本和条形顶部边缘之间的空间。仅适用于水平模式。

    示例:

    show_values_on_bars(sns_t, "h", 0.3)
    

    【讨论】:

    • 像魅力一样工作!我唯一要添加的是水平条形图的 va="center"。
    • 可能有用添加:value = 0 if (np.isnan(p.get_height())) else int(p.get_height())value = 0 if (np.isnan(p.get_width())) else int(p.get_width()) 用于计算标签值的方式,以防条形为空大小
    • 如何获得我的ax
    • 这也适用于 Seaborn countplot(),但不适用于带色调的水平条形图。我还有一个+ float(space)h_v = "v" 时,以便它调整垂直间距的间距。我看看能不能解决色相问题。编辑:如果您使用@AndrewMo 的建议,它实际上适用于色调,尽管默认情况下垂直对齐需要一些调整。谢谢!
    • 对于 h_v="h",我们需要_y = p.get_y() + p.get_height() * 3/4 在条形中心添加标签,并且需要_x = p.get_x() + p.get_width() 没有空格以避免标签间距过宽
    【解决方案5】:
    plt.figure(figsize=(15,10))
    graph = sns.barplot(x='name_column_x_axis', y="name_column_x_axis", data = dataframe_name ,  color="salmon")
    for p in graph.patches:
            graph.annotate('{:.0f}'.format(p.get_height()), (p.get_x()+0.3, p.get_height()),
                        ha='center', va='bottom',
                        color= 'black')
    

    【讨论】:

      【解决方案6】:

      希望这对项目 #2 有所帮助: a)您可以按总账单排序,然后将索引重置为该列 b) 使用palette="Blue" 使用此颜色将图表从浅蓝色缩放到深蓝色(如果深蓝色到浅蓝色,则使用palette="Blues_d")

      import pandas as pd
      import seaborn as sns
      %matplotlib inline
      
      df=pd.read_csv("https://raw.githubusercontent.com/wesm/pydata-book/master/ch08/tips.csv", sep=',')
      groupedvalues=df.groupby('day').sum().reset_index()
      groupedvalues=groupedvalues.sort_values('total_bill').reset_index()
      g=sns.barplot(x='day',y='tip',data=groupedvalues, palette="Blues")
      

      【讨论】:

      • 在这里,您仍然按照图表中出现的条形顺序应用调色板 (the leftmost bar has the lightest color)。这个想法(也在链接的问题中提出)是按照与排序的“total_bill”列相同的顺序对颜色进行排序,这样总账单最多的列的颜色最深。
      • 是的,你是对的。在看到您的帖子之前,我没有意识到这个问题与我的理解不同。谢谢
      【解决方案7】:

      一个简单的方法是添加以下代码(针对 Seaborn):

      for p in splot.patches:
          splot.annotate(format(p.get_height(), '.1f'), 
                         (p.get_x() + p.get_width() / 2., p.get_height()), 
                         ha = 'center', va = 'center', 
                         xytext = (0, 9), 
                         textcoords = 'offset points') 
      

      例子:

      splot = sns.barplot(df['X'], df['Y'])
      # Annotate the bars in plot
      for p in splot.patches:
          splot.annotate(format(p.get_height(), '.1f'), 
                         (p.get_x() + p.get_width() / 2., p.get_height()), 
                         ha = 'center', va = 'center', 
                         xytext = (0, 9), 
                         textcoords = 'offset points')    
      plt.show()
      

      【讨论】:

        【解决方案8】:
        import seaborn as sns
        
        fig = plt.figure(figsize = (12, 8))
        ax = plt.subplot(111)
        
        ax = sns.barplot(x="Knowledge_type", y="Percentage", hue="Distance", data=knowledge)
        
        for p in ax.patches:
            ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2., p.get_height()), 
               ha = 'center', va = 'center', xytext = (0, 10), textcoords = 'offset points')
        
        

        【讨论】:

        • 适用于 Python 3.6 和 Matplotlib 3.3.4
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-28
        • 1970-01-01
        • 2020-11-05
        • 2019-04-05
        • 2021-02-23
        • 2020-05-23
        • 2019-12-02
        相关资源
        最近更新 更多