如何创建一个堆叠条形图来指示每天花在鸟巢上的时间

how to create a stacked bar chart indicating time spent on nest per day

我有一些 owl 的数据出现在巢箱中。在上一个问题中,您帮助我想象了 owl 何时出现在框中:

另外,我用下面的代码绘制了每天花在盒子里的小时数(可能这样做效率更高):

import pandas as pd
import matplotlib.pyplot as plt

# raw data indicating time spent in box (each row represents start and end time)
time = pd.DatetimeIndex(["2021-12-01 18:08","2021-12-01 18:11",
                         "2021-12-02 05:27","2021-12-02 05:29",
                         "2021-12-02 22:40","2021-12-02 22:43",
                         "2021-12-03 19:24","2021-12-03 19:27",
                         "2021-12-06 18:04","2021-12-06 18:06",
                         "2021-12-07 05:28","2021-12-07 05:30",
                         "2021-12-10 03:05","2021-12-10 03:10",
                         "2021-12-10 07:11","2021-12-10 07:13",
                         "2021-12-10 20:40","2021-12-10 20:41",
                         "2021-12-12 19:42","2021-12-12 19:45",
                         "2021-12-13 04:13","2021-12-13 04:17",
                         "2021-12-15 04:28","2021-12-15 04:30",
                         "2021-12-15 05:21","2021-12-15 05:25",
                         "2021-12-15 17:40","2021-12-15 17:44",
                         "2021-12-15 22:31","2021-12-15 22:37",
                         "2021-12-16 04:24","2021-12-16 04:28",
                         "2021-12-16 19:58","2021-12-16 20:09",
                         "2021-12-17 17:42","2021-12-17 18:04",
                         "2021-12-17 22:19","2021-12-17 22:26",
                         "2021-12-18 05:41","2021-12-18 05:44",
                         "2021-12-19 07:40","2021-12-19 16:55",
                         "2021-12-19 20:39","2021-12-19 20:52",
                         "2021-12-19 21:56","2021-12-19 23:17",
                         "2021-12-21 04:53","2021-12-21 04:59",
                         "2021-12-21 05:37","2021-12-21 05:39",
                         "2021-12-22 08:06","2021-12-22 17:22",
                         "2021-12-22 20:04","2021-12-22 21:24",
                         "2021-12-22 21:44","2021-12-22 22:47",
                         "2021-12-23 02:20","2021-12-23 06:17",
                         "2021-12-23 08:07","2021-12-23 16:54",
                         "2021-12-23 19:36","2021-12-23 23:59:59",
                         "2021-12-24 00:00","2021-12-24 00:28",
                         "2021-12-24 07:53","2021-12-24 17:00",
                             ])

# create dataframe with column indicating presence (1) or absence (0)
time_df = pd.DataFrame(data={'present':[1,0]*int(len(time)/2)}, index=time)

# calculate interval length and add to time_df
time_df['interval'] = time_df.index.to_series().diff().astype('timedelta64[m]')

# add column with day to time_df
time_df['day'] = time.day

#select only intervals where owl is present 
timeinbox = time_df.iloc[1::2, :]
interval = timeinbox.interval
day = timeinbox.day

# sum multiple intervals per day
interval_tot = [interval[0]]
day_tot = [day[0]]
for i in range(1, len(day)):
    if day[i] == day[i-1]:
        interval_tot[-1] +=interval[i]
    else:
        day_tot.append(day[i])
        interval_tot.append(interval[i])

# recalculate to hours        
for i in range(len(interval_tot)):
    interval_tot[i] = interval_tot[i]/(60)

plt.figure(figsize=(15, 5))       
plt.grid(zorder=0)
plt.bar(day_tot, interval_tot, color='g', zorder=3) 

plt.xlim([1,31])
plt.xlabel('day in December')
plt.ylabel('hours per day in nest box')
plt.xticks(np.arange(1,31,1))
plt.ylim([0, 24])

