ggplot2 - аннотировать за пределами сюжета

Я хотел бы связать значения размера выборки с точками на графике. я могу использовать geom_text расположить числа рядом с точками, но это грязно. Было бы намного чище выстроить их вдоль внешнего края участка.

Например, у меня есть:

df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))

ggplot(df,aes(x=x,y=y,label=n))+geom_point()+geom_text(size=8,hjust=-0.5)

Который производит этот сюжет:

Я бы предпочел что-то вроде этого:

Я знаю, что могу создать второй сюжет и использовать grid.arrange (а-ля этот пост), но было бы утомительно определять интервал textGrobs для выравнивания с осью Y. Есть ли более простой способ сделать это? Спасибо!

5 ответов

Решение

Вам не нужно рисовать второй сюжет. Ты можешь использовать annotation_custom размещать гробов в любом месте внутри или за пределами области печати. Положение гробов в терминах данных координат. Предполагая, что "5", "10", "15" совпадают с "cat1", "cat2", "cat3", позаботится о вертикальном позиционировании textGrobs - y-координаты ваших трех textGrobs задаются Y-координаты трех точек данных. По умолчанию, ggplot2 закрепляет клипы в области построения, но отсечение может быть отменено. Соответствующее поле должно быть расширено, чтобы освободить место для гроба. Следующее (с использованием ggplot2 0.9.2) дает график, похожий на ваш второй график:

library (ggplot2)
library(grid)

df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))

p <- ggplot(df, aes(x,y)) + geom_point() +            # Base plot
     theme(plot.margin = unit(c(1,3,1,1), "lines"))   # Make room for the grob

for (i in 1:length(df$n))  {
p <- p + annotation_custom(
      grob = textGrob(label = df$n[i], hjust = 0, gp = gpar(cex = 1.5)),
      ymin = df$y[i],      # Vertical position of the textGrob
      ymax = df$y[i],
      xmin = 14.3,         # Note: The grobs are positioned outside the plot area
      xmax = 14.3)
 }    

# Code to override clipping
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)

Теперь это просто с ggplot2 3.0.0, так как теперь обрезка может быть отключена на графиках путем вызова coord_cartesian(clip = 'off'), как в примере ниже.

    # Generate data
    df <- data.frame(y=c("cat1","cat2","cat3"),
                     x=c(12,10,14),
                     n=c(5,15,20))

    # Create the plot
    ggplot(df,aes(x=x,y=y,label=n)) +
      geom_point()+
      geom_text(x = 14.25, # Set the position of the text to always be at '14.25'
                hjust = 0,
                size = 8) +
      coord_cartesian(xlim = c(10, 14), # This focuses the x-axis on the range of interest
                      clip = 'off') +   # This keeps the labels from disappearing
      theme(plot.margin = unit(c(1,3,1,1), "lines")) # This widens the right margin

Более простое решение на основе grid

require(grid)

df = data.frame(y = c("cat1", "cat2", "cat3"), x = c(12, 10, 14), n = c(5, 15, 20))

p <- ggplot(df, aes(x, y)) + geom_point() + # Base plot
theme(plot.margin = unit(c(1, 3, 1, 1), "lines"))

p

grid.text("20", x = unit(0.91, "npc"), y = unit(0.80, "npc"))
grid.text("15", x = unit(0.91, "npc"), y = unit(0.56, "npc"))
grid.text("5", x = unit(0.91, "npc"), y = unit(0.31, "npc"))

Другим вариантом может быть использованиеannotateотggplot2что почти то же самое, что и использованиеgeom_text:

      library(ggplot2)
df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))
ggplot(df,aes(x=x,y=y)) + 
  geom_point() + 
  annotate("text", x = max(df$x) + 0.5, y = df$y, label = df$n, size = 8) +
  coord_cartesian(xlim = c(min(df$x), max(df$x)), clip = "off") +
  theme(plot.margin = unit(c(1,3,1,1), "lines"))

Создано 14 августа 2022 г. пакетом reprex (v2.0.1)

Этот конкретный пример может относиться к ggh4x::guide_axis_manual.

      # remotes::install_github("teunbrand/ggh4x")
library(ggplot2)

df <- data.frame(y=c("cat1","cat2","cat3"), x=c(12,10,14), n=c(5,15,20))

ggplot(df, aes(x=x, y=y)) +
  geom_point() +
  guides(y.sec=ggh4x::guide_axis_manual(title = element_blank(), breaks = df$y, labels = paste0("n=",df$n)))

Создано 24 августа 2023 г. с использованием reprex v2.0.2.

Другие вопросы по тегам