我想用下面的代码通过Ploly制作一张我所在城市的白天长度饼图:

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()

The result looks like this:enter image description here

I want to add two lines to the pie chart, where the grey part meets the golden part, and add labels to them with sunset and sunrise, respectively. In short, I would like to see something like this: enter image description here

我如何才能做到这一点(如果这是可能的话)?

推荐答案

我重构了您的代码,以便我们使用go.Barpolar来创建地段,使用go.Scatterpolar来添加地段的文本标签以及指示sunrisesunset的行.

为了帮助在正确的位置放置时间字符串,我编写了一个将时间字符串转换为度量度的函数(例如,绘图需要知道"06:11"是从正北开始的顺时针92.75 degrees),并设置了极线图的参数,使0度为正北,正Angular 的方向顺时针移动-这确保了我们与时钟极坐标系统保持一致.

由于sunrisesunset标签与其他刻度线位于相同的径向位置,因此我们可以扩展tickvalsticktext数组,以包括这些附加标签的Angular 和文本.需要注意的一件事是,因为Plot从左到右书写文本,所以tickText应该看起来像[f"{sunrise} sunrise", f"sunset {sunset}"],这样时间字符串就更接近日出和日落的扇区.

from datetime import datetime
import typing as t
import plotly.graph_objects as go

def get_clock_theta(time_str: str):
    """
    converts time string in the format of '%H:%M' to degrees
    get_clock_theta("12:00") returns 180.0
    """
    time = datetime.strptime(time_str, '%H:%M')
    total_hours = time.hour + time.minute/60
    return (360 * total_hours / 24)

def main():
    values = [0.258, 0.542, 0.201]
    labels = ["night-sunrise", "day", "night-sunset"]
    sunrise, sunset = "06:11", "19:11"
    colors = ["#7D8491", "#DEB841", "#7D8491"]

    start_theta, end_theta = 0.0, 360.0
    sunrise_theta = get_clock_theta(sunrise)
    sunset_theta = get_clock_theta(sunset)

    all_angles = [start_theta, sunrise_theta, sunset_theta, end_theta]
    thetas, widths = [], []
    for i in range(len(all_angles)-1):
        thetas.append((all_angles[i] + all_angles[i+1]) / 2)
        widths.append(abs(all_angles[i+1] - all_angles[i]))

    r_min, r_max = 0.7, 1.0

    fig = go.Figure()
    for theta, width, label, color, value in zip(thetas, widths, labels, colors, values):
        fig.add_trace(go.Barpolar(
            r=[r_max],
            theta=[theta],
            width=[width],
            base=[r_min],
            name=label,
            marker=dict(color=color),
            text=value,
            legendgroup=label,
        ))
        fig.add_trace(go.Scatterpolar(
            r=[(r_min+r_max)/2],
            theta=[theta],
            mode='text',
            text=f"{value:.1%}",
            textfont=dict(color='rgb(50,50,50)'),
            showlegend=False,
            legendgroup=label,
        ))

    for theta, label in zip(
        [sunrise_theta, sunset_theta], 
        ["sunrise","sunset"]
    ):
        fig.add_trace(go.Scatterpolar(
            r=[r_min,r_max],
            theta=[theta, theta],
            mode='lines',
            marker=dict(color='white'),
            showlegend=False,
        ))

    fig.update_layout(template="plotly_dark")

    ## set 0 degrees to be due north, and go clockwise
    ## the default is 0 degrees being east, and going counterclockwise
    ## add 24 tickvals for each hour spaced evenly around the polar chart
    ## and also add your labels for sunrise and sunset
    fig.update_polars(
        angularaxis = dict(
            tickvals=[i*360/24 for i in range(24)] + [sunrise_theta, sunset_theta],
            ticktext=[f"{i:02d}:00" for i in range(24)] + [f"{sunrise} sunrisee", f"sunset {sunset}"],
            tickcolor="white",
            ticklen=10,
            rotation=90,
            direction='clockwise',
            gridcolor="rgba(0,0,0,0)"
        ),
        radialaxis = dict(
            visible=False,
            range=[0,1],
        )
    )

    fig.show()
    

if __name__ == "__main__":
    main()

enter image description here

Python相关问答推荐

取相框中一列的第二位数字

键盘.任务组

Python中使用Delivercio进行多个请求

Pandas滚动分钟,来自其他列的相应值

如何使用bs 4从元素中提取文本

如何将桌子刮成带有Se的筷子/要求/Beautiful Soup ?

Python中的函数中是否有充分的理由接受float而不接受int?

如何根据参数推断对象的返回类型?

运行终端命令时出现问题:pip start anonymous"

计算组中唯一值的数量

对所有子图应用相同的轴格式

如何从需要点击/切换的网页中提取表格?

考虑到同一天和前2天的前2个数值,如何估算电力时间序列数据中的缺失值?

Matplotlib中的字体权重

人口全部乱序 - Python—Matplotlib—映射

交替字符串位置的正则表达式

如何在海上配对图中使某些标记周围的黑色边框

Python—为什么我的代码返回一个TypeError

为什么Python内存中的列表大小与文档不匹配?

Flask运行时无法在Python中打印到控制台