如何用Python/Plotly绘制x轴为工作日y轴为24小时范围的柱状图
Plotly人员工时可视化实现方案
核心功能实现
- 支持美国4个常用时区切换(MT/PT/CT/ET),自动换算对应工时
- X轴为周一到周日7个工作日,Y轴为24小时时间范围,反转后时段垂直向下展示
- 多人工时重叠展示,透明度设置为0.6区分重叠区域
- 下拉菜单切换时自动刷新全图数据
完整可运行代码
import plotly.graph_objects as go import pandas as pd from datetime import datetime, timedelta # ---------------------- 1. 基础配置与原始数据定义 ---------------------- # 员工列表与对应UTC时区的上班时间、工时长度、工作日期,可按格式补充所有员工 employee_config = [ {"name": "Paige", "utc_start_hour": 13, "work_hours": 8, "work_days": [0,1,2,3,4]}, # 0=周一,6=周日 {"name": "Julissa", "utc_start_hour": 16, "work_hours": 8, "work_days": [0,1,2,3,4]}, {"name": "Jessica", "utc_start_hour": 13, "work_hours": 8, "work_days": [0,1,2,3,4]}, {"name": "David", "utc_start_hour": 14, "work_hours": 8, "work_days": [0,1,2,3,4]}, {"name": "Nicole", "utc_start_hour": 12, "work_hours": 8, "work_days": [0,1,2,3,4]} ] week_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] # 美国时区定义:时区名与UTC偏移小时 timezone_config = { "ET": -5, "CT": -6, "MT": -7, "PT": -8 } # ---------------------- 2. 数据转换函数 ---------------------- def generate_tz_data(tz_offset): df_list = [] for emp in employee_config: for day_idx in emp["work_days"]: # 换算对应时区的开始时间,跨天自动取模 tz_start_hour = (emp["utc_start_hour"] + tz_offset) % 24 df_list.append({ "dow": week_days[day_idx], "employee": emp["name"], "start": tz_start_hour, "duration": emp["work_hours"] }) return pd.DataFrame(df_list) # ---------------------- 3. 初始化绘图 ---------------------- # 默认加载MT时区数据 initial_tz = "MT" initial_offset = timezone_config[initial_tz] df = generate_tz_data(initial_offset) fig = go.Figure() # 批量添加员工trace for emp in df["employee"].unique(): emp_df = df[df["employee"] == emp] fig.add_trace(go.Bar( x=emp_df["dow"], y=emp_df["duration"], base=emp_df["start"], name=emp, opacity=0.6, width=0.8 )) # ---------------------- 4. 配置下拉菜单 ---------------------- buttons = [] for tz_name, tz_offset in timezone_config.items(): tz_df = generate_tz_data(tz_offset) # 构造每个按钮的更新参数 x_list = [] y_list = [] base_list = [] for emp in df["employee"].unique(): emp_df = tz_df[tz_df["employee"] == emp] x_list.append(emp_df["dow"]) y_list.append(emp_df["duration"]) base_list.append(emp_df["start"]) buttons.append(dict( label=tz_name, method="update", args=[ {"x": x_list, "y": y_list, "base": base_list}, {"title": f"CSI工作小时({tz_name}时区)"} ] )) fig.update_layout( updatemenus=[dict( active=list(timezone_config.keys()).index(initial_tz), buttons=buttons, x=0.1, y=1.15 )], title=f"CSI工作小时({initial_tz}时区)", xaxis={"title": "工作日", "categoryorder": "array", "categoryarray": week_days}, yaxis={ "title": "时间", "range": [24, 0], # 反转Y轴,0点在顶部 "tickmode": "linear", "dtick": 1, "ticktext": [f"{h}:00" for h in range(24)], "tickvals": list(range(24)) }, barmode="overlay", # 重叠展示 legend={"title": "员工"} ) fig.show()
关键调整说明
- 原始数据统一用UTC时间存储,切换时区时仅做小时偏移换算,无需维护多份数据,支持跨天工时自动适配
- 取消原代码的
barmode=group,改为barmode=overlay配合透明度参数,实现同个工作日多人工时重叠展示 - Y轴固定为0-23的小时刻度,反转后天然符合时段垂直向下展示的需求
- 下拉菜单切换时直接更新所有trace的x、y、base参数,无需重建图表,响应速度更快
内容的提问来源于stack exchange,提问作者Tiffa
相关产品推荐
相关产品推荐