现在我想通过制作堆叠条形图将所有数据合并到一个图中,其中每一天都由一个条形图表示,每个条形图指示 24*60 分钟中的每一分钟是否 owl是否存在。从当前的数据结构来看这可能吗?

数据似乎是手动创建的,所以我更改了显示数据的格式。我采取的方法是创建花费的时间和未花费的时间,以1分钟为间隔的连续索引,开始和结束时间作为差异时间,标志为1。现在创建非停留时间,我将以 1 分钟为间隔创建开始和结束日期 + 1 的时间序列索引。使用新创建的索引更新原始数据框。这是图表的数据。在图中,根据以天为单位提取的数据框,创建一个颜色列表,其中红色表示住宿,绿色表示非住宿。然后,在条形图中,堆叠高度。可能需要考虑将数据分组为小时单位。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import timedelta
import io

data = '''
start_time,end_time
"2021-12-01 18:08","2021-12-01 18:11"
"2021-12-02 05:27","2021-12-02 05:29"
"2021-12-02 22:40","2021-12-02 22:43"
"2021-12-03 19:24","2021-12-03 19:27"
"2021-12-06 18:04","2021-12-06 18:06"
"2021-12-07 05:28","2021-12-07 05:30"
"2021-12-10 03:05","2021-12-10 03:10"
"2021-12-10 07:11","2021-12-10 07:13"
"2021-12-10 20:40","2021-12-10 20:41"
"2021-12-12 19:42","2021-12-12 19:45"
"2021-12-13 04:13","2021-12-13 04:17"
"2021-12-15 04:28","2021-12-15 04:30"
"2021-12-15 05:21","2021-12-15 05:25"
"2021-12-15 17:40","2021-12-15 17:44"
"2021-12-15 22:31","2021-12-15 22:37"
"2021-12-16 04:24","2021-12-16 04:28"
"2021-12-16 19:58","2021-12-16 20:09"
"2021-12-17 17:42","2021-12-17 18:04"
"2021-12-17 22:19","2021-12-17 22:26"
"2021-12-18 05:41","2021-12-18 05:44"
"2021-12-19 07:40","2021-12-19 16:55"
"2021-12-19 20:39","2021-12-19 20:52"
"2021-12-19 21:56","2021-12-19 23:17"
"2021-12-21 04:53","2021-12-21 04:59"
"2021-12-21 05:37","2021-12-21 05:39"
"2021-12-22 08:06","2021-12-22 17:22"
"2021-12-22 20:04","2021-12-22 21:24"
"2021-12-22 21:44","2021-12-22 22:47"
"2021-12-23 02:20","2021-12-23 06:17"
"2021-12-23 08:07","2021-12-23 16:54"
"2021-12-23 19:36","2021-12-24 00:00"
"2021-12-24 00:00","2021-12-24 00:28"
"2021-12-24 07:53","2021-12-24 17:00"
'''
df = pd.read_csv(io.StringIO(data), sep=',')
df['start_time'] = pd.to_datetime(df['start_time'])
df['end_time'] = pd.to_datetime(df['end_time'])

time_df = pd.DataFrame()
for idx, row in df.iterrows():
    rng = pd.date_range(row['start_time'], row['end_time']-timedelta(minutes=1), freq='1min')
    tmp = pd.DataFrame({'present':[1]*len(rng)}, index=rng)
    time_df = time_df.append(tmp)
date_add = pd.date_range(time_df.index[0].date(), time_df.index[-1].date()+timedelta(days=1), freq='1min')
time_df = time_df.reindex(date_add, fill_value=0)
time_df['day'] = time_df.index.day

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8,15))
ax.set_yticks(np.arange(0,1500,60))
ax.set_ylim(0,1440)
ax.set_xticks(np.arange(1,25,1))

days = time_df['day'].unique()
for d in days:
    #if d == 1:
    day_df = time_df.query('day == @d')
    colors = [ 'r' if p == 1 else 'g' for p in day_df['present']]
    for i in range(len(day_df)): 
        ax.bar(d, height=1, width=0.5, bottom=i+1, color=colors[i])

plt.show()