【问题标题】:Change stacked bar plot legend in Python在 Python 中更改堆积条形图图例
【发布时间】:2019-05-01 11:13:12
【问题描述】:

我在 csv 文件中有以下数据:

Date    City    TruckA  TruckB  TruckC  TruckD
Date1   City1   1   0   0   0
Date1   City2   0   0   1   0
Date1   City3   1   0   0   0
Date1   City4   0   0   1   0
Date2   City1   1   0   0   0
Date2   City2   0   1   0   0
Date2   City3   0   0   0   1
Date2   City4   1   0   0   0
Date2   City5   0   1   0   0
Date3   City1   1   0   0   0
Date3   City2   0   0   1   0
Date3   City3   1   0   0   0
Date3   City4   0   0   1   0

我可以使用此代码成功绘制数据:

import pandas as pd

df = pd.read_csv("data.csv")

print(df)

df = df.set_index(["Date","City"])

df.unstack().plot(kind='bar', stacked=True)

我得到以下结果:

如您所见,颜色图例就像每一对 (City,Truck) 都有一个颜色。我希望图例仅依赖于卡车,并且理想情况下在每个城市的条形图上都有标签。

这可能吗?

【问题讨论】:

    标签: python pandas dataframe matplotlib


    【解决方案1】:

    按照@Scott 的出色回答,您可以根据需要获得堆叠的列。

    import matplotlib.pyplot as plt
    cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
    df_out = df.unstack()
    d = dict(zip(df.columns.get_level_values(0),cycle))
    c = df_out.columns.get_level_values(0).map(d)
    g=df_out.plot.bar(stacked=True, color=c, figsize=(10,8), edgecolor='k')
    

    要添加标签,您需要找到正确的位置并迭代地添加标签。
    这是一种方法:

    编辑:只有一个循环

    h=0
    x=0
    unique_dates=df1.index.get_level_values(0).unique() # get the bars
    city=df_out.iloc[x][df_out.iloc[x]!=0].dropna().index.get_level_values(1) #get the cities
    for y,val in enumerate(df1.index.get_level_values(0)): #loop through the dates
        if val==unique_dates[x]: #check the x position
            g.text(x-0.05,1+h-0.5,"%s" % city[h]) 
            h+=1
        else:                                             # move to next x coord, update city labels and add text for the next x coordinate (h=0)
            x+=1
            city=df_out.iloc[x][df_out.iloc[x]!=0].dropna().index.get_level_values(1) #get cities
            g.text(x-0.05,1-0.5,"%s" % city[0])
            h=1      # set h to 1 as we already printed for h=0
    

    原解决方案

    for x ,date in enumerate(df_out.index):
        h=0
        city=df_out.iloc[x][df_out.iloc[x]!=0].dropna().index.get_level_values(1) #get cities
        for y,val in enumerate(df.index.get_level_values(0)):
            if val==date:
                g.text(x,1+h-0.5,"%s" % city[h])
                h+=1
            else:
                continue
    

    【讨论】:

    • 非常感谢,它适用于我提供的数据。我有一个更大的数据集,有 260 行 x 9 列。令人惊讶的是,对于 120 行 x 9 列,它是在几秒钟内完成的,完整的数据集需要 50 分钟。有什么可以提高性能的想法吗?
    • 很好的答案... +1。但是,如果没有两个 for 循环,还有其他方法吗?
    • @ScottBoston @to25。您可以使用unique() 获得 x 位置。类似:unique_dates=df1.index.get_level_values(0).unique()。今天早上我很忙,但我很肯定你可以轻松删除第一个 for 循环。
    • @to25 查看更新后的答案,我认为它会更快。
    • 感谢您的更新。我对文本大小和位置进行了一些更改,现在非常完美!看起来拖慢速度的是斯科特将城市分开的部分。如果有任何解决方案,那就太好了,如果没有,不用担心!
    【解决方案2】:

    编辑

    import matplotlib.pyplot as plt
    cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
    df_out = df.unstack()
    d = dict(zip(df.columns.get_level_values(0),cycle))
    c = df_out.columns.get_level_values(0).map(d)
    df_out.plot.bar(stacked=True, color=c, figsize=(10,8))
    

    输出:

    添加了边缘颜色来区分城市:

    import matplotlib.pyplot as plt
    cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
    df_out = df.unstack()
    d = dict(zip(df.columns.get_level_values(0),cycle))
    c = df_out.columns.get_level_values(0).map(d)
    df_out.plot.bar(stacked=True, color=c, figsize=(10,8), edgecolor='k')
    


    IIUC,我认为您正在寻找这样的东西:

    df = df.set_index(["Date","City"])
    df.sum(level=0).plot.bar(stacked=True, figsize=(10,8))
    

    输出:

    【讨论】:

    • 首先,非常感谢您的回答。这不正是我要找的。我要找的图和我贴的图一样,只是应该只有 4 种不同的颜色,每种卡车类型一种。每个“盒子”代表一个城市。谢谢!
    • @to25 我想这就是你要找的,但是,我认为需要不同的边框颜色来区分不同的城市。
    • 这就是我想要的!有没有可能在每个盒子上添加带有城市名称的标签?
    猜你喜欢
    • 2017-05-27
    • 1970-01-01
    • 2015-07-08
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    相关资源
    最近更新 更多