Аннотировать ggplot с дополнительным тиком и меткой

Можете ли вы помочь мне аннотировать диаграмму рассеяния ggplot2?

К типичной диаграмме рассеяния (черный):

df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))
ggplot(df, aes(x=x, y=y)) + geom_point()

Я хочу добавить аннотации в виде дополнительного тика и пользовательской метки (красный):

Пример изображения:

enter image description here

Ответ 1

Четыре решения.

Первый использует scale_x_continuous для добавления дополнительного элемента, а затем использует theme для настройки нового текста и отметки (плюс некоторые дополнительные настройки).

Второй использует annotate_custom для создания новых гномов: текстового grob и линейного grob. Расположение гномов находится в координатах данных. Следствием этого является то, что позиционирование grob изменится, если границы оси y изменятся. Следовательно, ось y фиксирована в приведенном ниже примере. Кроме того, annotation_custom пытается построить за пределами панели сюжета. По умолчанию обрезание панели графика включено. Его нужно отключить.

Третий вариант - второй вариант (и рисует код из здесь). Система координат по умолчанию для grobs - это "npc", поэтому поместите grobs вертикально во время построения грызунов. Позиционирование грызунов с использованием annotation_custom использует координаты данных, поэтому поместите глыбы горизонтально в annotation_custom. Таким образом, в отличие от второго решения, расположение грыз в этом решении не зависит от диапазона значений y.

Четвертый использует viewports. Он устанавливает более удобную систему единиц для поиска текста и отметки. В направлении x местоположение использует координаты данных; в направлении y, в местоположении используются "npc" координаты. Таким образом, в этом решении позиционирование гномов не зависит от диапазона значений y.

Первое решение

## scale_x_continuous then adjust colour for additional element 
## in the x-axis text and ticks
library(ggplot2)
df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))

p = ggplot(df, aes(x=x, y=y)) + geom_point() + 
  scale_x_continuous(breaks = c(0,25,30,50,75,100), labels = c("0","25","xyz","50","75","100")) +
  theme(axis.text.x = element_text(color = c("black", "black", "red", "black", "black", "black")),
        axis.ticks.x = element_line(color = c("black", "black", "red", "black", "black", "black"),
                          size = c(.5,.5,1,.5,.5,.5)))

# y-axis to match x-axis
p = p + theme(axis.text.y = element_text(color = "black"),
        axis.ticks.y = element_line(color = "black"))

# Remove the extra grid line
p = p + theme(panel.grid.minor = element_blank(),
              panel.grid.major.x = element_line(color = c("white", "white", NA, "white", "white", "white")))
p

enter image description here

Второе решение

## annotation_custom then turn off clipping
library(ggplot2)
library(grid)
df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))

p = ggplot(df, aes(x=x, y=y)) + geom_point() + 
 scale_y_continuous(limits = c(0, 4)) +
 annotation_custom(textGrob("xyz", gp = gpar(col = "red")), 
        xmin=30, xmax=30,ymin=-.4, ymax=-.4) +
 annotation_custom(segmentsGrob(gp = gpar(col = "red", lwd = 2)), 
        xmin=30, xmax=30,ymin=-.25, ymax=-.15)

g = ggplotGrob(p)
g$layout$clip[g$layout$name=="panel"] <- "off"
grid.draw(g)

enter image description here

Третье решение

library(ggplot2)
library(grid)
df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))

p = ggplot(df, aes(x=x, y=y)) + geom_point() 

gtext = textGrob("xyz", y = -.05, gp = gpar(col = "red"))
gline = linesGrob(y = c(-.02, .02),  gp = gpar(col = "red", lwd = 2)) 

p = p + annotation_custom(gtext, xmin=30, xmax=30, ymin=-Inf, ymax=Inf) +
        annotation_custom(gline, xmin=30, xmax=30, ymin=-Inf, ymax=Inf)

g = ggplotGrob(p)
g$layout$clip[g$layout$name=="panel"] <- "off"
grid.draw(g)

введите описание изображения здесь

Четвертое решение

Обновлено до ggplot2 v2.2.0

## Viewports
library(ggplot2)
library(grid)
df <- data.frame(x=seq(1:100), y=sort(rexp(100, 2), decreasing = T))

(p = ggplot(df, aes(x=x, y=y)) + geom_point())


# Search for the plot panel using regular expressions
Tree = as.character(current.vpTree())
pos = gregexpr("\\[panel.*?\\]", Tree)
match = unlist(regmatches(Tree, pos))
match = gsub("^\\[(panel.*?)\\]$", "\\1", match) # remove square brackets
downViewport(match)

#######
# Or find the plot panel yourself
#  current.vpTree() # Find the plot panel
#  downViewport("panel.6-4-6-4")
#####

# Get the limits of the ggplot x-scale, including the expansion.
x.axis.limits = ggplot_build(p)$layout$panel_ranges[[1]][["x.range"]]

# Set up units in the plot panel so that the x-axis units are, in effect, "native",
# but y-axis units are, in effect, "npc".
pushViewport(dataViewport(yscale = c(0, 1), xscale = x.axis.limits, clip = "off"))
grid.text("xyz", x = 30, y = -.05, just = "center", gp = gpar(col = "red"), default.units = "native")
grid.lines(x = 30, y = c(.02, -.02), gp = gpar(col = "red", lwd = 2), default.units = "native") 

upViewport(0)

enter image description here

Ответ 2

Ниже вы получите ярлык xyz и строку над ним, вам может понадобиться играть с позицией x и y для обоих, чтобы получить ее именно там, где вы хотите.

ggplot(df, aes(x=x, y=y)) + geom_point() + annotate(x=27, y=0, label="xyz", color="red") +annotate(x=27, ymin=-1, ymax=1, color="red")

Подробнее здесь при необходимости.