You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python的Dash中为单个子图饼图命名?

嘿,这个场景我之前在做Dash仪表盘时刚好遇到过,给你两个实用的解决方案,看哪个更适合你:

方案1:单个Graph内自动生成饼图标题(不用手动硬编码坐标)

你完全不用手动去写每个annotations的坐标,可以通过动态计算饼图的位置来自动生成标题。因为多个饼图在单个Graph里是用domain参数划分画布的,我们可以基于每个饼图的domain范围,算出它的中心位置,然后把标题精准放在对应位置。

举个例子,假设你要放20个饼图,排成4行5列,代码可以这么写:

import dash
from dash import dcc, html
import plotly.graph_objects as go

app = dash.Dash(__name__)

# 模拟20组饼图数据
pie_data = [
    {"labels": ["A", "B", "C"], "values": [30, 40, 30], "title": f"饼图{i+1}"}
    for i in range(20)
]

fig = go.Figure()
annotations = []

# 设置网格布局:4行5列
rows = 4
cols = 5

for idx, data in enumerate(pie_data):
    # 计算当前饼图在画布中的domain范围
    row_idx = idx // cols
    col_idx = idx % cols
    x_start = col_idx / cols
    x_end = (col_idx + 1) / cols
    y_start = 1 - (row_idx + 1)/rows
    y_end = 1 - row_idx/rows

    # 添加饼图trace
    fig.add_trace(go.Pie(
        labels=data["labels"],
        values=data["values"],
        domain=dict(x=[x_start, x_end], y=[y_start, y_end]),
        showlegend=False  # 不需要图例可以关掉,节省空间
    ))

    # 自动计算标题的位置(放在饼图上方居中)
    title_x = (x_start + x_end) / 2
    title_y = y_end + 0.02  # 稍微向上偏移一点,避免和饼图重叠
    annotations.append({
        "x": title_x,
        "y": title_y,
        "text": data["title"],
        "xref": "paper",
        "yref": "paper",
        "showarrow": False,
        "font": {"size": 12, "weight": "bold"}
    })

fig.update_layout(annotations=annotations, height=800, width=1200)

app.layout = html.Div([dcc.Graph(figure=fig)])

if __name__ == "__main__":
    app.run_server(debug=True)

这个方法的好处是不管你要放多少个饼图,只要调整rows和cols参数,标题都会自动对齐,完全不用手动调坐标。

方案2:使用20个独立的Graph组件(完全可行!)

如果觉得单个Graph里搞annotations太繁琐,直接用20个独立的dcc.Graph绝对是更省心的选择,Dash对这种场景支持得非常好。

这种方式的优势很明显:

  • 每个饼图的标题直接用figure.layout.title设置,不用折腾复杂的annotations
  • 布局更灵活:可以用Dash的原生html.Div配合CSS Flex/Grid,或者用Dash Bootstrap Components快速排成网格(比如4行5列)
  • 维护更方便:每个饼图的逻辑独立,修改单个饼图不会影响其他的

给你个用Dash Bootstrap布局的示例:

import dash
from dash import dcc, html
import plotly.graph_objects as go
import dash_bootstrap_components as dbc  # 可选,用来快速实现响应式布局

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# 模拟20组饼图数据
pie_data = [
    {"labels": ["A", "B", "C"], "values": [30, 40, 30], "title": f"饼图{i+1}"}
    for i in range(20)
]

# 构建4行5列的网格布局
graph_rows = []
for i in range(0, 20, 5):
    current_row = []
    for j in range(5):
        if i + j < 20:
            data = pie_data[i+j]
            # 为每个Graph单独创建饼图
            fig = go.Figure(go.Pie(labels=data["labels"], values=data["values"]))
            fig.update_layout(title=data["title"], height=200, width=200)
            current_row.append(dbc.Col(dcc.Graph(figure=fig), width=2))
    graph_rows.append(dbc.Row(current_row, justify="center"))

app.layout = html.Div(graph_rows, style={"padding": "20px"})

if __name__ == "__main__":
    app.run_server(debug=True)

关于性能:20个Graph完全不用担心卡顿,只要每个饼图的数据量不是特别夸张(比如上万条分类数据),Dash渲染起来非常快。如果是动态加载数据,还可以用dcc.Store缓存数据,进一步优化加载速度。

总结

  • 如果追求画布的利用率,不想浪费空间,方案1更适合你;
  • 如果追求开发效率和后期维护的便捷性,方案2绝对是首选。

内容的提问来源于stack exchange,提问作者Mr. President

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:45:32