在Python的Dash/Plotly中实现多个子弹图分两行展示的问题问询
基于Dash栅格系统实现多组子弹图+图标布局
你不需要将所有子弹图都放在同一个Plotly Figure中调整domain参数,直接使用Dash的栅格布局系统拆分页面区域即可,既能轻松实现每行多组子弹图+独立图标的效果,后续添加下拉菜单等交互组件也更灵活。
完整实现代码如下:
import dash from dash import dcc, html, Input, Output import plotly.graph_objects as go import dash_bootstrap_components as dbc # 封装单个子弹图生成函数,减少重复代码 def create_bullet_fig(title, value, ref): fig = go.Figure(go.Indicator( mode = "number+gauge+delta", value = value, delta = {'reference': ref}, domain = {'x': [0, 1], 'y': [0, 1]}, title = {'text': title}, gauge = {'shape': "bullet"} )) fig.update_layout(height=120, margin={'t':10, 'b':10, 'l':10, 'r':10}) return fig # 初始化Dash应用,加载bootstrap样式方便做栅格布局 app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) # 应用布局 app.layout = dbc.Container([ # 顶部下拉菜单预留位,可直接配置选项和回调 html.Div([ dcc.Dropdown( options=[ {'label': '数据维度1', 'value': 'dim1'}, {'label': '数据维度2', 'value': 'dim2'} ], value='dim1', style={'width': '300px', 'margin': '20px 0'} ) ]), # 第一行内容,共2组子弹图+图标 dbc.Row([ # 第一组 dbc.Col([ # 左侧图标,修改src为你的本地图标路径或base64编码即可 html.Img(src='', style={'height': '80px', 'margin-right': '15px', 'display': 'inline-block', 'vertical-align': 'top'}), # 右侧3个子弹图 html.Div([ dcc.Graph(figure=create_bullet_fig("SV 1", 220, 200), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 2", 35, 200), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 3", 180, 200), config={'displayModeBar': False}), ], style={'display': 'inline-block', 'width': 'calc(100% - 100px)'}) ], width=6, style={'margin-bottom': '20px'}), # 第二组 dbc.Col([ html.Img(src='', style={'height': '80px', 'margin-right': '15px', 'display': 'inline-block', 'vertical-align': 'top'}), html.Div([ dcc.Graph(figure=create_bullet_fig("SV 4", 150, 180), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 5", 240, 200), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 6", 90, 100), config={'displayModeBar': False}), ], style={'display': 'inline-block', 'width': 'calc(100% - 100px)'}) ], width=6, style={'margin-bottom': '20px'}) ]), # 第二行内容,可按需扩展更多行 dbc.Row([ dbc.Col([ html.Img(src='', style={'height': '80px', 'margin-right': '15px', 'display': 'inline-block', 'vertical-align': 'top'}), html.Div([ dcc.Graph(figure=create_bullet_fig("SV 7", 120, 150), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 8", 190, 170), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 9", 70, 80), config={'displayModeBar': False}), ], style={'display': 'inline-block', 'width': 'calc(100% - 100px)'}) ], width=6, style={'margin-bottom': '20px'}), dbc.Col([ html.Img(src='', style={'height': '80px', 'margin-right': '15px', 'display': 'inline-block', 'vertical-align': 'top'}), html.Div([ dcc.Graph(figure=create_bullet_fig("SV 10", 300, 250), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 11", 110, 90), config={'displayModeBar': False}), dcc.Graph(figure=create_bullet_fig("SV 12", 40, 50), config={'displayModeBar': False}), ], style={'display': 'inline-block', 'width': 'calc(100% - 100px)'}) ], width=6, style={'margin-bottom': '20px'}) ]) ], fluid=True) if __name__ == '__main__': app.run_server(debug=True, use_reloader=True)
该方案的优势:
- 无需调整单个Figure内部的domain参数,所有布局调整都通过外层的Dash组件参数实现,门槛更低
- 每个组件独立,后续要给下拉菜单、图表加交互回调时逻辑更清晰,扩展成本低
- 自带响应式适配能力,可自动适配不同屏幕尺寸
内容的提问来源于stack exchange,提问作者alphanumEric
相关产品推荐
相关产品推荐

