Seaborn Factorplot在实际图块下方生成额外的空图

时间:2019-03-02 14:50:23

标签: python matplotlib plot visualization seaborn

全部

我正在尝试使用子图函数和Seaborn库绘制两个因子图。我可以使用下面的代码分别绘制两个图。但是,seaborn在实际图下方生成了额外的图(请参见下图)。有没有一种方法可以避免seaborn生成额外的空图?我尝试plt.close来摆脱地块,但不幸的是它只关闭了1个地块 另外,我试图将图例移出情节并在图例旁边显示图例。有没有简单的方法可以做到这一点。我尝试使用legend_out软件包中的seaborn,但是没有用。

我的代码:

f,axes=plt.subplots(1,2,figsize=(8,4))

sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=n, size=4, aspect=2,ax=axes[0])

sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=low_pickups, size=4, aspect=2,ax=axes[1])
plt.close(2)
plt.show()

上述代码的输出:

enter image description here

注意:我是python的新手,请提供您的代码说明。

数据帧的投放

#n dataframe
{'borough': {0: 'Bronx', 1: 'Brooklyn', 2: 'EWR', 3: 'Manhattan', 4: 'Queens', 5: 'Staten Island', 6: 'Unknown'}, 'pickups': {0: 50.66705042597283, 1: 534.4312687082662, 2: 0.02417683628827999, 3: 2387.253281142068, 4: 309.35482385447847, 5: 1.6018880957863229, 6: 2.0571804140650674}}
#low_pickups dataframe
{'borough': {2: 'EWR', 5: 'Staten Island', 6: 'Unknown'}, 'pickups': {2: 0.02417683628827999, 5: 1.6018880957863229, 6: 2.0571804140650674}}

3 个答案:

答案 0 :(得分:6)

请注意,factorplot在最新版本的seaborn中被称为'catplot'

catplotfactorplot是图形级功能。这意味着它们应该在图形级而不是轴级上工作。

您的代码中发生了什么

f,axes=plt.subplots(1,2,figsize=(8,4))
  • 这将创建“图1”。
sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=n, size=4, aspect=2,ax=axes[0])
  • 这会创建“图2”,但您并没有告诉seaborn从Figure 2的{​​{1}}上绘制,所以axes[0]仍然为空。
Figure 1
  • 现在,这又创建了一个图形:Figure 2,在这里,您也告诉seaborn从sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=low_pickups, size=4, aspect=2,ax=axes[1]) Figure 3的轴上绘制。
Figure 1
  • 您将在此处关闭seaborn创建的空axes[1]

因此,现在剩下plt.close(2) 了,您已经将两个轴“注入”到了Figure 2调用中,并且还有由第二次调用创建的仍然为空的Figure 1factorplot,但从不发表任何内容:(。

Figure 3
  • 现在您看到factorplot带有2个轴,而plt.show() 带有空图。

    这是在终端机中运行时的情况,在笔记本中,您可能只看到两个图形一个在另一个图形的下方,另一个图形似乎是带有三个轴的图形。


如何解决此问题:

您有2个选择:

1。快速的方法:

只需在Figure 1之前关闭Figure 3

Figure 3

基本上,您通过提供plt.show()中的“自定义”轴来使f,axes=plt.subplots(1,2,figsize=(8,4)) sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=n, size=4, aspect=2,ax=axes[0]) sns.factorplot(x="borough", y="pickups", hue="borough", kind='bar', data=low_pickups, size=4, aspect=2,ax=axes[1]) plt.close(2) plt.close(3) plt.show() 中创建图形和轴的部分短路。 可能不是factorplot设计的目的,但是,嘿,如果它起作用了,它就起作用了……而且起作用了。

2。正确的一个:

让图形级功能发挥作用并创建自己的图形。您需要做的是指定要作为列的变量。

由于似乎您有2个数据帧,Figure 1factorplot,因此您应该首先从其中创建一个数据帧,其中列n就是{{ 1}}或low_pickups

cat

现在,您可以使用变量n作为列,通过一次调用low_pickups(或您的情况下为# assuming n and low_pickups are a pandas.DataFrame: # first add the 'cat' column for both n['cat'] = 'n' low_pickups['cat'] = 'low_pickups' # now create a new dataframe that is a combination of both comb_df = n.append(low_pickups) )来创建图形:

sns.catplot

注意sns.factorplot是必需的,因为默认情况下它是true,并且您基本上看不到第二个面板中的值,因为它们比第一个面板中的值小得多面板。

版本2,然后给出: enter image description here

您可能仍需要一些样式,但我会留给您;)。

希望这对您有帮助!

答案 1 :(得分:2)

我猜这是因为FactorPlot本身使用子图。

EDIT 2019年3月10日18:43 GMT:从source code for categorical.py中确认:catplot(和factorplot)使用matplotlib子图。 @Jojo的回答完美地解释了正在发生的事情

def catplot(x=None, y=None, hue=None, data=None, row=None, col=None,
            col_wrap=None, estimator=np.mean, ci=95, n_boot=1000,
            units=None, order=None, hue_order=None, row_order=None,
            col_order=None, kind="strip", height=5, aspect=1,
            orient=None, color=None, palette=None,
            legend=True, legend_out=True, sharex=True, sharey=True,
margin_titles=False, facet_kws=None, **kwargs):
    ... # bunch of code
    g = FacetGrid(**facet_kws) # uses subplots

