python 更改使用catplot或barplot创建的条形图的宽度

mfuanj7w  于 2023-06-04  发布在  Python
关注(0)|答案(8)|浏览(840)

我正在尝试使用seaborn.factorplot创建条形图。我的代码看起来像这样:

import seaborn as sns
import matplotlib.pyplot as plt 
 
df = pd.read_csv('data.csv')
 
fg = sns.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

现在我的问题是如何改变酒吧的宽度,我不能通过改变大小和方面来实现这一点。

bksxznpy

bksxznpy1#

在我的例子中,我不需要定义一个自定义函数来改变上面建议的宽度(顺便说一句,这对我不起作用,因为所有的条都是不对齐的)。我只是简单地将属性dodge=False添加到seaborn plotting函数的参数中,这就成功了!例如

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

参见此处的附加参考:https://github.com/mwaskom/seaborn/issues/871
我的条形图现在看起来像这样:

368yc8dk

368yc8dk2#

实际上,您可以通过函数set_width直接使用patches属性来实现。但是,如果你只这样做,你只会修改你的补丁宽度,而不是在轴上的位置,所以你必须改变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()

结果是这样的:

voj3qocg

voj3qocg3#

我不认为西伯恩会这么做,但有可能姆瓦斯科姆会来核实。
首先,在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”获取了多个值
而且,是的,事实证明所有的海运分类比较都定义了width,并围绕它构建了很多美学。你可以直接在categorical.py中检查draw_bars函数,当然你也可以编辑你自己的www.example.com副本categorical.py,但是这部分seaborn的风格目前已经被烘焙了。

2wnc66cl

2wnc66cl4#

  • sns.factorplot已重命名为sns.catplot
  • 这是一个单一的Facet图,所以sns.barplot也可以工作。
  • 请参见图形级别与轴级函数
  • 接受的answer不起作用,因为它产生了这个plot,有许多重叠的条。

1.这个高投票率的answer(带有dodge=False)不起作用,因为'vesselID' == 13有两条路由,这导致'SEA-BR'被绘制在'ANA-SJ'的顶部,并导致这个plot

*当x轴上的一个类别有多个hue类别时,如果使用dodge=False,则条形图将彼此叠加。

  1. hue不应用于对出现在x轴上的相同类别进行双重编码(例如,x='route'hue='route'):
  2. seaborn已经为条形图着色,如本plot所示。
    1.颜色编码没有任何意义,如本answer所述。如果颜色编码没有意义,则条应该是单色,如plot所示。
    1.对于这种情况,最好的选择是针对唯一值绘制条形图,例如df.index,如果它是RangeIndex(例如range(0, 22)),使用dodge=False,然后使用set_xticklabels设置正确的标签。
import pandas as pd
import seaborn as sns

# DataFrame with data from the OP
data = {'route': ['ANA-SJ', 'ANA-SJ', 'ANA-SJ', 'ANA-SJ', 'ED-KING', 'ED-KING', 'ED-KING', 'F-V-S', 'F-V-S', 'F-V-S', 'MUK-CL', 'MUK-CL', 'PD-TAL', 'PT-COU', 'PT-COU', 'SEA-BI', 'SEA-BI', 'SEA-BI', 'SEA-BR', 'SEA-BR', 'SEA-BR', 'SEA-BR'],
        'vesselID': [13, 20, 38, 69, 30, 36, 68, 1, 28, 33, 18, 19, 65, 52, 66, 25, 32, 37, 2, 13, 15, 17],
        'dur_min': [39.357894736842105, 24.747663551401867, 33.72142857142857, 37.064516129032256, 22.10062893081761, 21.821428571428573, 23.39655172413793, 13.623239436619718, 14.31294964028777, 16.161616161616163, 13.953191489361702, 14.306513409961688, 12.477272727272728, 27.48148148148148, 28.24778761061947, 30.94267515923567, 31.0, 31.513513513513512, 55.8, 57.0, 54.05434782608695, 50.43859649122807]}

df = pd.DataFrame(data)

# sort df by the vesselID column, and ignore the index, which resets the index 
df = df.sort_values('vesselID', ignore_index=True)

# set the hue order to alphabetical
hue_order = sorted(df.route.unique())

# plot the data
g = sns.catplot(data=df, kind='bar', x=df.index.tolist(), y='dur_min', hue='route', aspect=1.5, dodge=False, hue_order=hue_order)

# set some nicer labels
g.set(xlabel='Vessel ID', ylabel='Duration (Min)')

# extract the the matplotlib.axes.Axes from the FacetGrid
ax = g.axes.flat[0]

# set the xticklabels
_ = ax.set_xticks(ticks=df.index, labels=df.vesselID)

  • 排序后df
route  vesselID    dur_min
0     F-V-S         1  13.623239
1    SEA-BR         2  55.800000
2    ANA-SJ        13  39.357895
3    SEA-BR        13  57.000000
4    SEA-BR        15  54.054348
5    SEA-BR        17  50.438596
6    MUK-CL        18  13.953191
7    MUK-CL        19  14.306513
8    ANA-SJ        20  24.747664
9    SEA-BI        25  30.942675
10    F-V-S        28  14.312950
11  ED-KING        30  22.100629
12   SEA-BI        32  31.000000
13    F-V-S        33  16.161616
14  ED-KING        36  21.821429
15   SEA-BI        37  31.513514
16   ANA-SJ        38  33.721429
17   PT-COU        52  27.481481
18   PD-TAL        65  12.477273
19   PT-COU        66  28.247788
20  ED-KING        68  23.396552
21   ANA-SJ        69  37.064516
byqmnocz

byqmnocz5#

这是对@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))
weylhg0b

weylhg0b6#

类似于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)
niwlg2el

niwlg2el7#

seaborn是一个比matplotlib更高级的库。虽然seaborn没有控制条形图宽度的灵活性,但matplotlib可以通过一行代码来实现:
plt.bar(data.xcol,data.ycol,4)

l0oc07j2

l0oc07j28#

另一个解决方案是修改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

相关问题