1

I'm trying to produce a graph and I'd like to bold part of a string of a geom_text(). Here's some sample data and a graph:

temp <- data.frame(num = c("big"),
                   text = c("small bullet point of text"),
                   col = c("red"))

ggplot(data = temp) +
  lims(x = c(0,100), y = c(0, 100)) + 
  geom_text(aes(x = 20, y = 50, label = num, color = col), size = 25) +
  geom_text(aes(x = 60, y = 50, label = text), size = 3)

enter image description here

There are two thigns I'd like to do, ideally. First, the most important is that I'd like to embolden the word "bullet" and only that word. Second, if possible I'd like to change the color of the word bullet to "red" , to match that of the word "big".

I've read on here solutions involving the bold() function which seems to come from the grDevices package but I can't get that to work. It gives the following error when I try the example in that link:

> paste("No. of ", bold("bacteria X"), " isolates with corresponding types")
Error in bold("bacteria X") : could not find function "bold"

Further, I'd like to be able to call an object from the environment so that I can package this up as a function. I've read about using bquote() here, but obviously I haven't been able to test that since I can't get bold() to work.

So, 1) Why can't I get bold() to work? 2) Is bquote() with bold() the best way to do this? 3) I'd imagine html tags may be an easy way to do this, is there any way to pass a string containing html tags and have ggplot interpert it properly? 4) I don't expect much on the color front as the bold part is what I'm really concerned about, but if you have any suggestions I'll gladly take them. Thanks!

> sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows Server 2008 R2 x64 (build 7601) Service Pack 1

Matrix products: default 

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] tidyr_0.8.1   stringr_1.3.1 scales_0.5.0  readxl_1.1.0  ggplot2_2.2.1 dplyr_0.7.5  

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.17     knitr_1.17       bindr_0.1.1      magrittr_1.5     tidyselect_0.2.3
 [6] munsell_0.4.3    colorspace_1.3-2 R6_2.2.2         rlang_0.2.1      plyr_1.8.4      
