当前位置:首页>python>Python| 哑铃图

Python| 哑铃图

  • 2026-09-02 19:15:07
Python| 哑铃图

未经授权不得转载或抄袭。

转载合作请后台联系授权,侵权必究。

    

哑铃图(Dumbbell Plot),由两个圆点(代表开始值和结束值)和一条连接线段(代表变化或差异)组成,专门用于展示两个数据点之间的变化或差异。

    • 背景带:在 x 轴方向用背景带表示起点组和终点组的均值 ± 标准差(SD)范围,直观展示两组数据的整体分布集中程度。

    • 均值虚线:用两条垂直虚线分别标注起点组和终点组的算术平均值,为比较两组数据的整体水平提供基准。

    注:本文所用数据均为模拟数据,不具有实际意义。

    01

    全局设置

    字体设置

    plt.rcParams['font.family'] = 'Arial'plt.rcParams['font.size'] = 15plt.rcParams['axes.unicode_minus'] = False

    颜色配置

    # ---- 起点(第一数值列)颜色 ----start_colors = {    'outer': '#8CC7CB',    'inner': '#CFE6E7',    'edge': '#30B2BC',    'mean': '#8CC7CB',    'error_band': '#DAEDEE'}# ---- 终点(第二数值列)颜色 ----end_colors = {    'outer': '#EEDCA0',    'inner': '#F8F0D8',    'edge': '#E7CB75',    'mean': '#EEDCA0',    'error_band': '#FBF6E4'}# ---- 差值标签颜色 ----diff_color = '#30B2BC'# ---- 坐标轴与网格 ----spine_color = 'lightgray'grid_alpha = 0.2y_ticklabels_color = '#30B2BC'legend_text_color = 'black'# ---- 其他几何参数 ----connector_height = 0.06dot_screen_radius_px = 15diff_label_y_offset = 0.1

    02

    读取数据 + 基础计算

        # 读取数据    df = pd.read_csv('data2.csv')    # 自动获取列名    cat_col = df.columns[0]   # 分类列    val_col1 = df.columns[1]  # 起点数值列    val_col2 = df.columns[2]  # 终点数值列    # 计算差值 + 生成Y轴坐标(每行一个位置)    df['diff'] = df[val_col2] - df[val_col1]    df['y'] = np.arange(len(df))    # 计算两组数据的均值和标准差(用于背景填充+均值线)    mean_start = df[val_col1].mean()    sd_start = df[val_col1].std()    mean_end = df[val_col2].mean()    sd_end = df[val_col2].std()

    03

    绘制核心部分

    绘制背景误差填充带(均值 ± 标准差)

        ax.axvspan(mean_start - sd_start, mean_start + sd_start,               color=start_colors['error_band'], alpha=0.5)    ax.axvspan(mean_end - sd_end, mean_end + sd_end,               color=end_colors['error_band'], alpha=0.5)

     绘制连接线

        # 创建从起点颜色到终点颜色的渐变色图    gradient_start_color = start_colors['outer']    gradient_end_color = end_colors['outer']    cmap_grad = LinearSegmentedColormap.from_list('grad',                                                  [gradient_start_color, gradient_end_color], N=256)    # 逐行绘制连接线    for _, row in df.iterrows():        y = row['y']        # 确保矩形 x 范围从左到右(起点值到终点值)        if row[val_col1] <= row[val_col2]:            extent = (row[val_col1], row[val_col2],                      y - connector_height / 2, y + connector_height / 2)            cmap_range = (0, 1)  # 颜色映射范围:左端对应起点颜色,右端对应终点颜色        else:            extent = (row[val_col2], row[val_col1],                      y - connector_height / 2, y + connector_height / 2)            cmap_range = (1, 0)  # 方向相反时翻转颜色范围        gradient_rect(ax, extent, cmap_grad, direction=0,                      cmap_range=cmap_range, alpha=0.9, zorder=2)

    绘制起点和终点的圆点

        for _, row in df.iterrows():        # 起点圆点        radial_gradient_circle(ax, row[val_col1], row['y'], dot_screen_radius_px,                               outer_color=start_colors['outer'],                               inner_color=start_colors['inner'],                               n_res=70, zorder=4,                               edgecolor=start_colors['edge'], edgewidth=1.5)        # 终点圆点        radial_gradient_circle(ax, row[val_col2], row['y'], dot_screen_radius_px,                               outer_color=end_colors['outer'],                               inner_color=end_colors['inner'],                               n_res=70, zorder=4,                               edgecolor=end_colors['edge'], edgewidth=1.5)

    添加数值标签(起点和终点的具体数值)

        for _, row in df.iterrows():        # 起点数值标签(位于圆点上方)        ax.text(row[val_col1], row['y'] + label_y_offset, f"{row[val_col1]:.1f}",                va='bottom', ha='center', color=start_colors['label'], zorder=5)        # 终点数值标签        ax.text(row[val_col2], row['y'] + label_y_offset, f"{row[val_col2]:.1f}",                va='bottom', ha='center', color=end_colors['label'], zorder=5)

     添加差值标签(变化量,显示在连接线中间)

        for _, row in df.iterrows():        mid_x = (row[val_col1] + row[val_col2]) / 2  # 连接线中点 X 坐标        diff_val = row['diff']        # 正值显示 "+X.X",负值显示 "-X.X"        label = f"+{diff_val:.1f}" if diff_val > 0 else f"{diff_val:.1f}"        ax.text(mid_x, row['y'] + diff_label_y_offset, label,                va='bottom', ha='center', color=diff_color, zorder=6)

       绘制均值垂直线(虚线)

        ax.axvline(mean_start, linestyle='--', color=start_colors['mean'], alpha=0.7,               label=f'{val_col1}均值 = {mean_start:.1f}')    ax.axvline(mean_end, linestyle='--', color=end_colors['mean'], alpha=0.7,               label=f'{val_col2}均值 = {mean_end:.1f}')

    “今日分享至此✨”

    如有错误或不足之处,欢迎随时在评论区指出,感谢!

    完整代码获取,见评论区。

    往期推荐

    Python| 各轴刻度范围不同・多维度雷达图

    求点赞

    求分享

    求推荐

    最新文章

    随机文章