pandas 使用 python 和 matplotlib 的时间线条形图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51505291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 05:50:23  来源:igfitidea点击:

Timeline bar graph using python and matplotlib

python-2.7pandasnumpymatplotlib

提问by mrb28830

I am looking to draw a timeline bar graph using matplotlibthat will show the things a person did in one day. I am adding the code below,output and an expected output that i am looking for. Any library can be used, in my case the closet i could get to was using matplotlib. Any help would be greatly appreciated.

我正在寻找使用matplotlib绘制时间线条形图,该条形图将显示一个人一天所做的事情。我正在添加下面的代码、输出和我正在寻找的预期输出。可以使用任何库,在我的情况下,我可以使用的壁橱使用matplotlib。任何帮助将不胜感激。

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

data = [    (dt.datetime(2018, 7, 17, 0, 15), dt.datetime(2018, 7, 17, 0, 30), 'sleep'),
            (dt.datetime(2018, 7, 17, 0, 30), dt.datetime(2018, 7, 17, 0, 45), 'eat'),
            (dt.datetime(2018, 7, 17, 0, 45), dt.datetime(2018, 7, 17, 1, 0), 'work'),
            (dt.datetime(2018, 7, 17, 1, 0), dt.datetime(2018, 7, 17, 1, 30), 'sleep'),
            (dt.datetime(2018, 7, 17, 1, 15), dt.datetime(2018, 7, 17, 1, 30), 'eat'), 
            (dt.datetime(2018, 7, 17, 1, 30), dt.datetime(2018, 7, 17, 1, 45), 'work')
        ]

rng=[]
for i in range(len(data)):
    rng.append((data[i][0]).strftime('%H:%M'))

index={}
activity = []
for i in range(len(data)):
    index[(data[i][2])]=[]
    activity.append(data[i][2])

for i in range(len(index)):
    for j in range(len(activity)):
        if activity[j]==index.keys()[i]:
            index[index.keys()[i]].append(15)
        else:
            index[index.keys()[i]].append(0)            

data = list(index.values())
df = pd.DataFrame(data,index=list(index.keys()))
df.plot.barh(stacked=True, sharex=False)
plt.show()

My Output:

我的输出

Using matplotlib this is what i was getting

使用 matplotlib 这就是我得到的

Using matplotlib this is what i was getting

使用 matplotlib 这就是我得到的

Expected Output:

预期输出

I got this using google charts Timeline graph but I need this using python and the data used for generating both graphs is not exactly the same, I hope you get the point I got this using google charts Timeline graph but I need this using python and the data used for generating both graphs is not exactly the same, I hope you get the point

我使用谷歌图表时间线图得到了这个,但我需要使用 python 并且用于生成两个图的数据并不完全相同,我希望你明白这一点 我使用谷歌图表时间线图得到了这个,但我需要使用 python 并且用于生成两个图的数据并不完全相同,我希望你明白这一点

回答by ImportanceOfBeingErnest

You may create a PolyCollectionof "bars". For this you would need to convert your dates to numbers (matplotlib.dates.date2num).

您可以创建一个PolyCollection“条”。为此,您需要将日期转换为数字 ( matplotlib.dates.date2num)。

import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.collections import PolyCollection

data = [    (dt.datetime(2018, 7, 17, 0, 15), dt.datetime(2018, 7, 17, 0, 30), 'sleep'),
            (dt.datetime(2018, 7, 17, 0, 30), dt.datetime(2018, 7, 17, 0, 45), 'eat'),
            (dt.datetime(2018, 7, 17, 0, 45), dt.datetime(2018, 7, 17, 1, 0), 'work'),
            (dt.datetime(2018, 7, 17, 1, 0), dt.datetime(2018, 7, 17, 1, 30), 'sleep'),
            (dt.datetime(2018, 7, 17, 1, 15), dt.datetime(2018, 7, 17, 1, 30), 'eat'), 
            (dt.datetime(2018, 7, 17, 1, 30), dt.datetime(2018, 7, 17, 1, 45), 'work')
        ]

cats = {"sleep" : 1, "eat" : 2, "work" : 3}
colormapping = {"sleep" : "C0", "eat" : "C1", "work" : "C2"}

verts = []
colors = []
for d in data:
    v =  [(mdates.date2num(d[0]), cats[d[2]]-.4),
          (mdates.date2num(d[0]), cats[d[2]]+.4),
          (mdates.date2num(d[1]), cats[d[2]]+.4),
          (mdates.date2num(d[1]), cats[d[2]]-.4),
          (mdates.date2num(d[0]), cats[d[2]]-.4)]
    verts.append(v)
    colors.append(colormapping[d[2]])

bars = PolyCollection(verts, facecolors=colors)

fig, ax = plt.subplots()
ax.add_collection(bars)
ax.autoscale()
loc = mdates.MinuteLocator(byminute=[0,15,30,45])
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))

ax.set_yticks([1,2,3])
ax.set_yticklabels(["sleep", "eat", "work"])
plt.show()

enter image description here

在此处输入图片说明

Note that such plots can equally be generated with a Broken Bar plot (broken_barh), however, the (unsorted) data used here, make it a bit easier using a PolyCollection.

请注意,此类图同样可以使用断条图 ( broken_barh) 生成,但是,此处使用的(未排序的)数据使使用 PolyCollection 更容易一些。

And now you would need to explain to me how you can sleep and eat at the same time - something I can never quite get at, as hard as I try.

现在你需要向我解释你如何可以同时睡觉和吃饭——这是我永远无法理解的,尽管我尽力了。

回答by GuillaumeS

My solution using Altair (example):

我使用 Altair 的解决方案(示例):

import altair as alt
import datetime as dt
import pandas as pd


alt.renderers.enable('jupyterlab')

data = pd.DataFrame()
data['from'] = [dt.datetime(2018, 7, 17, 0, 15),
             dt.datetime(2018, 7, 17, 0, 30),
             dt.datetime(2018, 7, 17, 0, 45), 
             dt.datetime(2018, 7, 17, 1, 0), 
             dt.datetime(2018, 7, 17, 1, 15), 
             dt.datetime(2018, 7, 17, 1, 30)]
data['to'] = [dt.datetime(2018, 7, 17, 0, 30),
             dt.datetime(2018, 7, 17, 0, 45),
             dt.datetime(2018, 7, 17, 1, 0), 
             dt.datetime(2018, 7, 17, 1, 15), 
             dt.datetime(2018, 7, 17, 1, 30), 
             dt.datetime(2018, 7, 17, 1, 45)]
data['activity'] = ['sleep','eat','work','sleep','eat','work']
#data

alt.Chart(data).mark_bar().encode(
    x='from',
    x2='to',
    y='activity',
    color=alt.Color('activity', scale=alt.Scale(scheme='dark2'))
)

Output:

输出:

Altair_render

Altair_render