Отображение текста под графиком, созданным ggplot2
Я пытаюсь отобразить некоторую информацию о данных ниже графика, созданного в ggplot2. Я хотел бы построить переменную N, используя координату оси X графика, но координата Y должна быть 10% от нижней части экрана. Фактически, желаемые координаты Y уже находятся в кадре данных как переменная y_pos.
Я могу думать о 3 подходах, используя ggplot2:
1) Создайте пустой сюжет ниже фактического графика, используйте тот же масштаб, а затем используйте geom_text для построения данных по пустому графику. Этот подход работает, но чрезвычайно сложный.
2) Используйте geom_text
для построения данных, но как-то используйте координату y в процентах от экрана (10%). Это заставит цифры отображаться ниже графика. Я не могу понять правильный синтаксис.
3) Используйте grid.text для отображения текста. Я могу легко установить его на 10% от нижней части экрана, но я не могу понять, как настроить координацию X в соответствии с графиком. Я попытался использовать grconvert, чтобы захватить начальную позицию X, но не смог заставить это работать.
Ниже приведен базовый график с фиктивными данными:
graphics.off() # close graphics windows
library(car)
library(ggplot2) #load ggplot
library(gridExtra) #load Grid
library(RGraphics) # support of the "R graphics" book, on CRAN
#create dummy data
test= data.frame(
Group = c("A", "B", "A","B", "A", "B"),
x = c(1 ,1,2,2,3,3 ),
y = c(33,25,27,36,43,25),
n=c(71,55,65,58,65,58),
y_pos=c(9,6,9,6,9,6)
)
#create ggplot
p1 <- qplot(x, y, data=test, colour=Group) +
ylab("Mean change from baseline") +
geom_line()+
scale_x_continuous("Weeks", breaks=seq(-1,3, by = 1) ) +
opts(
legend.position=c(.1,0.9))
#display plot
p1
Модифицированный gplot внизу отображает числа предметов, однако они отображаются в разделе "Сюжет". Они заставляют масштаб Y масштабироваться. Я бы хотел показать эти цифры НИЖЕ сюжета.
p1 <- qplot(x, y, data=test, colour=Group) +
ylab("Mean change from baseline") +
geom_line()+
scale_x_continuous("Weeks", breaks=seq(-1,3, by = 1) ) +
opts( plot.margin = unit(c(0,2,2,1), "lines"),
legend.position=c(.1,0.9))+
geom_text(data = test,aes(x=x,y=y_pos,label=n))
p1
Другой подход отображения чисел включает в себя создание фиктивного участка ниже фактического графика. Вот код:
graphics.off() # close graphics windows
library(car)
library(ggplot2) #load ggplot
library(gridExtra) #load Grid
library(RGraphics) # support of the "R graphics" book, on CRAN
#create dummy data
test= data.frame(
group = c("A", "B", "A","B", "A", "B"),
x = c(1 ,1,2,2,3,3 ),
y = c(33,25,27,36,43,25),
n=c(71,55,65,58,65,58),
y_pos=c(15,6,15,6,15,6)
)
p1 <- qplot(x, y, data=test, colour=group) +
ylab("Mean change from baseline") +
opts(plot.margin = unit(c(1,2,-1,1), "lines")) +
geom_line()+
scale_x_continuous("Weeks", breaks=seq(-1,3, by = 1) ) +
opts(legend.position="bottom",
legend.title=theme_blank(),
title.text="Line plot using GGPLOT")
p1
p2 <- qplot(x, y, data=test, geom="blank")+
ylab(" ")+
opts( plot.margin = unit(c(0,2,-2,1), "lines"),
axis.line = theme_blank(),
axis.ticks = theme_segment(colour = "white"),
axis.text.x=theme_text(angle=-90,colour="white"),
axis.text.y=theme_text(angle=-90,colour="white"),
panel.background = theme_rect(fill = "transparent",colour = NA),
panel.grid.minor = theme_blank(),
panel.grid.major = theme_blank()
)+
geom_text(data = test,aes(x=x,y=y_pos,label=n))
p2
grid.arrange(p1, p2, heights = c(8.5, 1.5), nrow=2 )
enter code here
Однако это очень сложно и будет трудно модифицировать для разных данных. В идеале я хотел бы передать координаты Y в процентах от экрана.
Спасибо заранее!
Ответы
Ответ 1
Отредактировано opts
устарело, заменено на theme
; element_blank
заменил theme_blank
; и ggtitle()
используется вместо opts(title = ...
Сэнди - большое вам спасибо!!!! Это делает именно то, что я хочу. Я бы хотел, чтобы мы могли контролировать обрезку в geom.text или geom.annotate.
Я собрал следующую программу, если кому-то еще интересно.
rm(list = ls()) # clear objects
graphics.off() # close graphics windows
library(ggplot2)
library(gridExtra)
#create dummy data
test= data.frame(
group = c("Group 1", "Group 1", "Group 1","Group 2", "Group 2", "Group 2"),
x = c(1 ,2,3,1,2,3 ),
y = c(33,25,27,36,23,25),
n=c(71,55,65,58,65,58),
ypos=c(18,18,18,17,17,17)
)
p1 <- qplot(x=x, y=y, data=test, colour=group) +
ylab("Mean change from baseline") +
theme(plot.margin = unit(c(1,3,8,1), "lines")) +
geom_line()+
scale_x_continuous("Visits", breaks=seq(-1,3) ) +
theme(legend.position="bottom",
legend.title=element_blank())+
ggtitle("Line plot")
# Create the textGrobs
for (ii in 1:nrow(test))
{
#display numbers at each visit
p1=p1+ annotation_custom(grob = textGrob(test$n[ii]),
xmin = test$x[ii],
xmax = test$x[ii],
ymin = test$ypos[ii],
ymax = test$ypos[ii])
#display group text
if (ii %in% c(1,4)) #there is probably a better way
{
p1=p1+ annotation_custom(grob = textGrob(test$group[ii]),
xmin = 0.85,
xmax = 0.85,
ymin = test$ypos[ii],
ymax = test$ypos[ii])
}
}
# Code to override clipping
gt <- ggplot_gtable(ggplot_build(p1))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
![enter image description here]()
Ответ 2
Обновлено opts()
заменено на theme()
В приведенном ниже коде строится базовый график с более широким полем в нижней части графика. TextGrob создается, затем вставляется в график с помощью annotation_custom(). За исключением того, что текст не отображается, потому что он находится за пределами панели сюжета - вывод подрезается к панели. Но используя baptiste code здесь, обрезание может быть отменено. Позиция относится к единицам данных, и обе текстовые метки центрированы.
library(ggplot2)
library(grid)
# Base plot
df = data.frame(x=seq(1:10), y = seq(1:10))
p = ggplot(data = df, aes(x = x, y = y)) + geom_point() + ylim(0,10) +
theme(plot.margin = unit(c(1,1,3,1), "cm"))
p
# Create the textGrobs
Text1 = textGrob(paste("Largest x-value is", round(max(df$x), 2), sep = " "))
Text2 = textGrob(paste("Mean = ", mean(df$x), sep = ""))
p1 = p + annotation_custom(grob = Text1, xmin = 4, xmax = 4, ymin = -3, ymax = -3) +
annotation_custom(grob = Text2, xmin = 8, xmax = 8, ymin = -3, ymax = -3)
p1
# Code to override clipping
gt <- ggplotGrob(p1)
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
![enter image description here]()
Или, используя grid
функции для создания и размещения метки.
p
grid.text((paste("Largest x-value is", max(df$x), sep = " ")),
x = unit(.2, "npc"), y = unit(.1, "npc"), just = c("left", "bottom"),
gp = gpar(fontface = "bold", fontsize = 18, col = "blue"))
![enter image description here]()
Edit
Или добавьте текст grob, используя функции gtable.
library(ggplot2)
library(grid)
library(gtable)
# Base plot
df = data.frame(x=seq(1:10), y = seq(1:10))
p = ggplot(data = df, aes(x = x, y = y)) + geom_point() + ylim(0,10)
# Construct the text grob
lab = textGrob((paste("Largest x-value is", max(df$x), sep = " ")),
x = unit(.1, "npc"), just = c("left"),
gp = gpar(fontface = "bold", fontsize = 18, col = "blue"))
gp = ggplotGrob(p)
# Add a row below the 2nd from the bottom
gp = gtable_add_rows(gp, unit(2, "grobheight", lab), -2)
# Add 'lab' grob to that row, under the plot panel
gp = gtable_add_grob(gp, lab, t = -2, l = gp$layout[gp$layout$name == "panel",]$l)
grid.newpage()
grid.draw(gp)
![введите описание изображения здесь]()
Ответ 3
Текущая версия ( > 2.1) имеет + labs(caption = "text")
, которая отображает аннотацию ниже графика. Это тема (свойства шрифта,... выравнивание влево/вправо). Для примера см. https://github.com/hadley/ggplot2/pull/1582.
Ответ 4
На самом деле лучшим ответом и самым простым решением является использование пакета cowplot.
Версия 0.5.0 пакета cowplot (на CRAN) обрабатывает субтитры ggplot2 с помощью функции add_sub.
Используйте его так:
diamondsCubed <-ggplot(aes(carat, price), data = diamonds) +
geom_point() +
scale_x_continuous(trans = cuberoot_trans(), limits = c(0.2, 3),
breaks = c(0.2, 0.5, 1, 2, 3)) +
scale_y_continuous(trans = log10_trans(), limits = c(350, 15000),
breaks = c(350, 1000, 5000, 10000, 15000)) +
ggtitle('Price log10 by Cube-Root of Carat') +
theme_xkcd()
ggdraw(add_sub(diamondsCubed, "This is an annotation.\nAnnotations can span multiple lines."))