如何减小Plotly绘制的两个图表之间的间距?
Plotly双图紧凑对齐排布实现方法
要解决两个独立Plotly图表间距过大、X轴不对齐的问题,可根据使用场景选择对应方案实现,不需要反复调整无效边距参数。
核心实现思路
- 纯Plotly本地渲染场景:使用内置子图接口创建统一布局,直接控制子图间距、强制X轴共享
- Dash应用部署场景:不改动原有绘图逻辑,通过调整组件样式+图表边距+统一X轴范围快速实现效果
方案1:纯Plotly单图实现(子图合并)
直接将甘特图、分面折线图合并到同一个figure对象中,从布局层面消除间距、保证对齐。
完整可运行代码
import plotly.express as px import plotly.graph_objects as go from plotly.subplots import make_subplots import pandas as pd # 甘特图数据集 df_fddevents = pd.DataFrame([ dict(Event="On", EventStartTime='2022-01-01 08:00:00', EventEndTime='2022-01-01 16:45:00', Point="Switch1", width=0.5), dict(Event="Off", EventStartTime='2022-01-01 16:45:00', EventEndTime='2022-01-02 08:00:00', Point="Switch1", width=0.3), dict(Event="On", EventStartTime='2022-01-02 08:00:00', EventEndTime='2022-01-02 16:45:00', Point="Switch1", width=0.5), dict(Event="On", EventStartTime='2022-01-01 08:00:00', EventEndTime='2022-01-01 10:00:00', Point="Switch2", width=0.3), dict(Event="Off", EventStartTime='2022-01-01 10:00:00', EventEndTime='2022-01-01 13:45:00', Point="Switch2", width=0.5), dict(Event="On", EventStartTime='2022-01-02 08:00:00', EventEndTime='2022-01-02 16:00:00', Point="Switch2", width=0.3) ]) # 折线图数据集 df2 = pd.DataFrame([ dict(DateTime='2022-01-01 00:00:00', Value=90, Point="A", Unit='%', DataType='Normal'), dict(DateTime='2022-01-01 00:15:00', Value=80, Point="A", Unit='%', DataType='Normal'), dict(DateTime='2022-01-01 00:30:00', Value=85, Point="A", Unit='%', DataType='Normal'), dict(DateTime='2022-01-01 00:45:00', Value=92, Point="A", Unit='%', DataType='Normal'), dict(DateTime='2022-01-01 01:00:00', Value=100, Point="A", Unit='%', DataType='Fault'), dict(DateTime='2022-01-01 01:15:00', Value=72, Point="A", Unit='%', DataType='Fault'), dict(DateTime='2022-01-01 00:00:00', Value=22, Point="B", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:15:00', Value=22, Point="B", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:30:00', Value=23, Point="B", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:45:00', Value=20, Point="B", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 01:00:00', Value=21, Point="B", Unit='°C', DataType='Fault'), dict(DateTime='2022-01-01 01:15:00', Value=23, Point="B", Unit='°C', DataType='Fault'), dict(DateTime='2022-01-01 00:00:00', Value=24, Point="C", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:15:00', Value=24, Point="C", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:30:00', Value=24, Point="C", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 00:45:00', Value=24, Point="C", Unit='°C', DataType='Normal'), dict(DateTime='2022-01-01 01:00:00', Value=24, Point="C", Unit='°C', DataType='Fault'), dict(DateTime='2022-01-01 01:15:00', Value=24, Point="C", Unit='°C', DataType='Fault'), dict(DateTime='2022-01-01 00:00:00', Value=60, Point="D", Unit='Pa', DataType='Normal'), dict(DateTime='2022-01-01 00:15:00', Value=58, Point="D", Unit='Pa', DataType='Normal'), dict(DateTime='2022-01-01 00:30:00', Value=62, Point="D", Unit='Pa', DataType='Normal'), dict(DateTime='2022-01-01 00:45:00', Value=61, Point="D", Unit='Pa', DataType='Normal'), dict(DateTime='2022-01-01 01:00:00', Value=64, Point="D", Unit='Pa', DataType='Fault'), dict(DateTime='2022-01-01 01:15:00', Value=59, Point="D", Unit='Pa', DataType='Fault'), dict(DateTime='2022-01-01 00:00:00', Value=0, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 00:15:00', Value=0, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 00:30:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 00:45:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 01:00:00', Value=1, Point="E", Unit='Binary', DataType='Fault'), dict(DateTime='2022-01-01 01:15:00', Value=1, Point="E", Unit='Binary', DataType='Fault'), dict(DateTime='2022-01-01 01:30:00', Value=0, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 01:45:00', Value=0, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 02:00:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 02:15:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 02:30:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), dict(DateTime='2022-01-01 02:45:00', Value=1, Point="E", Unit='Binary', DataType='Normal'), ]) # 创建子图:共5行(1行甘特图+4行折线分面),共享X轴,设置极小垂直间距 fig = make_subplots( rows=5, cols=1, shared_xaxes=True, vertical_spacing=0.02, row_heights=[0.18, 0.205, 0.205, 0.205, 0.205] ) # 生成甘特图并添加到第一行 fig_gantt = px.timeline(df_fddevents, x_start="EventStartTime", x_end="EventEndTime", y="Event", color="Point") fig_gantt.update_yaxes(autorange="reversed") for i, d in enumerate(fig_gantt.data): d.width = df_fddevents[df_fddevents['Point']==d.name]['width'] for trace in fig_gantt.data: fig.add_trace(trace, row=1, col=1) # 生成分面折线图,按分面顺序添加到2-5行 figline = px.line(df2, x="DateTime", y="Value", color="Point", line_group="Unit", hover_name="Point", facet_row="Unit", line_shape="spline", render_mode="svg") for idx, trace in enumerate(figline.data): fig.add_trace(trace, row=idx//len(df2['Point'].unique())+2, col=1) # 统一配置坐标轴、布局 fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='red') fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='red', autorange=True) fig.update_yaxes(autorange="reversed", row=1, col=1) fig.update_layout( hovermode="x unified", height=900, margin=dict(t=30, b=30, l=60, r=20), showlegend=False ) fig.show()
关键参数说明
vertical_spacing:取值范围01,设置为0.020.05即可实现两图无大段空白的紧凑效果shared_xaxes=True:强制所有子图共用同一X轴刻度、范围,实现完全对齐margin:调整画布整体外边距,消除边缘多余空白row_heights:按比例分配每行高度,适配甘特图内容少、折线分面多的高度需求
方案2:Dash应用快速适配(无需重构原有代码)
如果是在Dash项目中部署,不需要合并两个figure,直接调整样式即可实现效果:
- 给两个
dcc.Graph组件设置样式,去掉上下外边距 - 给两个图表设置完全一致的X轴范围、左右边距,保证X轴对齐
- 把甘特图的下边距、折线图的上边距设为0,消除两图之间的空白
核心布局代码
import dash import dash_core_components as dcc import dash_html_components as html app = dash.Dash(__name__) # 此处保留原有的fig_gantt、figline生成逻辑不变 app.layout = html.Div([ dcc.Graph( id='gantt-chart', figure=fig_gantt.update_layout( margin=dict(t=20, b=0, l=60, r=20), xaxis_range=['2022-01-01 00:00:00', '2022-01-02 20:00:00'] ), style={'margin-bottom': '0 !important'} ), dcc.Graph( id='line-chart', figure=figline.update_layout( margin=dict(t=0, b=20, l=60, r=20), xaxis_range=['2022-01-01 00:00:00', '2022-01-02 20:00:00'] ), style={'margin-top': '0 !important'} ) ]) if __name__ == '__main__': app.run_server(debug=True)
两种方案都可以实现两图紧凑排布、X轴完全对齐的效果,同时保留原有的hover联动、颜色配置等功能。
内容的提问来源于stack exchange,提问作者Sartaj0111
相关产品推荐
相关产品推荐

