如何在单个HTML中高效堆叠px.timeline图表并实现子图颜色独立
高效实现多子图独立配色的甘特图并导出小体积HTML
核心思路
不用单独生成每个图表再拼接,而是在同一个Plotly Figure中手动构建子图布局,为每个子图的trace独立分配配色。既满足子图内颜色唯一、子图间可重复的需求,又能保证导出的HTML体积紧凑,避免冗余开销。
具体步骤
- 用
plotly.subplots.make_subplots创建统一的子图框架,开启共享x轴减少重复元素 - 定义一个小型配色集合,每个子图内循环使用该集合,确保子图内任务颜色唯一
- 遍历每个分组,生成单组甘特图后提取trace,设置对应颜色再添加到子图中
- 统一调整布局,去掉不必要的元素(如全局图例)进一步压缩体积
代码示例
import pandas as pd import plotly.express as px import plotly.subplots as sp from plotly.colors import qualitative # 模拟60个分组、每组5个任务的甘特图数据 df = pd.DataFrame({ 'group': [f'Group {i}' for i in range(60) for _ in range(5)], 'task': [f'Task {j}' for i in range(60) for j in range(5)], 'start': pd.date_range('2024-01-01', periods=300, freq='D'), 'end': pd.date_range('2024-01-03', periods=300, freq='D') }) # 选用10种颜色的配色集,足够每组任务唯一区分 color_palette = qualitative.Plotly # 创建60行1列的子图布局,共享x轴减小文件体积 fig = sp.make_subplots( rows=60, cols=1, shared_xaxes=True, vertical_spacing=0.005, # 缩小子图间距,节省显示空间 subplot_titles=[f'Group {i}' for i in range(60)] ) # 遍历每个分组生成子图 for row_idx, group_name in enumerate(df['group'].unique(), 1): group_data = df[df['group'] == group_name] # 为当前分组的任务分配颜色 task_color_map = { task: color_palette[i % len(color_palette)] for i, task in enumerate(group_data['task'].unique()) } # 生成单组甘特图 sub_fig = px.timeline( group_data, x_start='start', x_end='end', y='task', color='task' ) # 调整每个trace的颜色并添加到对应子图 for trace in sub_fig.data: trace.marker.color = task_color_map[trace.name] fig.add_trace(trace, row=row_idx, col=1) # 隐藏子图y轴标题,简化布局 fig.update_yaxes(title_text='', row=row_idx, col=1) # 全局布局优化 fig.update_layout( height=60*80, # 每个子图分配80px高度,适配60组内容 showlegend=False, # 不需要全局图例,进一步减小文件体积 title_text='分组甘特图' ) # 导出HTML,体积与facet_row方式接近 fig.write_html('grouped_gantt.html')
为什么这个方法高效
- 所有子图的trace都整合在同一个Figure对象中,导出时不会重复包含Plotly的核心JS库和冗余结构,文件体积保持在4MB左右
- 共享x轴、隐藏全局图例等操作进一步减少了HTML中的冗余元素
- 配色循环使用,避免了全局配色集过大导致的颜色区分困难问题
内容的提问来源于stack exchange,提问作者Aisec Nory
相关产品推荐
相关产品推荐

