2026年3月20日 研究日志

绘制可用的会议展示用图

↓根据之前生成的生存分析结果绘制KM生存曲线

library(readr)
library(tidyr)
library(here)
library(ggplot2)
library(dplyr)
library(patchwork)
library(gridExtra)
library(tibble)
library(scales)
options(repr.plot.width=8.8, repr.plot.height=6, repr.plot.res=600)

# Basic information
PatientsInSGL <- 98897
PatientsInGLP <- 98902

# Input data(Additional annotations have been remove before)
data <- read.csv(here("Outcome_7_Result_b_KM_graph.csv"))
colnames(data) <- c("Time", 
                    "Surv1", "Lower1", "Upper1",
                    "Surv2", "Lower2", "Upper2")

# transfer to long format
plot_data <- data %>%
  pivot_longer(
    cols = -Time,
    names_to = c(".value", "Cohort"),
    names_pattern = "([A-Za-z]+)(\\d)"
  ) %>%
  mutate(
    Cohort = paste0("Cohort", Cohort)
  )

plot_data <- plot_data %>%
  mutate(Cohort = recode(Cohort,
                         "Cohort1" = "SGLT2i",
                         "Cohort2" = "GLP1RA"))

# Check data frame
if (nrow(plot_data) == 0 || all(is.na(plot_data$Lower))) {
  stop("Data conversion error: No confidence interval data was detected after conversion. Please check the original CSV structure.")
}

# Plot
# Color
color_SGLT2i <- "#8E00FA"  
fill_SGLT2i <- adjustcolor(color_SGLT2i, alpha.f = 0.2) 

color_GLP1RA <- "#117833" 
fill_GLP1RA <- adjustcolor(color_GLP1RA, alpha.f = 0.2) 

# label data
label_data <- data.frame(
  Cohort = c("SGLT2i", "GLP1RA"),
  Time = c(1000, 1000),  # fixed in x=1000
  Surv = c(
    approx(
      x = plot_data$Time[plot_data$Cohort == "SGLT2i"],
      y = plot_data$Surv[plot_data$Cohort == "SGLT2i"],
      xout = 1000
    )$y,
    approx(
      x = plot_data$Time[plot_data$Cohort == "GLP1RA"],
      y = plot_data$Surv[plot_data$Cohort == "GLP1RA"],
      xout = 1000
    )$y
  )
) %>%
  mutate(
    Surv_offset = ifelse(Cohort == "GLP1RA", Surv - 0.05, Surv + 0.05)
  )

# Create number table
number_table <- data %>%
  filter(Time %in% c(250, 500, 750, 1000)) %>%
  select(Surv1, Surv2) %>%
  `row.names<-`(as.character(c(250, 500, 750, 1000))) %>%
  rbind(data.frame(Surv1 = 1, Surv2 = 1, row.names = "0")) %>%
  slice(c(n(),1:n()-1)) %>%
  mutate(Surv1 = Surv1 * PatientsInSGL, Surv2 = Surv2 * PatientsInGLP) %>%
  mutate(across(everything(), round)) 

Ready_for_plot <- t(number_table) %>%
  as.data.frame(check.names = FALSE) %>%
  rownames_to_column("Drug") %>%
  mutate(Drug = recode(Drug, 
                       "Surv1" = "SGL T2i",
                       "Surv2" = "GLP-1RA")) %>%
  pivot_longer(
    cols = -Drug,
    names_to = "Time",
    values_to = "Value"
  ) %>%
  mutate(Value_num = as.numeric(Value)) %>%
  group_by(Drug) %>%
  mutate(
    Diff = first(Value_num) - Value_num,
    # table format
    Value_formatted = sprintf(
      "%s (%s)", 
      format(Value_num, big.mark = ",", trim = TRUE),  
      format(round(Diff), big.mark = ",", trim = TRUE) 
    )
  ) %>%
  ungroup() %>%
  select(Drug, Time, Value_formatted) %>%
  pivot_wider(
    names_from = Time,
    values_from = Value_formatted
  ) %>%
  column_to_rownames("Drug")

