【问题标题】:Styling of Pandas groupby boxplotsPandas groupby箱线图的样式
【发布时间】:2013-10-27 13:16:17
【问题描述】:

Python 中的普通 matplotlib boxplot 命令返回一个字典,其中包含框、中值、胡须、传单和大写的键。这让造型变得非常容易。

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Create a dataframe and subset it for a boxplot
df1 = pd.DataFrame(rand(10), columns=['Col1'] )
df1['X'] = pd.Series(['A','B','A','B','A','B','A','B','A','B'])
boxes= [df1[df1['X'] == 'A'].Col1, df1[df1['X'] == 'B'].Col1]

# Call the standard matplotlib boxplot function,
# which returns a dictionary including the parts of the graph
mbp = plt.boxplot(boxes)
print(type(mbp))

# This dictionary output makes styling the boxplot easy
plt.setp(mbp['boxes'], color='blue')
plt.setp(mbp['medians'], color='red')
plt.setp(mbp['whiskers'], color='blue')
plt.setp(mbp['fliers'], color='blue')

Pandas 库为其分组(分层索引)数据帧提供了“优化”箱线图功能。然而,它不是为每个组返回几个字典,而是返回一个 matplotlib.axes.AxesSubplot 对象。这使得造型非常困难。

# Pandas has a built-in boxplot function that returns
# a matplotlib.axes.AxesSubplot object
pbp = df1.boxplot(by='X')
print(type(pbp))

# Similar attempts at styling obviously return TypeErrors
plt.setp(pbp['boxes'], color='blue')
plt.setp(pbp['medians'], color='red')
plt.setp(pbp['whiskers'], color='blue')
plt.setp(pbp['fliers'], color='blue')

pandas df.boxplot(by='X') 函数生成的这个 AxisSubplot 对象是否可访问?

【问题讨论】:

  • 你能给我们看一些示例代码(带有假数据吗?)
  • 我已编辑问题以包含示例数据和代码,并更清楚地展示我的问题。

标签: python matplotlib pandas


【解决方案1】:

您还可以将return_type 指定为dict。这将直接在字典中返回箱线图属性,该字典由箱线图中绘制的每一列索引。

使用上面的例子(在 IPython 中):

from pandas import *
import matplotlib
from numpy.random import rand
import matplotlib.pyplot as plt
df = DataFrame(rand(10,2), columns=['Col1', 'Col2'] )
df['X'] = Series(['A','A','A','A','A','B','B','B','B','B'])
bp = df.boxplot( by='X', return_type='dict' )

>>> bp.keys()
['Col1', 'Col2']

>>> bp['Col1'].keys()
['boxes', 'fliers', 'medians', 'means', 'whiskers', 'caps']

现在,改变线宽是列表理解的问题:

>>> [ [item.set_linewidth( 2 ) for item in bp[key]['medians']] for key in bp.keys() ]
[[None, None], [None, None]]

【讨论】:

    【解决方案2】:

    恐怕你必须硬编码。以pandas 为例:http://pandas.pydata.org/pandas-docs/stable/visualization.html#box-plotting

    from pandas import *
    import matplotlib
    from numpy.random import rand
    import matplotlib.pyplot as plt
    df = DataFrame(rand(10,2), columns=['Col1', 'Col2'] )
    df['X'] = Series(['A','A','A','A','A','B','B','B','B','B'])
    bp = df.boxplot(by='X')
    cl=bp[0].get_children()
    cl=[item for item in cl if isinstance(item, matplotlib.lines.Line2D)]
    

    现在让我们确定哪个是盒子、中位数等:

    for i, item in enumerate(cl):
        if item.get_xdata().mean()>0:
            bp[0].text(item.get_xdata().mean(), item.get_ydata().mean(), str(i), va='center', ha='center')
    

    情节是这样的:

    每个栏包含 8 个项目。例如,第 5 项是中位数。第 7 项和第 8 项可能是传单,我们这里没有。

    知道了这些,修改部分吧就很容易了。如果我们想将中位数设为linewidth 为 2:

    for i in range(_your_number_of_classes_2_in_this_case):
        cl[5+i*8].set_linewidth(2.)
    

    【讨论】:

    • 太棒了!非常有帮助@ct-zhu。我采用了您的解决方案并创建了一个函数,该函数采用 pandas 数据框和您想要分组的列并返回一个用于格式化的字典。我会把它放在他的答案下面,但它不适合。这是link to a gist on github
    猜你喜欢
    • 2015-07-04
    • 2014-08-11
    • 2017-11-24
    • 2021-06-26
    • 2021-06-14
    • 1970-01-01
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多