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

ggplot2绘制饼图:图例百分比与切片不匹配问题排查

问题原因及修复方案

核心问题原因

  • 类别顺序不统一:你手动构建的pie_data里的AgeCategorySex是按自定义顺序排列的,但ggplot会自动将这个字符串向量转为因子,并按字母顺序排序切片和图例。而你生成的custom_legend是按原始自定义顺序拼接的,这就导致图例标签和实际切片的对应关系完全错乱,百分比和颜色自然不匹配。
  • 未固定颜色映射:你定义了colors调色板但从未使用,ggplot默认的颜色映射会随类别排序变化,进一步加剧颜色和类别的不对应。
  • 冗余数据操作:循环中反复修改breed_data$AgeCategory是多余的,你已经通过age_counts直接构建了pie_data,这部分操作不会影响饼图,但会增加不必要的计算开销。

修复代码调整

1. 提前将类别设为固定顺序的因子

在定义AgeCategorySex后添加:

# 将类别设为固定顺序的因子,避免ggplot自动排序
AgeCategorySex <- factor(AgeCategorySex, levels = AgeCategorySex)

2. 替换图例和颜色映射的代码

把原来的scale_fill_discrete替换为scale_fill_manual,手动绑定颜色、类别和标签:

# 替换原有的图例设置代码
chart <- chart + 
  guides(fill = guide_legend(title = "Age Category (Percentage)")) +
  scale_fill_manual(
    values = colors,  # 使用你定义的颜色板
    labels = custom_legend,
    breaks = AgeCategorySex  # 强制按因子顺序显示图例
  )

3. 移除冗余的breed_data$AgeCategory操作

删掉以下代码(因为你没有用这个列生成饼图,完全冗余):

# Add AgeCategory column and initialize it
breed_data$AgeCategory <- NA

以及内层循环中对breed_data$AgeCategory[j]的赋值操作。

完整修复后的核心循环片段

# Loop through each breed
for (breed in data2) {
  breed_data <- subset(data1, Primary.Breed == breed)
  
  # Initialize vector to store counts for each age category sex
  age_counts <- rep(0, length(AgeCategorySex))
  
  # Calculate difference in days between each birth date and each date in the vector
  for (i in 1:length(dates)) {
    date2 <- dates[i]
    
    # Reset age counts for each date
    age_counts <- rep(0, length(AgeCategorySex))
    
    # Calculate age category for each record
    for (j in 1:nrow(breed_data)) {
      diff <- as.numeric(difftime(date2, breed_data$DateOfBirth[j], units = "days"))
      if (!is.na(diff) && diff>0) {
        if (diff < 90 && breed_data$Sex[j] == "M") {
          age_counts[1] <- age_counts[1] + 1
        } else if (diff < 90 && breed_data$Sex[j] == "F") {
          age_counts[2] <- age_counts[2] + 1
        } else if (diff >= 90 && diff < 180 && breed_data$Sex[j] == "M") {
          age_counts[3] <- age_counts[3] + 1
        } else if (diff >= 90 && diff < 180 && breed_data$Sex[j] == "F") {
          age_counts[4] <- age_counts[4] + 1
        } else if (diff >= 180 && diff < 365 && breed_data$Sex[j] == "M") {
          age_counts[5] <- age_counts[5] + 1
        } else if (diff >= 180 && diff < 365 && breed_data$Sex[j] == "F") {
          age_counts[6] <- age_counts[6] + 1
        } else if (diff >= 365 && breed_data$Sex[j] == "M") {
          age_counts[7] <- age_counts[7] + 1
        } else if (diff >= 365 && breed_data$Sex[j] == "F") {
          age_counts[8] <- age_counts[8] + 1
        }
      }
    }
    
    # Calculate total count
    total_count <- sum(age_counts)
    
    # Calculate percentages
    percentages <- paste0(round((age_counts / total_count) * 100, 2), "%")
    
    # Create the pie chart using ggplot2
    chart_title <- paste("Pie chart for", breed, "on", as.character(dates[i]), "(Total:", total_count, ")")
    pie_data <- data.frame(AgeCategorySex, Count = age_counts)
    chart <- ggplot(pie_data, aes(x = "", y = Count, fill = AgeCategorySex)) +
      geom_bar(stat = "identity") +
      coord_polar("y", start = 0) +
      labs(title = chart_title) +
      theme_void()
    
    # Add custom legend with percentages and fixed color mapping
    custom_legend <- paste(pie_data$AgeCategorySex, percentages, sep = " - ")
    chart <- chart + 
      guides(fill = guide_legend(title = "Age Category (Percentage)")) +
      scale_fill_manual(
        values = colors,
        labels = custom_legend,
        breaks = AgeCategorySex
      )
    
    # Save the plot as a PNG file with increased width
    ggsave(filename = paste0(breed, "_plot", date2, ".png"), plot = chart, width = 10, height = 4)
    
    # Add the plot image to the Word document
    doc <- body_add_img(doc, src = paste0(breed, "_plot", date2, ".png"), width = 7, height = 4)
    
    # Print plot for current month and breed
    print(chart)
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:20:53