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

如何在Plotly饼图指定位置添加标注线与自定义标签?

问题:为Plotly当日城市时长饼图添加日出日落标注线及文本

我希望通过Plotly绘制当日所在城市的时长饼图,使用如下代码:

import typing as t
import plotly.graph_objects as go


def add_circular_labels(fig: go.Figure,
                        labels: t.List[str]):
    fig.add_trace(go.Scatterpolar())
    fig.update_layout(
        polar = dict(
            radialaxis_visible=False,
            angularaxis = dict(
                type="category",
                categoryarray=labels,
                direction="clockwise",
                showticklabels=True,
                ticks="outside",
                ticklen=8,
                tickcolor="white",
                showgrid=False)
        )
    )
    return fig


def main():
    values = [0.258, 0.542, 0.201]
    labels = ["night-sunrise", "day", "night-sunset"]
    sunset, sunrise = "06:11", "19:11"
    fig = go.Figure(data=[go.Pie(labels=labels,
                                 values=values,
                                 hole=.7,
                                 direction="clockwise",
                                 sort=False)])
    fig.update_layout(template="plotly_dark")
    fig.update_traces(marker=dict(colors=["#7D8491", "#DEB841", "#7D8491"]))
    fig = add_circular_labels(fig, [f"{i:02d}:00" for i in range(24)])
    fig.show()
    

if __name__ == "__main__":
    main()

当前生成的饼图已具备基础效果,我想要在灰色区域与金色区域的交界处添加两条标注线,并分别标注sunset和sunrise,请问该如何实现?


解决方案

要实现这个需求,我们可以通过计算交界点的极坐标角度,使用Scatterpolar绘制标注线,并通过annotations添加文本标签。具体修改如下:

1. 核心逻辑说明

  • Plotly极坐标的0°对应顶部(12点位置),角度顺时针递增,每小时对应15°(360°/24小时)。
  • 将日出日落时间转换为小时数,再计算对应的极坐标角度,确保标注线精准对齐交界位置。
  • 用Scatterpolar绘制从饼图中心到边缘的线段,用add_annotation在标注线外侧添加文本标签。

2. 修改后的完整代码

import typing as t
import plotly.graph_objects as go


def add_circular_labels(fig: go.Figure,
                        labels: t.List[str]):
    fig.add_trace(go.Scatterpolar())
    fig.update_layout(
        polar = dict(
            radialaxis_visible=False,
            angularaxis = dict(
                type="category",
                categoryarray=labels,
                direction="clockwise",
                showticklabels=True,
                ticks="outside",
                ticklen=8,
                tickcolor="white",
                showgrid=False)
        )
    )
    return fig


def time_to_angle(time_str: str) -> float:
    # 将HH:MM时间转换为极坐标角度(顺时针,顶部0°对应12点)
    hours, minutes = map(int, time_str.split(":"))
    total_hours = hours + minutes / 60
    # 1小时对应15°,计算最终角度
    return total_hours * 15


def main():
    values = [0.258, 0.542, 0.201]
    labels = ["night-sunrise", "day", "night-sunset"]
    sunset, sunrise = "06:11", "19:11"
    
    # 计算日出日落对应的极坐标角度
    sunrise_angle = time_to_angle(sunrise)
    sunset_angle = time_to_angle(sunset)
    
    fig = go.Figure(data=[go.Pie(labels=labels,
                                 values=values,
                                 hole=.7,
                                 direction="clockwise",
                                 sort=False)])
    fig.update_layout(template="plotly_dark")
    fig.update_traces(marker=dict(colors=["#7D8491", "#DEB841", "#7D8491"]))
    
    # 添加日出日落标注线
    # 日出标注线
    fig.add_trace(go.Scatterpolar(
        r=[0, 1],
        theta=[sunrise_angle, sunrise_angle],
        mode="lines",
        line=dict(color="white", width=2),
        showlegend=False
    ))
    # 日落标注线
    fig.add_trace(go.Scatterpolar(
        r=[0, 1],
        theta=[sunset_angle, sunset_angle],
        mode="lines",
        line=dict(color="white", width=2),
        showlegend=False
    ))
    
    # 添加文本标注(将极坐标转换为笛卡尔坐标,放置在标注线外侧)
    # 日出文本
    cartesian_sunrise = go.layout.polar.angularaxis.radial_to_cartesian(sunrise_angle, 1)
    fig.add_annotation(
        x=0.5 + 0.55 * cartesian_sunrise[0],
        y=0.5 + 0.55 * cartesian_sunrise[1],
        text=sunrise,
        showarrow=False,
        font=dict(color="white", size=12)
    )
    # 日落文本
    cartesian_sunset = go.layout.polar.angularaxis.radial_to_cartesian(sunset_angle, 1)
    fig.add_annotation(
        x=0.5 + 0.55 * cartesian_sunset[0],
        y=0.5 + 0.55 * cartesian_sunset[1],
        text=sunset,
        showarrow=False,
        font=dict(color="white", size=12)
    )
    
    fig = add_circular_labels(fig, [f"{i:02d}:00" for i in range(24)])
    fig.show()
    

if __name__ == "__main__":
    main()

关键细节

  • time_to_angle函数:精准转换时间到极坐标角度,确保标注线对齐实际日出日落时刻。
  • 标注线设置:通过r=[0,1]绘制从中心到饼图边缘的线段,颜色与深色模板适配。
  • 文本位置:利用极坐标转笛卡尔坐标的方法,将文本放在标注线外侧,避免遮挡饼图内容。

内容的提问来源于stack exchange,提问作者Gleb Ryabov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:24:56