pythonic生物人

再见R语言,AI搞定Nature子刊主图「a~h 8张图」,只用1分钟

使用R语言复现一下Nature aging中以下子图a~h 8张图,细节拉满,非常值得学习!

来源:s43587-026-01154-7
来源:s43587-026-01154-7

先理解一下图要表达的意思:

a~h图依次展示8个变量,即p16ink4a (a), Cdkn2a (b), Lgals3 (c), Cdkn1a/p21 (d), Ccl2 (e), Ccl5 (f), Apoe (g)和Gpr34 (h)在雌雄鼠的两个部位中的表达量差异。

以子图a为例,

图片

以上直接将原图给到AI,让它描述即可,

图片

再理解一下作者用什么样的图来展示:

  • 用抖动散点图展示数据点
  • 用颜色展示雌(粉色)雄(蓝色)个体
  • 用虚线展示雌(粉色)雄(蓝色)个体
  • 用标记展示小鼠中不同部分,圆圈(HIP部分),三角(FFCC部位)
  • 同性别内,上侧展示不同部位之间统计p value
  • 每个性别,添加误差棒(mean ± SD)
  • 添加均值横线

还是以子图a为例,

图片

同样,以上直接将原图给到AI,让它描述即可,

图片

通过以上两步已经搞定图的含义+图的展现形式,然后让AI再次汇总回答,结合原图描述,使用R语言复现,

图片

每次输出代码后,结合原图,让它调整,经过多轮交流,看一下最终效果图

图片

代码学习:导入R package

library(ggplot2)
library(patchwork)
library(readxl)

设置颜色、导入数据

xlsx_file <- "r_data/s43587-026-01154-7_fig1.xlsx"
group_levels <- c("F:HIP", "F:FFCC", "M:HIP", "M:FFCC")
female_fill <- "#E98AA8"# 雌性填充色(粉)
male_fill   <- "#7EB6E0"# 雄性填充色(蓝)

数据转换为长数据

# ---- 转换为长表(每个观测一行) ----
  long <- do.call(rbind, lapply(group_levels, function(g)
    data.frame(
      group  = factor(g, levels = group_levels),                     # F:HIP, F:FFCC, M:HIP, M:FFCC
      sex    = factor(ifelse(startsWith(g, "F"), "Female", "Male"), c("Female", "Male")),
      region = factor(ifelse(grepl("HIP", g), "HIP", "FFCC"), c("HIP", "FFCC")),
      value  = as.numeric(raw[[g]]),
      stringsAsFactors = FALSE
    )
  ))
  long <- long[!is.na(long$value), ]  # 去除缺失值

数据作Welch双尾t检验、计算每组均值和标准差

# ---- 计算每组均值和标准差 ----
  sm <- aggregate(value ~ group + sex + region, long, function(x)
    c(mean = mean(x), sd = sd(x)))
  sm <- data.frame(
    group = sm$group, sex = sm$sex, region = sm$region,
    mean_y = sm$value[, "mean"], sd_y = sm$value[, "sd"]
  )

# ---- Welch双尾t检验(HIP vs FFCC,分雌雄) ----
  hip_f  <- long$value[long$sex == "Female" & long$region == "HIP"]
  ffcc_f <- long$value[long$sex == "Female" & long$region == "FFCC"]
  hip_m  <- long$value[long$sex == "Male"   & long$region == "HIP"]
  ffcc_m <- long$value[long$sex == "Male"   & long$region == "FFCC"]
  pf <- t.test(hip_f, ffcc_f, var.equal = FALSE)$p.value  # 雌性p值
  pm <- t.test(hip_m, ffcc_m, var.equal = FALSE)$p.value  # 雄性p值

雌雄分组虚线、误差棒、均值横线

ggplot(long, aes(group, value, fill = sex, shape = region)) +
# 雌雄分组虚线
    geom_vline(xintercept = 2.5, linetype = "dashed", colour = "#333", linewidth = 0.35) +
# 误差棒(mean ± SD)
    geom_linerange(
      data = sm, aes(x = group, ymin = pmax(0, mean_y - sd_y), ymax = mean_y + sd_y),
      inherit.aes = FALSE, linewidth = 0.45, colour = "#111"
    ) +
# 均值横线
    geom_crossbar(
      data = sm, aes(x = group, y = mean_y, ymin = mean_y, ymax = mean_y),
      inherit.aes = FALSE, width = 0.38, linewidth = 0.55, colour = "#111", middle.linewidth = 0.85
    ) 

抖动散点

# 散点(jitter避免重叠)
    geom_jitter(width = 0.12, height = 0, size = 2.1, stroke = 0.25, colour = "#333") 

添加统计P value

if (pf < 0.05) {
    g <- g +
      annotate("segment", x = 1, xend = 2, y = ym * 1.02, yend = ym * 1.02, linewidth = 0.32) +
      annotate("text", x = 1.5, y = ym * 1.065, label = fmt(pf), size = 2.35)
  }
if (pm < 0.05) {
    g <- g +
      annotate("segment", x = 3, xend = 4, y = ym * 1.02, yend = ym * 1.02, linewidth = 0.32) +
      annotate("text", x = 3.5, y = ym * 1.065, label = fmt(pm), size = 2.35)
  }

设置坐标轴、线、刻度、颜色、字号等细节

# y轴范围与刻度
    scale_y_continuous(
      limits = c(0, ym * 1.16), breaks = p$y_breaks, expand = c(0, 0)
    ) +
    labs(x = NULL, y = p$y_label, title = p$letter) +
    theme_classic(base_family = "sans") +
    theme(
      plot.title = element_text(face = "bold", size = 12, hjust = 0),
      axis.title.y = element_text(size = 8),
      axis.text.y = element_text(size = 7),
      axis.text.x = element_text(size = 6.5, angle = 90, hjust = 1, vjust = 0.5)
    )

测试数据+详细代码,后期会加入👉2026可视化工具TOP3

加入学习

图片


往期精彩

2026可视化工具TOP3

复现IF50.0期刊上6张图

复现Science正刊图

复现顶刊forestplot

师姐认为你会的55个科研图表

师弟师妹偷偷用的7大科研图表

复现Nature中的PCA图

复现Cell图