还有axisgrid.py源代码,其中包含FacetGrid定义:

class FacetGrid(Grid):
    def __init(...):
        ... # bunch of code
        # Build the subplot keyword dictionary
        subplot_kws = {} if subplot_kws is None else subplot_kws.copy()
        gridspec_kws = {} if gridspec_kws is None else gridspec_kws.copy()
        # bunch of code
        fig, axes = plt.subplots(nrow, ncol, **kwargs)

是的,您正在创建许多子图,但不知道它,并使用ax=...参数弄乱了它们。 @ Jojo是对的。


还有其他一些选择:

选项1 enter image description here

选项2 enter image description here

请注意,在更高的Seaborn版本中不建议使用factorplot。

import pandas as pd
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt

print(pd.__version__)
print(sns.__version__)
print(matplotlib.__version__)

# n dataframe
n = pd.DataFrame(
    {'borough': {0: 'Bronx', 1: 'Brooklyn', 2: 'EWR', 3: 'Manhattan', 4: 'Queens', 5: 'Staten Island', 6: 'Unknown'},
     'kind': {0: 'n', 1: 'n', 2: 'n', 3: 'n', 4: 'n', 5: 'n', 6: 'n'},
     'pickups': {0: 50.66705042597283, 1: 534.4312687082662, 2: 0.02417683628827999, 3: 2387.253281142068,
                 4: 309.35482385447847, 5: 1.6018880957863229, 6: 2.0571804140650674}})
# low_pickups dataframe
low_pickups = pd.DataFrame({'borough': {2: 'EWR', 5: 'Staten Island', 6: 'Unknown'},
                            'kind': {0: 'low_pickups', 1: 'low_pickups', 2: 'low_pickups', 3: 'low_pickups',
                                     4: 'low_pickups', 5: 'low_pickups', 6: 'low_pickups'},
                            'pickups': {2: 0.02417683628827999, 5: 1.6018880957863229, 6: 2.0571804140650674}})

new_df = n.append(low_pickups).dropna()

print(n)
print('--------------')
print(low_pickups)
print('--------------')
print(new_df)

g = sns.FacetGrid(data=new_df, col="kind", hue='kind', sharey=False)
g.map(sns.barplot, "borough", "pickups", order=sorted(new_df['borough'].unique()))
plt.show()

控制台输出:

0.24.1
0.9.0
3.0.2
         borough kind      pickups
0          Bronx    n    50.667050
1       Brooklyn    n   534.431269
2            EWR    n     0.024177
3      Manhattan    n  2387.253281
4         Queens    n   309.354824
5  Staten Island    n     1.601888
6        Unknown    n     2.057180
--------------
         borough         kind   pickups
0            NaN  low_pickups       NaN
1            NaN  low_pickups       NaN
2            EWR  low_pickups  0.024177
3            NaN  low_pickups       NaN
4            NaN  low_pickups       NaN
5  Staten Island  low_pickups  1.601888
6        Unknown  low_pickups  2.057180
--------------
         borough         kind      pickups
0          Bronx            n    50.667050
1       Brooklyn            n   534.431269
2            EWR            n     0.024177
3      Manhattan            n  2387.253281
4         Queens            n   309.354824
5  Staten Island            n     1.601888
6        Unknown            n     2.057180
2            EWR  low_pickups     0.024177
5  Staten Island  low_pickups     1.601888
6        Unknown  low_pickups     2.057180

或尝试以下操作:

g = sns.barplot(data=new_df, x="kind", y="pickups", hue='borough')#, order=sorted(new_df['borough'].unique()))
g.set_yscale('log')

我不得不使用y对数刻度,因为数据值在很大的范围内相当分散。您可以考虑进行分类(请参阅熊猫的剪裁)

编辑2019年3月10日18:43 GMT:正如@Jojo在他的回答中所述,最后一个选择确实是:

sns.catplot(data=new_df, x="borough", y="pickups", col='kind', hue='borough', sharey=False, kind='bar')

没有时间完成学习,所以一切功劳归功于他!

答案 2 :(得分:0)

我之所以来到这里,是因为我在sns.catplot绘图网格下方的空白绘图中遇到了完全相同的问题。 @jojo的答案很好,并详细解释了所有内容。作为这些东西的新手,除了一点之外,我无法改善它。快速解决方案就是关闭sns.catplot()创建的图形,只需在plt.close(plt.gcf())之后直接调用 sns.catplot() 即可最轻松地实现。这样,您无需考虑要关闭的数字的数字索引。

至少以下内容对我有用,并且可以完全满足我的需求。 5个x3排列的14个不同的Catplot。没有空图,不在网格下方和网格的尽头。

cols = [ "Year Built", "Year Remod/Add", "Bsmt Full Bath", "Bsmt Half Bath",
    "Full Bath", "Half Bath", "Bedroom AbvGr", "Kitchen AbvGr", "TotRms AbvGrd",
    "Fireplaces", "Garage Yr Blt", "Garage Cars", "Mo Sold", "Yr Sold" ] # len 14
fig, axs = plt.subplots(5, 3, figsize = (18, 24))
for i, ax in enumerate(axs.flatten()):
    if i < len(cols):
        sns.catplot(x = cols[i], y = "SalePrice", data = df, ax = ax, kind = "boxen")
        plt.close(plt.gcf()) # close current figure just created by catplot
    else:
        ax.set_axis_off() # hide empty subplot at end of grid