[英]Boxed geom_text with ggplot2
I am developing a graphic with ggplot2 wherein I need to superimpose text over other graphical elements. 我正在用ggplot2开发一个图形,其中我需要在其他图形元素上叠加文本。 Depending on the color of the elements underlying the text, it can be difficult to read the text.
根据文本底层元素的颜色,可能难以阅读文本。 Is there a way to draw geom_text in a bounding box with a semi-transparent background?
有没有办法在具有半透明背景的边界框中绘制geom_text?
I can do this with plotrix: 我可以用plotrix做到这一点:
library(plotrix)
Labels <- c("Alabama", "Alaska", "Arizona", "Arkansas")
SampleFrame <- data.frame(X = 1:10, Y = 1:10)
TextFrame <- data.frame(X = 4:7, Y = 4:7, LAB = Labels)
### plotrix ###
plot(SampleFrame, pch = 20, cex = 20)
boxed.labels(TextFrame$X, TextFrame$Y, TextFrame$LAB,
bg = "#ffffff99", border = FALSE,
xpad = 3/2, ypad = 3/2)
But I do not know of a way to achieve similar results with ggplot2: 但我不知道用ggplot2获得类似结果的方法:
### ggplot2 ###
library(ggplot2)
Plot <- ggplot(data = SampleFrame,
aes(x = X, y = Y)) + geom_point(size = 20)
Plot <- Plot + geom_text(data = TextFrame,
aes(x = X, y = Y, label = LAB))
print(Plot)
As you can see, the black text labels are impossible to perceive where they overlap the black geom_points in the background. 如您所见,黑色文本标签无法感知它们与背景中的黑色geom_points重叠的位置。
Try this geom, which is slightly modified from GeomText. 试试这个geom,稍微修改一下GeomText。
GeomText2 <- proto(GeomText, {
objname <- "text2"
draw <- function(., data, scales, coordinates, ..., parse = FALSE,
expand = 1.2, bgcol = "grey50", bgfill = NA, bgalpha = 1) {
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coordinates$transform(data, scales), {
tg <- do.call("mapply",
c(function(...) {
tg <- with(list(...), textGrob(lab, default.units="native", rot=angle, gp=gpar(fontsize=size * .pt)))
list(w = grobWidth(tg), h = grobHeight(tg))
}, data))
gList(rectGrob(x, y,
width = do.call(unit.c, tg["w",]) * expand,
height = do.call(unit.c, tg["h",]) * expand,
gp = gpar(col = alpha(bgcol, bgalpha), fill = alpha(bgfill, bgalpha))),
.super$draw(., data, scales, coordinates, ..., parse))
})
}
})
geom_text2 <- GeomText2$build_accessor()
Labels <- c("Alabama", "Alaska", "Arizona", "Arkansas")
SampleFrame <- data.frame(X = 1:10, Y = 1:10)
TextFrame <- data.frame(X = 4:7, Y = 4:7, LAB = Labels)
Plot <- ggplot(data = SampleFrame, aes(x = X, y = Y)) + geom_point(size = 20)
Plot <- Plot + geom_text2(data = TextFrame, aes(x = X, y = Y, label = LAB),
size = 5, expand = 1.5, bgcol = "green", bgfill = "skyblue", bgalpha = 0.8)
print(Plot)
BUG FIXED AND CODE IMPROVED BUG固定和代码改进
GeomText2 <- proto(GeomText, {
objname <- "text2"
draw <- function(., data, scales, coordinates, ..., parse = FALSE,
expand = 1.2, bgcol = "grey50", bgfill = NA, bgalpha = 1) {
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coordinates$transform(data, scales), {
sizes <- llply(1:nrow(data),
function(i) with(data[i, ], {
grobs <- textGrob(lab[i], default.units="native", rot=angle, gp=gpar(fontsize=size * .pt))
list(w = grobWidth(grobs), h = grobHeight(grobs))
}))
gList(rectGrob(x, y,
width = do.call(unit.c, lapply(sizes, "[[", "w")) * expand,
height = do.call(unit.c, lapply(sizes, "[[", "h")) * expand,
gp = gpar(col = alpha(bgcol, bgalpha), fill = alpha(bgfill, bgalpha))),
.super$draw(., data, scales, coordinates, ..., parse))
})
}
})
geom_text2 <- GeomText2$build_accessor()
Instead of adding a bounding box, I would suggest changing the text color to white
which can be done by doing 我建议不要添加边界框,而是将文本颜色更改为
white
Plot <- Plot +
geom_text(data = TextFrame, aes(x = X, y = Y, label = LAB), colour = 'white')
The other approach would be to add an alpha
to geom_point
to make it more transparent 另一种方法是在
geom_point
添加alpha
以使其更透明
Plot <- Plot + geom_point(size = 20, alpha = 0.5)
EDIT. 编辑。 Here is a way to generalize Chase's solution to automatically compute the bounding box.
这是一种概括Chase解决方案以自动计算边界框的方法。 The trick is to add the
width
and height
of text directly to the text data frame. 诀窍是将文本的
width
和height
直接添加到文本数据框中。 Here is an example 这是一个例子
Labels <- c("Alabama", "Alaska", "Arizona", "Arkansas",
"Pennsylvania + California")
TextFrame <- data.frame(X = 4:8, Y = 4:8, LAB = Labels)
TextFrame <- transform(TextFrame,
w = strwidth(LAB, 'inches') + 0.25,
h = strheight(LAB, 'inches') + 0.25
)
ggplot(data = SampleFrame,aes(x = X, y = Y)) +
geom_point(size = 20) +
geom_rect(data = TextFrame, aes(xmin = X - w/2, xmax = X + w/2,
ymin = Y - h/2, ymax = Y + h/2), fill = "grey80") +
geom_text(data = TextFrame,aes(x = X, y = Y, label = LAB), size = 4)
In the development version of ggplot2 package there is a new geom called geom_label()
that implements this directly. 在ggplot2包的开发版本中,有一个名为
geom_label()
的新geom直接实现了它。 Transperency can be atchieved with alpha=
parameter. 可以使用
alpha=
参数来实现transperency。
ggplot(data = SampleFrame,
aes(x = X, y = Y)) + geom_point(size = 20)+
geom_label(data = TextFrame,
aes(x = X, y = Y, label = LAB),alpha=0.5)
Update for ggplot2
v0.9 更新
ggplot2
v0.9
library(ggplot2)
library(proto)
btextGrob <- function (label,x = unit(0.5, "npc"), y = unit(0.5, "npc"),
just = "centre", hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE,
default.units = "npc", name = NULL, gp = gpar(), vp = NULL, f=1.5) {
if (!is.unit(x))
x <- unit(x, default.units)
if (!is.unit(y))
y <- unit(y, default.units)
grob(label = label, x = x, y = y, just = just, hjust = hjust,
vjust = vjust, rot = rot, check.overlap = check.overlap,
name = name, gp = gp, vp = vp, cl = "text")
tg <- textGrob(label = label, x = x, y = y, just = just, hjust = hjust,
vjust = vjust, rot = rot, check.overlap = check.overlap)
w <- unit(rep(1, length(label)), "strwidth", as.list(label))
h <- unit(rep(1, length(label)), "strheight", as.list(label))
rg <- rectGrob(x=x, y=y, width=f*w, height=f*h,
gp=gpar(fill="white", alpha=0.3, col=NA))
gTree(children=gList(rg, tg), vp=vp, gp=gp, name=name)
}
GeomText2 <- proto(ggplot2:::GeomText, {
objname <- "text2"
draw <- function(., data, scales, coordinates, ..., parse = FALSE, na.rm = FALSE) {
data <- remove_missing(data, na.rm,
c("x", "y", "label"), name = "geom_text2")
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coord_transform(coordinates, data, scales),
btextGrob(lab, x, y, default.units="native",
hjust=hjust, vjust=vjust, rot=angle,
gp = gpar(col = alpha(colour, alpha), fontsize = size * .pt,
fontfamily = family, fontface = fontface, lineheight = lineheight))
)
}
})
geom_text2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
parse = FALSE, ...) {
GeomText2$new(mapping = mapping, data = data, stat = stat,position = position,
parse = parse, ...)
}
qplot(wt, mpg, data = mtcars, label = rownames(mtcars), size = wt) +
geom_text2(colour = "red")
One option is to add another layer that corresponds to the text layer. 一种选择是添加与文本图层对应的另一个图层。 Since ggplot adds layers sequentially, place a
geom_rect
under the call to geom_text
and it will create the illusion you're after. 由于ggplot按顺序添加图层,因此在
geom_rect
调用下放置一个geom_text
,它会产生你想要的错觉。 This is admittedly a bit of a manual process trying to figure out the appropriate size for the box, but it's the best I can come up with for now. 这无疑是一个手动过程,试图找出盒子的合适尺寸,但这是我现在能想到的最好的。
library(ggplot2)
ggplot(data = SampleFrame,aes(x = X, y = Y)) +
geom_point(size = 20) +
geom_rect(data = TextFrame, aes(xmin = X -.4, xmax = X + .4, ymin = Y - .4, ymax = Y + .4), fill = "grey80") +
geom_text(data = TextFrame,aes(x = X, y = Y, label = LAB), size = 4)
following baptiste v0.9 answer, here's an update with rudimentary control of the box appearance (bgfill, bgalpha, bgcol, expand_w, expand_h): 按照baptiste v0.9回答,这是一个更新,对框外观进行初步控制(bgfill,bgalpha,bgcol,expand_w,expand_h):
btextGrob <- function (label,x = unit(0.5, "npc"), y = unit(0.5, "npc"),
just = "centre", hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE,
default.units = "npc", name = NULL, gp = gpar(), vp = NULL, expand_w, expand_h, box_gp = gpar()) {
if (!is.unit(x))
x <- unit(x, default.units)
if (!is.unit(y))
y <- unit(y, default.units)
grob(label = label, x = x, y = y, just = just, hjust = hjust,
vjust = vjust, rot = rot, check.overlap = check.overlap,
name = name, gp = gp, vp = vp, cl = "text")
tg <- textGrob(label = label, x = x, y = y, just = just, hjust = hjust,
vjust = vjust, rot = rot, check.overlap = check.overlap)
w <- unit(rep(1, length(label)), "strwidth", as.list(label))
h <- unit(rep(1, length(label)), "strheight", as.list(label))
rg <- rectGrob(x=x, y=y, width=expand_w*w, height=expand_h*h,
gp=box_gp)
gTree(children=gList(rg, tg), vp=vp, gp=gp, name=name)
}
GeomTextbox <- proto(ggplot2:::GeomText, {
objname <- "textbox"
draw <- function(., data, scales, coordinates, ..., parse = FALSE, na.rm = FALSE,
expand_w = 1.2, expand_h = 2, bgcol = "grey50", bgfill = "white", bgalpha = 1) {
data <- remove_missing(data, na.rm,
c("x", "y", "label"), name = "geom_textbox")
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coord_transform(coordinates, data, scales),
btextGrob(lab, x, y, default.units="native",
hjust=hjust, vjust=vjust, rot=angle,
gp = gpar(col = alpha(colour, alpha), fontsize = size * .pt,
fontfamily = family, fontface = fontface, lineheight = lineheight),
box_gp = gpar(fill = bgfill, alpha = bgalpha, col = bgcol),
expand_w = expand_w, expand_h = expand_h)
)
}
})
geom_textbox <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
parse = FALSE, ...) {
GeomTextbox$new(mapping = mapping, data = data, stat = stat,position = position,
parse = parse, ...)
}
qplot(wt, mpg, data = mtcars, label = rownames(mtcars), size = wt) +
theme_bw() +
geom_textbox()
Update for ggplot2 1.0.1 更新ggplot2 1.0.1
GeomText2 <- proto(ggplot2:::GeomText, {
objname <- "text2"
draw <- function(., data, scales, coordinates, ..., parse = FALSE, na.rm = FALSE
,hjust = 0.5, vjust = 0.5
,expand = c(1.1,1.2), bgcol = "black", bgfill = "white", bgalpha = 1) {
data <- remove_missing(data, na.rm, c("x", "y", "label"), name = "geom_text")
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coord_transform(coordinates, data, scales),{
sizes <- llply(1:nrow(data),
function(i) with(data[i, ], {
grobs <- textGrob(lab[i], default.units="native", rot=angle, gp=gpar(fontsize=size * .pt))
list(w = grobWidth(grobs), h = grobHeight(grobs))
})
)
w <- do.call(unit.c, lapply(sizes, "[[", "w"))
h <- do.call(unit.c, lapply(sizes, "[[", "h"))
gList(rectGrob(x, y,
width = w * expand[1],
height = h * expand[length(expand)],
just = c(hjust,vjust),
gp = gpar(col = alpha(bgcol, bgalpha), fill = alpha(bgfill, bgalpha))),
.super$draw(., data, scales, coordinates, ..., parse))
})
}
})
geom_text2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",parse = FALSE, ...) {
GeomText2$new(mapping = mapping, data = data, stat = stat, position = position, parse = parse, ...)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.