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

ggplot(plotnine)分组柱状图缺失观测时的position_dodge2定位问题

解决分组柱状图无数据组留空白的问题

要让无观测数据的组保留空白位置,不让剩余柱子居中,需要两步核心操作:补全缺失的分组数据,再调整柱状图的位置参数。

关键修改点

  1. 补全数据:确保每个homeworld都包含male和female两个性别组,无数据的组计数设为0
  2. 调整位置参数:移除position_dodge2的preserve="single"参数,改用常规的position_dodge固定柱子位置

修改后的完整代码

import plotnine as pn
import pandas as pd
import plotnine.colors as pf  # 补充原代码用到的颜色模块

data = pd.read_csv("starwars.csv")  # 数据来源:https://github.com/tidyverse/dplyr/blob/main/data-raw/starwars.csv
hw = data["homeworld"].value_counts().head(6)
data = data.merge(hw, left_on="homeworld", right_on="homeworld")

# 预处理:补全所有性别-家园组合,无数据的填0
data = data.dropna(subset=["gender"])
count_data = (
    data.groupby(["homeworld", "gender"])
    .size()
    .unstack(fill_value=0)
    .reset_index()
    .melt(id_vars="homeworld", var_name="gender", value_name="count")
)

# 按男性数量排序家园顺序
order = (
    count_data[count_data["gender"] == "male"]
    .sort_values("count", ascending=False)["homeworld"]
    .tolist()
)

(
    pn.ggplot(count_data, pn.aes(x="factor(homeworld)", y="count", fill="factor(gender, ['male', 'female'])"))
    + pn.geom_bar(stat="identity", position=pn.position_dodge(width=0.8))  # 固定分组柱子位置
    + pn.scale_fill_manual({"male": pf.color.BLUE, "female": pf.color.RED})
    + pn.scale_x_discrete(limits=order)
    + pn.scale_y_continuous(expand=(0, 0))
    + pn.labs(
        title="Difference between males and females", 
        y="Count", x="Homeworld", 
        fill='Gender',
        caption="There is a significant difference between the number of males and females on Naboo and Tatooine.",
    )
)

代码说明

  • 通过groupby+unstack+melt的组合操作,生成每个家园对应两种性别的完整计数,无数据的组自动填充0,确保每个x轴类别下都有两组数据
  • 改用stat="identity"直接使用统计好的计数,搭配position_dodge(width=0.8)让柱子按分组固定位置排列,即使某组计数为0,也会保留对应的空白位置
  • 调整排序逻辑,基于男性计数确定x轴家园顺序,符合需求

内容的提问来源于stack exchange,提问作者Petr Hála

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:40:15