[英]How to draw lines outside of plot area in ggplot2?
I created this plot with ggplot2 : 我用ggplot2创建了这个图:
The outside lines need to correspond to the Y scale, (ie the Y position of the lines for Text1 should be 100 and 85). 外部线需要对应于Y比例尺(即Text1的线的Y位置应为100和85)。 The only way I can do it by drawing a blank plot to the right of the figure with the same scale as the barchart and then using annotate function to draw the lines.
我可以做到的唯一方法是在图的右侧绘制一个与条形图相同比例的空白图,然后使用注释功能绘制线条。 Another approach is to simply "manually" draw the lines with
grid.lines
, however the coordinates of grid.lines
will not correspond to the Y scale of the plot. 另一种方法是简单的“手动”绘制线条
grid.lines
,但是坐标grid.lines
将不符合情节的Y规模。
Is it possible to somehow draw these lines using a different approach? 是否可以使用其他方法以某种方式画出这些线? I assume it would have to be done with
grid.lines
. 我认为必须使用
grid.lines
完成。 How could I pass Y coordindates of the barchart to grid.lines
? 如何将条形图的Y坐标传递给
grid.lines
?
Below is the minimal code used to create this figure: 以下是用于创建该图形的最少代码:
library (ggplot2)
test= data.frame(
group=c(rep(1,6), rep(2,6)),
subgroup=c( 1,1,1,2,2,2,1,1,1,2,2,2),
category=c( rep(1:3, 4)),
count=c( 10,80,10,5,90,5, 10,80,10,5,90,5 )
)
qplot(subgroup,
count,
data=test,
geom="bar",
stat="identity",
fill =category,
facets = .~ group, width=0.9)+
opts(legend.position="none",
plot.margin = unit(c(0,9,2,0), "lines"))
How can I draw the lines to the right of the bars? 如何在条形的右边画线?
I recently asked a question about drawing text outside of plot area in ggplot2 and the solution was to use gt$layout
and grid.draw
. 我最近问了一个有关在ggplot2中在绘图区域之外绘制文本的问题,解决方案是使用
gt$layout
和grid.draw
。
Displaying text below the plot generated by ggplot2 在ggplot2生成的绘图下方显示文本
Could the similar approach be used here? 可以在这里使用类似的方法吗? It is my understanding that annotation_custom is for text only and won't work with other graphical elements.
据我了解,annotation_custom仅用于文本,不能与其他图形元素一起使用。 Thanks
谢谢
Update 更新资料
The original solution used annotation_custom
, but a problem with annotation_custom
is that it draws the annotation in all panels. 最初的解决方案中使用
annotation_custom
,但有一个问题annotation_custom
是,它在吸引所有面板的注释。 However, with a simple modification, annotation_custom
can be made to draw in one panel only (taken from Baptiste's answer here ) 然而,简单的修改,
annotation_custom
可制成只有一个面板绘制(从巴蒂斯特的答案采取这里 )
annotation_custom2 <-
function (grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, data)
{
layer(data = data, stat = StatIdentity, position = PositionIdentity,
geom = ggplot2:::GeomCustomAnn,
inherit.aes = TRUE, params = list(grob = grob,
xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax))
}
library(ggplot2)
library(grid)
#Some data
test = data.frame(
group=c(rep(1,6), rep(2,6)),
subgroup=c( 1,1,1,2,2,2,1,1,1,2,2,2),
category=c( rep(1:3, 4)),
count=c( 10,80,10,5,90,5, 10,80,10,5,90,5 )
)
# base plot
p <- ggplot(test) +
geom_bar(aes(subgroup, count, fill = category), stat = "identity") +
facet_grid(. ~ group) +
theme(legend.position = "none",
plot.margin = unit(c(1,5,1,1), "lines"))
# Create the text Grobs
Text1 = textGrob("Text 1")
Text2 = textGrob("Text 2")
Text4 = textGrob("Text 4")
## Add the annotations
# Which panel to attach the annotations
data = data.frame(group=2)
# Text 1
p1 = p + annotation_custom2(Text1, xmin = 3., xmax = 3., ymin = 85, ymax = 100, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 100, ymax = 100, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 85, ymax = 85, data = data) +
annotation_custom2(linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 85, ymax = 100, data = data)
# Text 2
p1 = p1 + annotation_custom2(Text2, xmin = 3, xmax = 3, ymin = 20, ymax = 80, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 80, ymax = 80, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 20, ymax = 20, data = data) +
annotation_custom2(linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 20, ymax = 80, data = data)
# Text 4
p1 = p1 + annotation_custom2(Text4, xmin = 3, xmax = 3, ymin = 0, ymax = 15, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 15, ymax = 15, data = data) +
annotation_custom2(linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 0, ymax = 0, data = data) +
annotation_custom2(linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 0, ymax = 15, data = data)
# Code to override clipping
gt <- ggplotGrob(p1)
gt$layout[grepl("panel", gt$layout$name), ]$clip <- "off"
# Draw the plot
grid.newpage()
grid.draw(gt)
Original Solution 原始解决方案
I think almost any Grob created using grid()
can be used in annotation_custom()
. 我认为几乎所有使用
grid()
创建的Grob都可以在annotation_custom()
。 There might be neater ways to do this, but here's a way using grid
, annotation_custom
and @baptiste's code from here to override the clipping (as in the earlier post). 可能有更巧妙的方法来执行此操作,但是这是从此处使用
grid
, annotation_custom
和@baptiste的代码来覆盖剪切的一种方法(如先前的文章中所述)。
library (ggplot2)
library(grid)
test= data.frame(
group=c(rep(1,6), rep(2,6)),
subgroup=c( 1,1,1,2,2,2,1,1,1,2,2,2),
category=c( rep(1:3, 4)),
count=c( 10,80,10,5,90,5, 10,80,10,5,90,5 )
)
## EDIT: Updated qplot() command
p <- qplot(subgroup, count,
data = test, geom = "bar", stat = "identity",
fill = category,
facets = .~ group, width = 0.9)+
theme(legend.position="none", plot.margin = unit(c(0,9,2,0), "lines"))
# Create the text Grobs
Text1 = textGrob("Text 1")
Text2 = textGrob("Text 2")
Text4 = textGrob("Text 4")
# Draw the plot
# Text 1
p1 = p + annotation_custom(grob = Text1, xmin = 3., xmax = 3., ymin = 85, ymax = 100) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 100, ymax = 100) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 85, ymax = 85) +
annotation_custom(grob = linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 85, ymax = 100)
# Text 2
p1 = p1 + annotation_custom(grob = Text2, xmin = 3, xmax = 3, ymin = 20, ymax = 80) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 80, ymax = 80) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 20, ymax = 20) +
annotation_custom(grob = linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 20, ymax = 80)
# Text 4
p1 = p1 + annotation_custom(grob = Text4, xmin = 3, xmax = 3, ymin = 0, ymax = 15) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 15, ymax = 15) +
annotation_custom(grob = linesGrob(), xmin = 2.6, xmax = 2.75, ymin = 0, ymax = 0) +
annotation_custom(grob = linesGrob(), xmin = 2.75, xmax = 2.75, ymin = 0, ymax = 15)
p1
# Code to override clipping
gt <- ggplot_gtable(ggplot_build(p1))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
Updated opts
has been deprecated; 更新
opts
已弃用; use theme
instead. 改用
theme
。
Here's another solution. 这是另一个解决方案。 It gets round the problem of
annotation_custom()
drawing grobs in both panels. 解决了两个面板中的
annotation_custom()
绘图问题。 It draws two graphs: the first is your bar plot; 它绘制了两个图形:第一个是您的条形图;第二个是您的条形图。 the second contains only the annotations.
第二个仅包含注释。 Then the two are put together using
grid.arrange()
from the gridExtra
package. 然后使用
gridExtra
包中的grid.arrange()
将两者放在一起。 However, your polyline issue remains. 但是,您的折线问题仍然存在。
There is still the issue of getting the y-axis scales the same in the two plots. 在两个图中,仍然存在使y轴比例相同的问题。 But with care, it can be done.
但是只要小心,就可以做到。 In the plot that contains the annnotations, notice how elements that could have an impact on the y-axis scale are not removed (via
theme_blank()
, but rather are hidden (using colour = NA
). 在包含注释的图形中,请注意如何删除不会对y轴比例产生影响的元素(通过
theme_blank()
,而是将其隐藏(使用colour = NA
)。
library(ggplot2)
library(gridExtra)
library(grid)
test= data.frame(
group=c(rep(1,6), rep(2,6)),
subgroup=c( 1,1,1,2,2,2,1,1,1,2,2,2),
category=c( rep(1:3, 4)),
count=c( 10,80,10,5,90,5, 10,80,10,5,90,5))
# The bar plot
p1 <- ggplot(test, aes(subgroup, count, fill = category)) +
geom_bar(stat = "identity") +
facet_grid(.~ group) +
theme(legend.position = "none",
plot.margin = unit(c(1,0,2,0), "lines"))
p1 <- p1 + ylim(0, 100)
# The empty plot to contain the annotations
p2 = ggplot(data.frame(x = c(1,2), y = c(0,100), z = c(1,1)), aes(x,y)) + theme_bw() + facet_wrap(~ z) +
theme(axis.title.y = element_blank(),
axis.title.x = element_text(colour = NA),
axis.text.y = element_blank(),
axis.text.x = element_text(colour = NA),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.ticks = element_line(colour = NA),
panel.border = element_rect(colour = NA),
strip.background = element_rect(colour = NA, fill = NA),
strip.text.x = element_text(colour = NA),
plot.margin = unit(c(1,0,2,0), "lines"))
# The annotations
Text1 = textGrob("Text 1")
Text2 = textGrob("Text 2")
Text4 = textGrob("Text 4")
p2 = p2 + annotation_custom(grob = Text1, xmin = 1.4, xmax = 1.4, ymin = 85, ymax = 100) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 100, ymax = 100) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 85, ymax = 85) +
annotation_custom(grob = linesGrob(), xmin = 1.1, xmax = 1.1, ymin = 85, ymax = 100)
p2 = p2 + annotation_custom(grob = Text2, xmin = 1.4, xmax = 1.4, ymin = 20, ymax = 80) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 80, ymax = 80) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 20, ymax = 20) +
annotation_custom(grob = linesGrob(), xmin = 1.1, xmax = 1.1, ymin = 20, ymax = 80)
p2 = p2 + annotation_custom(grob = Text4, xmin = 1.4, xmax = 1.4, ymin = 0, ymax = 15) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 15, ymax = 15) +
annotation_custom(grob = linesGrob(), xmin = 1, xmax = 1.1, ymin = 0, ymax = 0) +
annotation_custom(grob = linesGrob(), xmin = 1.1, xmax = 1.1, ymin = 0, ymax = 15)
# Putting the two plots together
plot = arrangeGrob(p1, p2, ncol = 2, widths = unit(c(10, 2), c("null", "null")))
grid.draw(plot)
I added the lines/text using code from this link: Using grconvertX/grconvertY in ggplot2 . 我使用以下链接中的代码添加了行/文本: 在ggplot2中使用grconvertX / grconvertY 。 This approach uses grid.text and grid.lines instead of grobs.
这种方法使用grid.text和grid.lines而不是grobs。 I am not sure which approach is better.
我不确定哪种方法更好。
I think grid.lines could be combined into grid.polyline statement or possibly done via a loop. 我认为可以将grid.lines合并为grid.polyline语句,也可以通过循环来完成。 The x and y positions can be set to one variable instead of hardcoding in every line.
可以将x和y位置设置为一个变量,而不是在每一行中进行硬编码。
The only possible complication is passing the scale to the viewport. 唯一可能的麻烦是将比例传递到视口。 However, as long as the the same scale is used in GGPLOT and the viewport this code should work.
但是,只要在GGPLOT和视口中使用相同的比例尺,此代码就应该起作用。 Note that the viewport is using the entire height of the plot as 0 to 100.
请注意,视口将图的整个高度用作0到100。
library (ggplot2)
library(grid)
library(gridBase)
test= data.frame(
group=c(rep(1,6), rep(2,6)),
subgroup=c( 1,1,1,2,2,2,1,1,1,2,2,2),
category=c( rep(1:3, 4)),
count=c( 10,80,10,5,90,5, 10,80,10,5,90,5 )
)
qplot(subgroup, count,
data=test, geom="bar", stat="identity",
fill =category,
facets = .~ group, width=0.9)+
opts(legend.position="none", plot.margin = unit(c(0,9,2,0), "lines"))
current.vpTree()
downViewport('panel-4-6')
pushViewport(dataViewport( yscale=c(0,100), clip='off',xscale=c(0,1)))
grid.text(x=1.21, y = 90, default.units='native' ,label="Text 1")
grid.text(x=1.21, y = 55, default.units='native' ,label="Text 2")
grid.text(x=1.21, y = 10, default.units='native' ,label="Text 3")
grid.lines(x=c(1.02,1.12), y = c(95,95), default.units='native' )
grid.lines(x=c(1.02,1.12), y = c(85, 85), default.units='native' )
grid.lines(x=c(1.12,1.12), y = c(85, 95), default.units='native' )
grid.lines(x=c(1.02,1.12), y = c(80, 80), default.units='native' )
grid.lines(x=c(1.02,1.12), y = c(20, 20), default.units='native' )
grid.lines(x=c(1.12,1.12), y = c(80, 20), default.units='native' )
grid.lines(x=c(1.02,1.12), y = c(5, 5), default.units='native' )
grid.lines(x=c(1.02,1.12), y = c(15, 15), default.units='native' )
grid.lines(x=c(1.12,1.12), y = c(5, 15), default.units='native' )
Apologies for any formatting problems - I simply pasted my code and used the code button to indent it. 对于任何格式问题,我们深表歉意-我只是粘贴了代码,然后使用代码按钮对其进行了缩进。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.