# Main plot----
main_plot <- ggplot(plot_data, aes(x = Time, y = Surv)) +
  geom_ribbon(
    aes(ymin = Lower, ymax = Upper, fill = Cohort), 
    alpha = 0.2, 
    linetype = "dashed",
    size = 0.3,
    color = "gray50"
  ) +
  geom_step(aes(color = Cohort), linewidth = 1.2) +
  
  # y axis scale
  scale_y_continuous(
    limits = c(0.969, 1.0),
    breaks = seq(0.97, 1.0, by = 0.01),  # identify y-axis range
    expand = c(0, 0),
    labels = scales::number_format(accuracy = 0.01)
  ) +
  
  # x axis scale
  scale_x_continuous(
    expand = c(0, 0),
    breaks = function(limits) {
      # ensure 0 exist
      breaks <- unique(c(0, seq(0, max(limits), by = 250)))  # x-axis range: 250days
      breaks[breaks <= max(limits)]  
    }
  ) +
  
  labs(
    x = "Days", 
    y = "Survival Probability",
    title = "KM Curve(Mortality)"
  ) +
  
  scale_color_manual(
    name = NULL,
    values = c("SGLT2i" = color_SGLT2i, "GLP1RA" = color_GLP1RA),
    labels = c("SGLT2i" = "SGLT2i", "GLP1RA" = "GLP-1RA")
  ) +
  scale_fill_manual(
    name = NULL,
    values = c("SGLT2i" = fill_SGLT2i, "GLP1RA" = fill_GLP1RA),
    labels = c("SGLT2i" = "SGLT2i", "GLP1RA" = "GLP-1RA")
  ) +
  
  annotate("text", 
           x = Inf, y = Inf, 
           label = "P = 0.0003", 
           hjust = 1.1, 
           vjust = 1.5,
           size = 5) +
  
  theme_bw(base_size = 14) +
  theme(
    legend.position = c(0.02, 0.02),
    legend.justification = c(0, 0),
    legend.direction = "vertical",
    legend.title = element_blank(),
    legend.key = element_blank(),
    legend.key.size = unit(0.8, "cm"),
    panel.grid = element_blank(),
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.8),
    plot.title = element_text(hjust = 0.5, face = "bold"),
    axis.line = element_blank(),
    # use scale line
    axis.ticks = element_line(color = "black", size = 0.5),  # scale line size
    axis.ticks.length = unit(0.2, "cm"),  # scale line length
    axis.text = element_text(color = "black"),
    axis.text.y = element_text(margin = margin(r = 10)),
    plot.margin = margin(10, 20, 10, 20)
  ) +
  coord_cartesian(clip = "off") +
  
  # show 0 label
  annotate("text", 
           x = 0, y = -Inf, 
           label = "", 
           vjust = 1.5, 
           hjust = 0.5,
           size = 4)

main_plot

# Table plot----
table_data <- as.data.frame(Ready_for_plot)

x_min <- -150
x_max <- 1100
x_breaks <- c(0, 250, 500, 750, 1000)

table_plot <- ggplot() +
  # title
  ggtitle("All-cause mortality") +
  
  scale_x_continuous(
    breaks = x_breaks,
    limits = c(x_min, x_max),
    expand = c(0, 0)
  ) +
  # Data
  annotate("text", 
           x = x_breaks,
           y = 1, 
           label = as.character(table_data["SGL T2i", ]),
           size = 4.5,
           fontface = "bold",
           hjust = 0.5) +
  
  annotate("text", 
           x = x_breaks,
           y = 0, 
           label = as.character(table_data["GLP-1RA", ]),
           size = 4.5,
           fontface = "bold",
           hjust = 0.5) +
  
  # Drug name
  annotate("text",
           x = -100,
           y = 1,
           label = "SGL T2i",
           size = 4.5,
           fontface = "bold",
           hjust = 1) +
  
  annotate("text",
           x = -100,
           y = 0,
           label = "GLP-1RA",
           size = 4.5,
           fontface = "bold",
           hjust = 1) +
  
  # Set y axis limit
  ylim(-0.5, 1.5) +
  
  coord_cartesian(clip = "off") +
  theme_void() +
  theme(
    plot.margin = margin(20, 50, 10, 100),  
    plot.title = element_text(              
      size = 16, 
      face = "bold", 
      hjust = 0, 
      vjust = 1.5,
      margin = margin(b = 3)
    )
  )

table_plot

# Final plot(merge main_plot & table_plot)
final_plot <- (
  # adjust main plot
  main_plot +
    scale_x_continuous(
      breaks = c(0, 250, 500, 750, 1000),
      expand = c(0, 0)
    ) +
    theme(
      plot.margin = margin(0, 20, 0, 50)  # Control margin
    )
) / (
  # adjust table plot
  ggplot() +
    # Table data
    annotate("text", 
             x = c(0, 250, 500, 750, 1000),
             y = 1, 
             label = as.character(table_data["SGL T2i", ]),
             size = 4.5,
             fontface = "bold",
             hjust = 0.5) +
    annotate("text", 
             x = c(0, 250, 500, 750, 1000),
             y = 0, 
             label = as.character(table_data["GLP-1RA", ]),
             size = 4.5,
             fontface = "bold",
             hjust = 0.5) +
    # Drug name
    annotate("text",
             x = -73, 
             y = 1,
             label = "SGLT2i",
             size = 4.5,
             fontface = "bold",
             hjust = 1) +
    annotate("text",
             x = -74,
             y = 0,
             label = "GLP-1RA",
             size = 4.5,
             fontface = "bold",
             hjust = 1) +
    # Table title
    annotate("text",
             x = -160,  
             y = 1.5,    
             label = "All-cause mortality",
             size = 6,
             fontface = "bold",
             hjust = 0) + 
    # Set location
    ylim(-0.5, 1.5) +
    scale_x_continuous(expand = c(0, 0)) +
    coord_cartesian(clip = "off", xlim = c(-20, 1100)) +  # Limit shown region
    theme_void() +
    theme(plot.margin = margin(0, 20, 10, 20))  # balance margin
) + 
  plot_layout(heights = c(3, 1))

# show final result
final_plot

# Output
formats <- c("pdf", "png")
for(fmt in formats) {
  ggsave(paste0("KMFinal_plot_ver2.", fmt),
         plot = final_plot,
         dpi = ifelse(fmt=="png", 1200, 300),
         width=8.8, height=6)
}

今天翻来覆去搞这个图真是耗费心神,今天就这样吧,只有再看看怎么给博客添加图片