如何在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
相关产品推荐
相关产品推荐

