Вторичные метки оси X для размера выборки с ggplot2 на R - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь скопировать следующий график, который я сделал в Excel, с ggplot2 в R:

Sample

Я могу успешно создать линии с geom_line (), метки с geom_text () / некоторыми ручными настройками и ось y. Найдите мой код ниже:

library(readxl)
library(ggplot2)

somedata <- read_excel("somedata.xlsx")
somedata[,c(3:6)] <- somedata[,c(3:6)] * 100
somedata[,6] <- somedata[,6] + 25 

somegraph <- ggplot(data = somedata, aes(x = date))
somegraph + 
  geom_point(aes(y = eligible_main), shape = 15, size = 4) + 
  geom_line(aes(y = eligible_main)) + 
  geom_line(aes(y = eligible_center), size = 2) + 
  geom_line(aes(y = eligible_upper), linetype = 2) + 
  geom_line(aes(y = eligible_lower), linetype = 2) + 
  scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 10), labels = paste0(seq(0, 100, 10), "%")) + 
  labs(title = "Title", x = "Time", y = "Percentage") + theme_classic() + 
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 90, hjust = 1))

Для справки, вот некоторые поддельные данные, которые я создал в том же формате, что и данные, которые я строю на графике. Вы можете вставить его в R и запустить мой код выше в консоли: http://s000.tinyupload.com/?file_id=43876540434394267818

Но мне очень трудно создать вторичные метки размера выборки на Ось X в той же ориентации . Есть ли простое решение для этого в ggplot2 или с другим пакетом? Кроме того, могу ли я добавить строки аннотаций на график, чтобы указать на вещи после завершения?

Большое спасибо!

1 Ответ

0 голосов
/ 01 мая 2020

У меня есть решение, которое может помочь. Мне не удалось получить данные, которыми вы поделились, я создал свой собственный фиктивный набор данных следующим образом:

set.seed(12345)
library(lubridate)

df <- data.frame(
  dates=as.Date('2020-03-01')+days(0:9),
  y_vals=rnorm(10, 50,7),
  n=100
)

Сначала базовый сюжет c:

library(scales)
library(ggrepel)    
p.basic <- ggplot(df, aes(dates, y_vals)) +
        geom_line() +
        geom_point(size=2.5, shape=15) +
        geom_text_repel(
            aes(label=paste0(round(y_vals, 1), '%')),
            size=3, direction='y', force=7) +
        ylim(0,100) +
        scale_x_date(breaks=date_breaks('day'), labels=date_format('%b %d')) +
        theme_bw()

enter image description here

Обратите внимание, что мой код немного отличается от вашего. Текстовые метки отбрасываются с помощью пакета ggrepel. Я также использую некоторые функции из scales для исправления и установки форматирования оси даты (обратите внимание также, что lubridate - это пакет, используемый для создания дат в наборе фиктивных данных выше). В противном случае, довольно стандартные ggplot вещи там.

Для текста вне оси, лучший способ сделать это - через пользовательскую аннотацию, где вы должны настроить grob. Подход здесь следующий:

  • Переместите ось «вниз», чтобы освободить место для дополнительного текста. Мы делаем это путем установки поля в верхней части заголовка оси.

  • Отключение отсечения с помощью coord_cartesian(clip='off'). Это необходимо для того, чтобы увидеть аннотации за пределами графика, позволяя рисовать объекты вне области графика.

  • L oop через значения df$n, чтобы создать отдельный annotation_custom объект, добавленный на график через for l oop.

Вот код:

p <- p.basic +
    theme(axis.title.x = element_text(margin=margin(50,0,0,0))) +
    coord_cartesian(clip='off')

for (i in 1:length(df$n)) {
  p <- p + annotation_custom(
    textGrob(
      label=paste0('n=',df$n[i]), rot=90, gp=gpar(fontsize=9)),
      xmin=df$dates[i], xmax=df$dates[i], ymin=-25, ymax=-15
    )
}
p

enter image description here

Дополнительные параметры для большего удовольствия

Еще две вещи, которые нужно добавить: аннотации (например, выноски для заданных c точек + текст) и линии под графиком между метка оси.

Для линий ниже оси: Вы можете довольно просто добавить breaks= к другим осям с помощью scale_... и параметра breaks=; однако для оси даты это ... сложно. Вот почему мы просто добавим строки, используя тот же метод, что и выше, для текста под осью. Идея здесь состоит в том, чтобы разбить ось на sub.div сегментов в приведенном ниже коде, который основан на том, сколько дискретных значений находится на вашей оси x. Я мог бы сделать это in-line несколько раз ... но сначала интересно создать переменную:

sub.div <- 1/length(df$n)

Затем я использую это для создания линий, аннотируя отдельные строки вдоль шага sub.div*i снова используя for l oop:

for (i in 1:(length(df$n)-1)) {
  p <- p + annotation_custom(
    linesGrob(
      x=unit(c(sub.div*i,sub.div*i), 'npc'),
      y=unit(c(0,-0.2), 'npc')   # length of the line below axis
    )
  )
}

enter image description here

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

Аннотации (со стрелками, почему бы и нет?): Есть много способов сделать аннотации. Некоторые из них описаны здесь с использованием функции annotate(). Как и здесь . Вы можете использовать annotate(), если у вас sh, но в этом примере я просто собираюсь использовать geom_label для текстовых меток и geom_curve для создания пышных стрелок.

Вы можете вручную передать отдельные значения aes() через вызов обеих функций для каждой аннотации. Например, geom_text(aes(x=as.Date('2020-03-01'), y=55,..., но если у вас есть несколько в вашем наборе данных, было бы целесообразно установить аннотации на основе информации в самом кадре данных. Сначала я сделаю это здесь, где мы отметим две точки:

df$notes <- c('','','','Wow!','','','OMG!!!','','','')

Вы можете использовать значение df$notes, чтобы указать, какая из точек помечается, а также воспользоваться преимуществами отображение значений x и y в одном и том же наборе данных.

Затем вам просто нужно добавить два geom к вашему графику, изменив их по мере того, как вы sh подгоняетесь под свою эстетику.

p <- p + geom_curve(
    data=df[which(df$notes!=''),],
    mapping=aes(x=dates+0.5, xend=dates, y=y_vals+20, yend=y_vals+2),
    color='red', curvature = 0.5,
    arrow=arrow(length=unit(5,'pt'))
  ) +
  geom_label(
    data=df[which(df$notes!=''),],
    aes(y=y_vals+20, label=notes),
    size=4, color='red', hjust=0
  )

enter image description here

Последнее: горизонтальные линии Последнее, что я заметил в вашем коде ранее, но забыл указать, это чтобы сделать горизонтальные линии, просто используйте geom_hline. Это намного проще. Кроме того, вы можете сделать это за два вызова geom_hline довольно легко (и даже всего за один вызов, если вы хотите передать фрейм данных в функцию):

p <- p + geom_hline(yintercept = 50, size=2, color='gray30') +
  geom_hline(yintercept = c(25,75), linetype=2, color='gray30')

Просто обратите внимание, что желательно добавить эти два geom_hline звонка до geom_line или geom_point в исходном сюжете p.basic, поэтому они отстают от всего остального.

enter image description here

...