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

如何基于Pandas DataFrame在Python中绘制Spotfire风格对比圆环图?

基于Pandas DataFrame实现Spotfire风格对比圆环图

可以用Matplotlib或Plotly实现这类对比圆环图,核心是将DataFrame中的指标映射为圆的大小(半径)和圆环宽度(与基准值的差异),同时按环形布局排列对比项。

示例数据准备

先构造模拟数据,包含基准项(Center)和多个对比项,Value用于计算差异(圆环宽度),Size用于决定圆的半径:

import pandas as pd

data = {
    "Category": ["Center", "A", "B", "C", "D"],
    "Value": [100, 85, 120, 90, 110],
    "Size": [150, 120, 160, 130, 140]
}
df = pd.DataFrame(data)

用Matplotlib实现

Matplotlib适合静态可视化,通过计算布局坐标、圆半径和圆环宽度来绘制:

import matplotlib.pyplot as plt
import numpy as np

# 提取基准值
base_value = df.loc[df["Category"] == "Center", "Value"].iloc[0]
base_size = df.loc[df["Category"] == "Center", "Size"].iloc[0]

# 分离对比项
comparison_df = df[df["Category"] != "Center"].reset_index(drop=True)
n_comparisons = len(comparison_df)

# 计算对比项的布局角度(环形分布)
angles = np.linspace(0, 2 * np.pi, n_comparisons, endpoint=False)
# 布局半径(控制对比圆与中心圆的距离)
layout_radius = base_size * 1.8

fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect("equal")

# 绘制中心基准圆
base_radius = base_size / 20  # 缩放比例适配画布
circle_base = plt.Circle((0, 0), base_radius, color="white", ec="black", lw=2)
ax.add_artist(circle_base)
# 中心标注
ax.text(0, 0, f"{base_value}\n{base_size}", ha="center", va="center", fontsize=12)

# 绘制每个对比圆环
for i in range(n_comparisons):
    cat = comparison_df.loc[i, "Category"]
    val = comparison_df.loc[i, "Value"]
    size = comparison_df.loc[i, "Size"]
    # 计算圆环宽度:基于与基准值的差异比例
    diff_ratio = abs(val - base_value) / base_value
    ring_width = base_radius * diff_ratio
    # 对比圆半径
    comp_radius = size / 20
    # 计算对比圆的坐标
    x = layout_radius / 20 * np.cos(angles[i])
    y = layout_radius / 20 * np.sin(angles[i])
    
    # 绘制外环(基础圆)
    circle_outer = plt.Circle((x, y), comp_radius, color="white", ec="gray", lw=1)
    ax.add_artist(circle_outer)
    # 绘制差异圆环
    color = "red" if val > base_value else "blue"
    circle_ring = plt.Circle((x, y), comp_radius - ring_width/2, width=ring_width, color=color, alpha=0.6)
    ax.add_artist(circle_ring)
    # 标注类别和数值
    ax.text(x, y + comp_radius + 0.5, f"{cat}\n{val}", ha="center", va="bottom", fontsize=10)

# 调整坐标轴范围
max_radius = max(layout_radius, base_size, max(comparison_df["Size"])) / 20 + 2
ax.set_xlim(-max_radius, max_radius)
ax.set_ylim(-max_radius, max_radius)
ax.axis("off")
plt.title("Spotfire Style Comparison Circles", fontsize=14)
plt.show()

代码说明

  • 中心圆为基准项,周围对比圆按环形均匀分布
  • 圆的大小由Size字段映射,圆环宽度由Value与基准值的差异比例决定
  • 颜色区分差异方向:红色表示高于基准值,蓝色表示低于

用Plotly实现(交互式)

Plotly支持交互式可视化,鼠标悬停可查看详细数据,布局逻辑类似但更简洁:

import plotly.graph_objects as go
import numpy as np

# 提取基准值
base_value = df.loc[df["Category"] == "Center", "Value"].iloc[0]
base_size = df.loc[df["Category"] == "Center", "Size"].iloc[0]
comparison_df = df[df["Category"] != "Center"].reset_index(drop=True)
n_comparisons = len(comparison_df)

# 计算对比项坐标
angles = np.linspace(0, 2 * np.pi, n_comparisons, endpoint=False)
layout_radius = base_size * 1.8
x = layout_radius / 20 * np.cos(angles)
y = layout_radius / 20 * np.sin(angles)

fig = go.Figure()

# 添加中心基准圆
fig.add_trace(go.Scatter(
    x=[0], y=[0],
    mode="markers+text",
    marker=dict(size=base_size/5, color="white", line=dict(color="black", width=2)),
    text=[f"{base_value}\nSize: {base_size}"],
    textposition="middle center",
    name="Center"
))

# 添加对比圆环
for i in range(n_comparisons):
    cat = comparison_df.loc[i, "Category"]
    val = comparison_df.loc[i, "Value"]
    size = comparison_df.loc[i, "Size"]
    diff_ratio = abs(val - base_value) / base_value
    ring_width = size/5 * diff_ratio  # 圆环宽度
    
    # 外层基础圆
    fig.add_trace(go.Scatter(
        x=[x[i]], y=[y[i]],
        mode="markers+text",
        marker=dict(size=size/5, color="white", line=dict(color="gray", width=1)),
        text=[cat],
        textposition="top center",
        showlegend=False
    ))
    # 差异圆环
    color = "#ff4d4d" if val > base_value else "#4d79ff"
    fig.add_trace(go.Scatter(
        x=[x[i]], y=[y[i]],
        mode="markers",
        marker=dict(size=size/5 - ring_width, color=color, line=dict(color=color, width=ring_width)),
        hovertext=f"Category: {cat}<br>Value: {val}<br>Size: {size}<br>Difference: {val - base_value}",
        hoverinfo="text",
        name=f"{cat} ({val})"
    ))

# 调整布局
fig.update_layout(
    title="Interactive Comparison Circles",
    showlegend=True,
    xaxis=dict(visible=False, range=[-15, 15]),
    yaxis=dict(visible=False, range=[-15, 15]),
    width=700,
    height=700,
    hovermode="closest"
)

fig.show()

代码说明

  • 交互式悬停可查看每个对比项的详细指标
  • 用两层 marker 实现圆环效果:外层白色基础圆,内层带宽度的颜色环
  • 同样通过颜色区分与基准值的差异方向

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:05:35