pandas/matplotlib:分面条形图

8

我正在制作两个分类变量和一个数字数据的一系列条形图。我已经有如下内容,但我希望像使用ggplot中的facet_wrap一样按一个分类变量进行细分。我有一个部分有效的示例,但我得到了错误的图表类型(线条而不是条形图),而且我在循环中对数据进行了子集划分,这肯定不是最好的方式。

## first try--plain vanilla
import pandas as pd
import numpy as np
N = 100

## generate toy data
ind = np.random.choice(['a','b','c'], N)
cty = np.random.choice(['x','y','z'], N)
jobs = np.random.randint(low=1,high=250,size=N)

## prep data frame
df_city = pd.DataFrame({'industry':ind,'city':cty,'jobs':jobs})
df_city_grouped = df_city.groupby(['city','industry']).jobs.sum().unstack()
df_city_grouped.plot(kind='bar',stacked=True,figsize=(9, 6))

这将会得到类似于这样的结果:
  city industry  jobs
0    z        b   180
1    z        c   121
2    x        a    33
3    z        a   121
4    z        c   236

firstplot

然而,我想看到的是这样的:


(以下内容需要更多上下文信息才能进行准确翻译,请提供更多信息)
## R code
library(plyr)
df_city<-read.csv('/home/aksel/Downloads/mockcity.csv',sep='\t')

## summarize
df_city_grouped <- ddply(df_city, .(city,industry), summarise, jobstot = sum(jobs))

## plot
ggplot(df_city_grouped, aes(x=industry, y=jobstot)) +
  geom_bar(stat='identity') +
  facet_wrap(~city)

输入图像描述

在Matplotlib中最接近的效果大概是这样的:

cols =df_city.city.value_counts().shape[0]
fig, axes = plt.subplots(1, cols, figsize=(8, 8))

for x, city in enumerate(df_city.city.value_counts().index.values):
    data = df_city[(df_city['city'] == city)]
    data = data.groupby(['industry']).jobs.sum()
    axes[x].plot(data)

输入图像描述

因此有两个问题:

  1. 我能使用AxesSubplot对象绘制条形图(它们会像这里显示的那样绘制线条),并最终得到类似于facet_wrap示例的东西吗?
  2. 在生成此类尝试的循环中,我对每个数据进行了子集处理。 我想象不出这是做这种分面的“正确”方式,您认为呢?

你为什么不在循环中使用 bar 呢? - tacaswell
@tcaswell,好建议。绘制条形图的技巧是什么?两个参数似乎都需要是数字。先转换分类变量?有更规范的方式吗? - ako
请查看http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.bar。 - tacaswell
抱歉回答一个旧问题,但我从谷歌搜索中来到了这里。 现在你可以使用seaborn.FacetGrid,查看文档https://seaborn.pydata.org/generated/seaborn.FacetGrid.html或者这个教程https://seaborn.pydata.org/tutorial/axis_grids.html - rhedak
4个回答

4

我想这是可行的,但我真的很喜欢它们在单独的面板中,就像ggplot一样,特别是随着添加更多维度,它非常灵活。当然,这个例子不喜欢数据框变量是非数字的。你有好的方法来解决这个问题吗? - ako
这看起来就像是我想要的开箱即用的东西——而不必在每个循环中对数据进行子集处理。现在唯一需要做的就是理解在图表中绘制分类变量的“正确”方法。 - ako
1
第一个链接已经损坏。 - young_souvlaki

2

@tcasell建议在循环中使用bar调用。这是一个可行的例子,虽然不够优雅。

## second try--facet by county

N = 100
industry = ['a','b','c']
city = ['x','y','z']
ind = np.random.choice(industry, N)
cty = np.random.choice(city, N)
jobs = np.random.randint(low=1,high=250,size=N)
df_city =pd.DataFrame({'industry':ind,'city':cty,'jobs':jobs})

## how many panels do we need?
cols =df_city.city.value_counts().shape[0]
fig, axes = plt.subplots(1, cols, figsize=(8, 8))

for x, city in enumerate(df_city.city.value_counts().index.values):
    data = df_city[(df_city['city'] == city)]
    data = data.groupby(['industry']).jobs.sum()
    print (data)
    print type(data.index)
    left=  [k[0] for k in enumerate(data)]
    right=  [k[1] for k in enumerate(data)]

    axes[x].bar(left,right,label="%s" % (city))
    axes[x].set_xticks(left, minor=False)
    axes[x].set_xticklabels(data.index.values)

    axes[x].legend(loc='best')
    axes[x].grid(True)
    fig.suptitle('Employment By Industry By City', fontsize=20)

enter image description here


2
一个微妙的区别是这里所有三个图都有不同的刻度,这使得跨面板比较困难。 - Mohit Verma
2
这个问题可以很容易地通过在 subplots 函数中添加 sharey 来解决,像这样:plt.subplots(1, cols, figsize=(8, 8), sharey=True) - YeO

1

Seaborn库建立在Matplotlib基础之上,可以被视为其超集,具有灵活且强大的面向图绘制选项--它们甚至使用类似于R的术语。请在此页面向下滚动查看多个示例。


1

我最近发现了plotnine,它在Python中提供了类似于ggplot2的界面。使用plotnine,你可以这样编写代码:

from plotnine import *

# load your data

(ggplot(df_city_grouped, aes(x='industry', y='jobstot'))
 + geom_bar(stat='identity')
 + facet_wrap('~city'))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接