R plots: Is there any way to draw border, shadow or buffer around text labels?

﹥>﹥吖頭↗ 提交于 2019-12-09 09:05:10

问题


I want to plot a label over a line in a monochrome graphic. So I need small white border on each letter of the label.

The border or background of rectangle of the text label is not useful because hide a lot of data plotted.

Is there any way to put border, shadow or buffer around text labels in R plots?

EDIT:

shadowtext <- function(x, y=NULL, labels, col='white', bg='black',
                   theta= seq(pi/4, 2*pi, length.out=8), r=0.1, ... ) {

  xy <- xy.coords(x,y)
  xo <- r*strwidth('x')
  yo <- r*strheight('x')

  for (i in theta) {
    text( xy$x + cos(i)*xo, xy$y + sin(i)*yo, labels, col=bg, ... )
  }
  text(xy$x, xy$y, labels, col=col, ... )
}

pdf(file="test.pdf", width=2, height=2); par(mar=c(0,0,0,0)+.1)
  plot(c(0,1), c(0,1), type="l", lwd=20, axes=FALSE, xlab="", ylab="")
  text(1/6, 1/6, "Test 1")
  text(2/6, 2/6, "Test 2", col="white")
  shadowtext(3/6, 3/6, "Test 3")
  shadowtext(4/6, 4/6, "Test 4", col="black", bg="white")
  shadowtext(5/6, 5/6, "Test 5", col="black", bg="white", theta = seq(pi/4, 2*pi, length.out=24))
dev.off()

The code above use the solution from koekenbakker. This is fine for PNG graphic but I need a different approach for high resolution PDF.


回答1:


You can try this 'shadowtext' function that draws a halo or border around the text by printing it several times with a slight offset in a different colour. All credits to Greg Snow here.

shadowtext <- function(x, y=NULL, labels, col='white', bg='black', 
                       theta= seq(0, 2*pi, length.out=50), r=0.1, ... ) {

    xy <- xy.coords(x,y)
    xo <- r*strwidth('A')
    yo <- r*strheight('A')

    # draw background text with small shift in x and y in background colour
    for (i in theta) {
        text( xy$x + cos(i)*xo, xy$y + sin(i)*yo, labels, col=bg, ... )
    }
    # draw actual text in exact xy position in foreground colour
    text(xy$x, xy$y, labels, col=col, ... )
}

# And here is an example of use:
# pdf(file="test2.pdf", width=2, height=2); par(mar=c(0,0,0,0)+.1)
plot(c(0,1), c(0,1), type="n", lwd=20, axes=FALSE, xlab="", ylab="")

rect(xleft = 0.5, xright = 1, ybottom = 0, ytop = 1, col=1)
text(1/6, 1/6, "Test 1")
shadowtext(2/6, 2/6, "Test 2", col='red', bg="blue")
shadowtext(3/6, 3/6, "Test 3", cex=2)

# `r` controls the width of the border
shadowtext(5/6, 5/6, "Test 4", col="black", bg="white", cex=4, r=0.2)
# dev.off()




回答2:


I needed to do this for a map in R and ended up using the "raster" package to draw halos around text labels.

http://rpackages.ianhowson.com/cran/raster/man/text.html

e.g.,

library(raster)

text(Points, labels = Points$Labels, halo = TRUE, hw = 0.08, hc = "white", cex = 0.8)
# hw = halo width
# hc = halo color




回答3:


The shadowtext package can be used to draw outline or shadow around text for ggplot2 plots.

library(ggplot2)
library(shadowtext)

jet.colors <- colorRampPalette(c("#00007F", "blue", "#007FFF", "cyan", "#7FFF7F", 
                                 "yellow", "#FF7F00", "red", "#7F0000"))

### Note: jet (rainbow) is not color-blind friendly, not perceptually uniform, and can be misleading 
# so please don't use it for your plots
# https://blogs.egu.eu/divisions/gd/2017/08/23/the-rainbow-colour-map/
# https://www.nature.com/articles/519291d
# Choose viridis instead https://cran.r-project.org/web/packages/viridis/vignettes/intro-to-viridis.html
# I only use jet here for the demonstration of the `shadowtext` package.

ggplot(faithfuld, aes(waiting, eruptions)) +
  geom_raster(aes(fill = density)) +
  scale_fill_gradientn(colors = jet.colors(7)) +
  geom_shadowtext(aes(x = 75, y = 4.5),
    label = "White text with black outline\nwill be visible on any background",
    check_overlap = TRUE,
    size = 8) +
  theme_minimal()

Created on 2018-10-14 by the reprex package (v0.2.1.9000)




回答4:


Here is my attempt to add a text buffer when labelling contours (or circles in this example). It's definitely not as effective or pretty as koekenbakker's solution but it served its purpose for me to isolate the text label from the line.

require(shape)
plot(250,250, xlim=c(0,500), ylim=c(0,500), axes=F, ylab="", xlab="", col="black") ## set up the plotting area

circle_radius<-c(200, 150, 50) ## we wan't to draw a few circles which we will label after using our buffer

for (i in 1:length(circle_radius)){
    plotcircle(mid=c(250,250), r=circle_radius[i], lwd=0.5,lcol="grey40") ## iteratively plot the circles

text_buffer<-seq(0.1, 0.7, by=0.01) ## this is the key to the text buffer. Create a vector of values to set the character size (cex) during the following loop

for(j in text_buffer){
    text(x=250+circle_radius[i], 250, print(paste(circle_radius[i],"m")), cex=j, srt=270, col="white") ## write the text buffer in white starting from the smallest value of cex to the largest
}  ## end of loop for writing buffer
    text(x=250+circle_radius[i], 250, print(paste(circle_radius[i],"m")), cex=0.5, srt=270) ## write over the buffer with black text

}  ## end of loop for drawing circles




回答5:


I wrote a similar function for text fields, which also works on logarithmic scales.

install.packages("berryFunctions")
library("berryFunctions")
?textField

This may be considered nicer for vector graphics. Here are some examples:

PS: If you want to contribute: https://github.com/brry/berryFunctions



来源:https://stackoverflow.com/questions/25631216/r-plots-is-there-any-way-to-draw-border-shadow-or-buffer-around-text-labels

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!