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

在R中使用for循环绘制多物种分国家直方图时重复绘图的问题

问题与解决方案

问题描述

现有名为pairs的数据集,结构示例如下:

id_density sp_code country  dens_ab ...
       <dbl> <fct>  <chr>     <dbl>       
1         15 LALO     US      24.0
2         16 LALO     US      32.0 
3         17 LALO     US      20.0 
4         18 LALO     US      30.0
5         19 LALO     US      17.5 
6         20 LALO     US      32.5 
...

需求:为每个物种(sp_code共21种)生成一组小倍数直方图,每组包含3个国家的dens_ab分布直方图。

尝试的代码如下:

# libraries
library(ggplot2)
library(dplyr)

# group by country
pairs <- pairs %>% group_by(country)

dplyr::is_grouped_df(pairs)
# Grouped (TRUE)

# Loop
plot.country <- function(x = pairs) {
  sp_code <- unique(x$sp_code)
  for (i in seq_along(sp_code)) {
    plot <- x %>% 
      ggplot(aes(x = dens_ab, color = country, fill = country)) +
  geom_histogram(data = filter(x, sp_code == sp_code[i]), alpha = 0.6, binwidth = 0.5) +
  scale_fill_viridis(discrete=TRUE) +
  scale_color_viridis(discrete=TRUE) +
  theme_ipsum()+
  xlab("Density (pairs/km2)") +
  ylab("Frequency") +
  facet_wrap(~country)
    if (dir.exists("output")) { } 
    else {dir.create("output")}
    ggsave(filename = paste0("output/", sp_code[i], "plot_site_dens.png"),
           plot = plot,
           width = 11, height = 8.5, units = "in")
    print(plot)
  }
}

# Plot function execution
plot.country()

遇到的问题:

  • 生成的直方图存在重复内容,不符合实际数据分布
  • 循环生成的图背景为黑色(非循环绘制时背景为白色)

问题分析与修正

1. 移除不必要的分组操作

一开始对pairs执行group_by(country)完全多余,分组后的数据集会让后续的filter操作按组执行,导致过滤逻辑混乱,先取消分组:

pairs <- pairs %>% ungroup()  # 取消分组,或者直接删除原代码中的group_by步骤

2. 修正ggplot数据过滤逻辑

原代码中,ggplot初始化时使用整个分组数据集,然后在geom_histogram里单独过滤,这会导致facet的分组基于整个数据集的country,但实际绘图数据是过滤后的,容易出现重复或错误分布。正确的做法是先过滤出当前物种的数据,再传入ggplot。

3. 解决黑色背景问题

theme_ipsum()是hrbrthemes包的主题,默认使用深色背景。如果需要白色背景,可以:

  • 改用默认白色背景主题(如theme_bw())
  • 或修改theme_ipsum()的参数(如theme_ipsum(plot_background = "white", panel_background = "white"))

修正后的完整代码

# 加载所需包
library(ggplot2)
library(dplyr)
# 如果使用theme_ipsum需要加载hrbrthemes
# library(hrbrthemes)

# 确保数据集未分组
pairs <- pairs %>% ungroup()

# 定义绘图函数
plot_country <- function(data = pairs) {
  # 获取所有唯一物种代码
  sp_list <- unique(data$sp_code)
  
  # 创建输出目录(放在循环外,避免重复检查)
  if (!dir.exists("output")) {
    dir.create("output")
  }
  
  # 循环每个物种
  for (sp in sp_list) {
    # 过滤当前物种的数据
    sp_data <- data %>% filter(sp_code == sp)
    
    # 绘制小倍数直方图
    p <- ggplot(sp_data, aes(x = dens_ab, color = country, fill = country)) +
      geom_histogram(alpha = 0.6, binwidth = 0.5) +
      scale_fill_viridis(discrete = TRUE) +
      scale_color_viridis(discrete = TRUE) +
      theme_bw()  # 使用白色背景主题,替换theme_ipsum()
      # 如果坚持用theme_ipsum,改为:
      # theme_ipsum(plot_background = "white", panel_background = "white") +
      xlab("Density (pairs/km2)") +
      ylab("Frequency") +
      facet_wrap(~country)
    
    # 保存图片
    ggsave(
      filename = paste0("output/", sp, "_plot_site_dens.png"),
      plot = p,
      width = 11, height = 8.5, units = "in"
    )
    
    # 打印图片
    print(p)
  }
}

# 执行绘图
plot_country()

额外优化建议

  • 避免使用plot作为变量名(它是R的内置函数),改用p或其他名称
  • 把创建目录的逻辑放在循环外,避免每次循环都重复检查
  • 使用sp in sp_list的循环方式更易读,比seq_along更直观

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:53:09