[11] tools_3.4.1      grid_3.4.1       gtable_0.2.0     digest_0.6.12    lazyeval_0.2.0  
[16] assertthat_0.2.0 tibble_1.4.2     bindrcpp_0.2.2   reshape2_1.4.2   purrr_0.2.4     
[21] glue_1.2.0       labeling_0.3     stringi_1.1.7    compiler_3.4.1   pillar_1.1.0    
[26] cellranger_1.1.0 pkgconfig_2.0.1 
cparmstrong
  • 799
  • 6
  • 23
  • [This](https://stackoverflow.com/questions/31568453/using-different-font-styles-in-annotate-ggplot2) might be relevant. I haven't seen an easy way to add different colors within the string, though, other than adding things in separate `annotate()` calls. – aosmith Jun 08 '18 at 19:36
  • @aosmith that solution worked for at least getting it to bold the text. I can't seem to get it to call from the environment though. if I do `a <- "boldedword"` and then run it as `paste("this is the ", bold(a), " here")` it gives the same result as the unquoted version `paste("this is the ", bold("a"), " here")`. Any idea how to make it work? – cparmstrong Jun 08 '18 at 20:02

2 Answers2

5

Working with plotmath in ggplot2 confounds me every time, especially when trying to pass in a variable.

I think I got things to work how you want them, complete with one bold word with a separate color passed from a variable. It involves deparse() and bquote() and bold() along with phantom(). Phew.

The phantom() holds the place of the words you don't want to show with the specific color, so it takes two annotate() layers to make the whole expression using different colors.

a = "bullet"
ggplot(mtcars, aes(x = wt, y = mpg)) + 
    annotate("text", x = 4, y = 25, 
             label = deparse(bquote(phantom(small)~bold(.(a))~phantom(point~of~text))),
             colour = "red", parse = TRUE) +
    annotate("text", x = 4, y = 25, 
             label = deparse(bquote(small~phantom(bold(.(a)))~point~of~text)),
             colour = "black", parse = TRUE)

enter image description here

Adding facets

I feel certain there is an easier approach to facets and "a" as a vector but this is what I've come up with on a Friday afternoon. :-D

My approach is to loop through the (character) vector and make a new variable with all the deparsing and bquoting and such. The faceting variable is part of the text dataset.

dat = data.frame(x = c(4, 4),
                 y = c(25, 25),
                 a = c("bullet", "shell"),
                 am = c(0, 1) )

dat$a1 = sapply(as.character(dat$a), 
                       function(x) deparse(bquote(phantom(small)~bold(.(x))~phantom(point~of~text))), 
                simplify = TRUE)
dat$a2 = sapply(as.character(dat$a), 
                       function(x) deparse(bquote(small~phantom(bold(.(x)))~point~of~text)), 
                simplify = TRUE)

ggplot(mtcars, aes(x = wt, y = mpg) ) +
    geom_text(data = dat, aes(x, y, label = a1), color = "red", parse = TRUE) +
    geom_text(data = dat, aes(x, y, label = a2), color = "black", parse = TRUE) +
    facet_wrap(~am)

enter image description here

Working with multiple variables

Last, if you need to get characters pasted together with colors and font style and such using multiple columns in a vector you an do so. My approach involves loping through every row in the dataset, working with the columns that contain the label info. Note I'm working with characters (not factors) to avoid problems.

I pull in the helper function pmap() from package purrr for rowwise work.

If colors need to be different for the highlighted word in each facet you can define the colors in the data.frame and use scale_color_identity to use those colors.

dat = data.frame(x = c(4, 4),
                 y = c(25, 25),
                 a = c("bullet", "shells"),
                 b = c("point of text", "on the beach"),
                 am = c(0, 1),
                 color = c("red", "purple"),
                 stringsAsFactors = FALSE)

library(ggplot2)
library(purrr)

dat$a1 = pmap_chr(dat, function(a, b, ...) 
                deparse(bquote(phantom(small)~bold(.(a))~phantom(.(b))) ) )

dat$a2 = pmap_chr(dat, function(a, b, ...) 
     deparse(bquote(small~phantom(bold(.(a)))~.(b))))

ggplot(mtcars, aes(x = wt, y = mpg) ) +
     geom_text(data = dat, aes(x, y, label = a1, color = color), parse = TRUE) +
     geom_text(data = dat, aes(x, y, label = a2), color = "black", parse = TRUE) +
     facet_wrap(~am) +
     scale_color_identity()

enter image description here

aosmith
  • 34,856
  • 9
  • 84
  • 118
  • This is awesome. I'm going to work with it over the weekend. I'll be back soon with either a question or your check mark. – cparmstrong Jun 08 '18 at 21:11
  • Sidebar: do you know if this works when `a` is a vector? In my actual use case, I'm faceting on a third variable but it seems like `bquote()` doesn't want to produce the output in the way I need it. When I tried to replace `a` in your code with `vs` or `mtcars$vs` it gives the same error: `Error: Aesthetics must be either length 1 or the same as the data (2): label, colour` – cparmstrong Jun 08 '18 at 21:13
  • I've got a feeling there's something useful in here, but I haven't quite figured it out yet. Playing with it to see what might work https://github.com/tidyverse/ggplot2/wiki/Plotmath – cparmstrong Jun 08 '18 at 21:27
  • @seeellayewhy See my edits. But, yes, it seems like there is likely a simpler way out there. – aosmith Jun 08 '18 at 21:36
  • thanks so much for your help. Truly the best support I've ever gotten on here, wish I had more to offer than just a check and a vote! My use case has even more nuances (vectorized non-bolded text as well) so I'm off to figure that part out but I'd have never gotten started without your suggestions. – cparmstrong Jun 08 '18 at 23:48
-1

Try this:

my_text <- expression(paste("small ", bold("bullet"), " point of text"))
ggplot() +
  lims(x = c(0,100), y = c(0, 100)) + 
  annotate('text', x=25, y=25, label=my_text)

enter image description here

thc
  • 9,527
  • 1
  • 24
  • 39
  • I tried it and it gave the following error message: `Error in stats::complete.cases(df[, vars, drop = FALSE]) : invalid 'type' (expression) of argument`. Did a little googling but I can't quite figure out what the issue is. – cparmstrong Jun 08 '18 at 19:37
  • @seeellayewhy Install the latest development version of ggplot (https://github.com/tidyverse/ggplot2). It will work. – thc Jun 08 '18 at 22:34