与matplotlib堆积的条形图

问题描述 投票:2回答:1

我有一个从WhatsApp中提取的数据帧,其中包含以下列:日期和时间,消息,名称,msg_len。 Date&Time是一个DateTime对象,表示消息发送的时间,msg是实际消息,name是发送消息的人,msg_len是消息的实际长度。我正在尝试使用此数据框构建堆积条形图:在X轴上日期(例如2019-02),y轴,平均长度或当月发送的消息数量和每个条形码是除以每个人。到目前为止我的功能看起来像这样:

def BarPlotMonth(Data):
    """
    This function plots a barplot for the number of messages sent for each month and the mean length of the messages for each month
    """

    fig,axes = plt.subplots(2,1,
            figsize=(18,10),
            sharex = True)


    GroupedByMonth = Data.groupby(Data['Date&Time'].dt.strftime('%Y-%m'))['msg_len']

    Mean = GroupedByMonth.mean()
    Count = GroupedByMonth.count()
    Std = GroupedByMonth.std()

    axes[0].bar(Count.index, Count, color = 'lightblue')
    axes[0].set_title('Number of text per month')
    axes[0].set_ylabel('Count')

    axes[1].bar(Mean.index, Mean, color = 'lightblue', yerr = Std)
    axes[1].set_title('Mean lenght of a message per month')
    axes[1].set_ylabel('Mean lenght')
    axes[1].set_xlabel('Year-Month')

    plt.xticks(rotation=45)
    axes[1].legend()

    plt.savefig('WhatsApp_conversations.png')
    plt.show()

但我不能划分每个栏。我怎么解决这个问题?

python-3.x matplotlib pandas-groupby
1个回答
1
投票

你需要重新调整你的DataFrame,以便能够使用df.plot(kind='bar', stacked=True)

group_by_month_per_user = df.groupby(
    [
        df['Date&Time'].dt.strftime('%Y-%m'),
        'name'
    ]   
).mean().unstack()

group_by_month_per_user

这将生成具有以下结构的表。

             msg_len                                 
name           alice        bob   giuseppe     martin
Date&Time                                            
2019-01    48.870968  42.315789  56.391304  49.586207
2019-02    51.099174  48.777778  56.173913  51.895652
2019-03    52.336364  49.626168  47.021898  46.626263

请注意,列是一个多索引,所有列都有msg_len,我们需要删除它以使图例保持整洁(可以简单地选择整个列)。然后得到的DataFrame可以传递给.plot

group_by_month_per_user['msg_len'].plot(kind='bar', stacked=True, legend=['name'])

这产生了以下图表。

output showing stacked bar for SMS length

以下代码用于生成随机数据集。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
from random import randint, choice
import string

ts = datetime.now()
data = []
names = ['bob', 'alice', 'martin', 'giuseppe']

for n in range(1000):
    msg_len = randint(0, 100)
    row = [
        ts - timedelta(days=randint(-30,30)),
        ''.join(random.choice(string.ascii_lowercase) for _ in range(msg_len)),
        choice(names),
        msg_len
    ]

    data.append(row)

df = pd.DataFrame(data, columns = ['Date&Time', 'msg', 'name', 'msg_len'])
© www.soinside.com 2019 - 2024. All rights reserved.