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

Plotly Scaleratio适配异范围X/Y点集的图形优化技术问询

坐标轴范围差异极大时的圆盘可视化优化方案

问题根源

当x、y轴数值范围差距悬殊(比如x∈[0.1,1.2],y∈[150,250]),原代码中fig.update_yaxes(scaleanchor="x", scaleratio=1)会强制坐标轴等比例缩放,导致y轴被极度压缩,扇形圆盘变成细长条,完全失去可视化意义。之前尝试的y值归一化未解决问题,核心是没有配合调整轴比例或图形尺寸。

可行解决方案

方案1:使用Pie图表定位(推荐)

利用Plotly的go.Pie组件,通过domain参数将饼图精准定位到对应坐标点,不受坐标轴比例影响,圆盘始终保持圆形:

import numpy as np
import plotly.graph_objects as go

x_points = [0.39, 0.17, 0.12, 1.2]
y_points = [210, 160, 150, 250]
ab = [[1, 1], [1, 2], [3, 7], [15, 2]]
colors = ["yellow", "red"]

# 计算坐标轴范围,用于转换饼图的domain参数
x_min, x_max = min(x_points), max(x_points)
y_min, y_max = min(y_points), max(y_points)
x_range = x_max - x_min
y_range = y_max - y_min

# 控制圆盘大小的比例系数(可根据需求调整)
pie_size = 0.08

fig = go.Figure()

for idx, (x, y, (a, b)) in enumerate(zip(x_points, y_points, ab)):
    # 将坐标点转换为归一化的domain范围
    x_domain = [(x - x_min)/x_range - pie_size/2, (x - x_min)/x_range + pie_size/2]
    y_domain = [(y - y_min)/y_range - pie_size/2, (y - y_min)/y_range + pie_size/2]
    
    fig.add_trace(go.Pie(
        labels=[f"{a/(a+b)*100:.1f}%", f"{b/(a+b)*100:.1f}%"],
        values=[a, b],
        marker_colors=colors,
        domain={'x': x_domain, 'y': y_domain},
        showlegend=idx == 0,  # 仅第一个饼图显示图例
        textposition='none'  # 隐藏内部文字,避免拥挤
    ))

# 可选:添加中心标记点,增强定位清晰度
fig.add_trace(go.Scatter(
    x=x_points, y=y_points,
    mode='markers',
    marker=dict(color='black', size=3),
    showlegend=False
))

fig.update_layout(
    xaxis_title='X轴',
    yaxis_title='Y轴',
    # 给坐标轴添加少量边距,避免圆盘被截断
    xaxis=dict(range=[x_min - x_range*0.1, x_max + x_range*0.1]),
    yaxis=dict(range=[y_min - y_range*0.1, y_max + y_range*0.1])
)

fig.show()

方案2:动态调整扇形半径适配轴比例

如果坚持使用原有的Scatter绘制扇形,可根据坐标轴的比例关系,分别设置x、y方向的半径,确保圆盘显示为圆形:

import numpy as np
from numpy import pi, sin, cos
import plotly.graph_objects as go

def degree2rad(degrees):
    return degrees * pi / 180

# 修改disk_part函数,支持单独设置x、y方向的半径
def disk_part(center, radius_x, radius_y, start_angle, end_angle, n_points=50):
    t = np.linspace(degree2rad(start_angle), degree2rad(end_angle), n_points)
    x = center[0] + radius_x * cos(t)
    y = center[1] + radius_y * sin(t)
    return np.append(x, (center[0], x[0])), np.append(y, (center[1], y[0]))

x_points = [0.39, 0.17, 0.12, 1.2]
y_points = [210, 160, 150, 250]
ab = [[1, 1], [1, 2], [3, 7], [15, 2]]
colors = ["yellow", "red"]

# 计算坐标轴比例系数
x_min, x_max = min(x_points), max(x_points)
y_min, y_max = min(y_points), max(y_points)
axis_ratio = (x_max - x_min) / (y_max - y_min)

# 基于x轴范围设置基础半径,再推算y方向半径
base_radius_x = 0.1
base_radius_y = base_radius_x / axis_ratio

fig = go.Figure()

for x, y, (a, b) in zip(x_points, y_points, ab):
    ratio = a / (a + b)
    for start_angle, end_angle, color in zip(
        (0, 360 * ratio), (360 * ratio, 359.9), colors
    ):
        x_disk, y_disk = disk_part([x, y], base_radius_x, base_radius_y, start_angle, end_angle)
        fig.add_trace(
            go.Scatter(
                x=x_disk,
                y=y_disk,
                fill="toself",
                fillcolor=color,
                line={"color": color},
                name=f"{(end_angle-start_angle)/360 * 100:.1f}%" if start_angle == 0 else None,
                showlegend=start_angle == 0
            )
        )

# 取消强制等比例缩放,让坐标轴自适应数据
fig.update_layout(
    xaxis_title='X轴',
    yaxis_title='Y轴',
    xaxis=dict(range=[x_min - base_radius_x*2, x_max + base_radius_x*2]),
    yaxis=dict(range=[y_min - base_radius_y*2, y_max + base_radius_y*2])
)

fig.show()

关键注意点

  • 原代码的scaleanchor="x", scaleratio=1是导致拉伸的核心原因,必须取消或配合动态半径调整。
  • 方案1的go.Pie方式更简洁,且天然适配任意坐标轴比例,是优先选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:03:11