【问题标题】:Changing width of bars in bar chart created using seaborn.factorplot更改使用 seaborn.factorplot 创建的条形图中条形的宽度
【发布时间】:2016-04-25 14:11:44
【问题描述】:

我正在尝试使用 seaborn.factorplot 创建条形图。我的代码如下所示:

 import seaborn
 import matplotlib.pyplot as plt 

df=pd.read_csv('data.csv')

 fg = seaborn.factorplot(x='vesselID', y='dur_min', hue='route', size=6,aspect=2    ,kind='bar', data=df)

我的 data.csv 看起来像这样

 ,route,vesselID,dur_min
 0,ANA-SJ,13,39.357894736842105
 1,ANA-SJ,20,24.747663551401867
 2,ANA-SJ,38,33.72142857142857
 3,ANA-SJ,69,37.064516129032256
 4,ED-KING,30,22.10062893081761
 5,ED-KING,36,21.821428571428573
 6,ED-KING,68,23.396551724137932
 7,F-V-S,1,13.623239436619718
 8,F-V-S,28,14.31294964028777
 9,F-V-S,33,16.161616161616163
 10,MUK-CL,18,13.953191489361702
 11,MUK-CL,19,14.306513409961687
 12,PD-TAL,65,12.477272727272727
 13,PT-COU,52,27.48148148148148
 14,PT-COU,66,28.24778761061947
 15,SEA-BI,25,30.94267515923567
 16,SEA-BI,32,31.0
 17,SEA-BI,37,31.513513513513512
 18,SEA-BR,2,55.8
 19,SEA-BR,13,57.0
 20,SEA-BR,15,54.05434782608695
 21,SEA-BR,17,50.43859649122807

现在我的问题是如何更改栏的宽度,而我无法通过更改大小和方面来实现这一点。

【问题讨论】:

  • 这是一个比你需要的复杂得多的例子,我不能只是复制并运行它。最小的,完整的!
  • 感谢您的回复。我已经编辑了我的帖子。希望这有助于解决我的问题
  • 不够简单。将数据放入示例代码中以便复制粘贴,或者使用 seaborn 示例数据集(更好的主意)。
  • 我希望这有助于解决我的问题。提前致谢。
  • 好吧,你的缩进是错误的,你使用 pd 而不导入它,并且创建一个 csv 文件比在代码 sn-p 中包含数据更烦人,但是。下次在 MVCE 上做更多工作:stackoverflow.com/help/mcve

标签: python pandas matplotlib


【解决方案1】:

我认为 seaborn 不会这样做,但 mwaskom 可能会来验证。

首先,在 seaborn 中调整 matplotlib 调用的一般方法是通过更多的 kwargs(或者在某些情况下是其中的 dict),这会像这样改变你的代码:

fg = seaborn.factorplot(x='vesselID', y='dur_min', hue='route',
                        size=6,  aspect=2,
                        kind='bar', 
                        width=10, # Factorplot passes arguments through
                        data=df)

但是当我运行时,错误是:

TypeError: bar() 为关键字参数 'width' 获取了多个值

而且,是的,事实证明,所有 seaborn 分类比较都定义了 width,并围绕它构建了很多美学。您可以直接在categorical.py 中查看draw_bars 函数,当然您可以编辑自己的categorical.py 副本,但目前seaborn 样式的那部分已被纳入。

【讨论】:

    【解决方案2】:

    seaborn 是 matplotlib 之上的一个更高级别的库。虽然 seaborn 不具备控制条形宽度的灵活性,但 matplotlib 可以通过一行代码完成:

    plt.bar(data.xcol,data.ycol,4)

    【讨论】:

      【解决方案3】:

      实际上,您可以直接使用带有函数set_width 的补丁属性来完成此操作。然而,如果你只这样做,你只会修改你的补丁宽度而不是斧头上的位置,所以你也必须改变 x 坐标。

      import pylab as plt
      import seaborn as sns
      
      tips = sns.load_dataset("tips")
      fig, ax = plt.subplots()
      
      sns.barplot(data=tips, ax=ax, x="time", y="tip", hue="sex")
      
      def change_width(ax, new_value) :
          for patch in ax.patches :
              current_width = patch.get_width()
              diff = current_width - new_value
      
              # we change the bar width
              patch.set_width(new_value)
      
              # we recenter the bar
              patch.set_x(patch.get_x() + diff * .5)
      
      change_width(ax, .35)
      plt.show()
      

      结果如下:

      【讨论】:

      • 我正在将此功能添加到我的本地实用程序模块!
      • 这对我不起作用 - 我的地块上有大约 50 个条,它们确实改变了宽度,但 x 坐标修复不起作用。
      • 好吧,也许新版本的 matlplotlib 或 seaborn 会有变化。你能告诉我你用的是哪个版本吗?
      【解决方案4】:

      就我而言,我不必定义自定义函数来更改上面建议的宽度(顺便说一句,这对我不起作用,因为所有条都未对齐)。我只是将属性 dodge=False 添加到 seaborn 绘图函数的参数中,这就成功了!例如

      sns.countplot(x='x', hue='y', data=data, dodge=False);
      

      在此处查看其他参考:https://github.com/mwaskom/seaborn/issues/871

      我的条形图现在看起来像这样:

      【讨论】:

      • 这个答案帮助我抓住了hue 用法和“细”条问题的根源。在此之前,我尝试了widthheight 参数但没有成功。它只给出了像barh() got multiple values for argument 'height' 这样的错误。
      • 完美答案!特别是当涉及到由于色调而导致的细条时
      【解决方案5】:

      这是对@jsgounot 答案的轻微修改,我觉得这很有启发性。修改有助于将条形图集中在适当的 xtick 上。

      def change_width(ax, new_value) :
          locs = ax.get_xticks()
          for i,patch in enumerate(ax.patches):
              current_width = patch.get_width()
              diff = current_width - new_value
      
              # we change the bar width
              patch.set_width(new_value)
      
              # we recenter the bar
              patch.set_x(locs[i//4] - (new_value * .5))
      

      【讨论】:

        【解决方案6】:

        另一种解决方法是修改box_aspect:

        import pylab as plt
        import seaborn as sns
        
        tips = sns.load_dataset("tips")
        fig, ax = plt.subplots()
        
        ax = sns.barplot(data=tips, ax=ax, x="time", y="tip", hue="sex")
        
        ax.set_box_aspect(10/len(ax.patches)) #change 10 to modify the y/x axis ratio
        plt.show()
        

        enter image description here

        【讨论】:

          【解决方案7】:

          类似于为 jsgounot 给出的答案,但用于更改水平条形图的宽度:

          def change_width_horizontal(ax, new_value) :
              
              for patch in ax.patches :
                  
                  current_height = patch.get_height()
                  diff = current_height - new_value
          
                  # we change the bar width
                  patch.set_height(new_value)
          
                  # we recenter the bar
                  patch.set_y(patch.get_y() + diff * .5)
          

          【讨论】: