8

I often work with dataframes with "R-friendly"/"programmer-friendly" column names, typically with no spaces, and/or abbreviated (lazy to type the full names when doing the analysis). For example:

ir <- data.frame(
   sp=iris$Species,
   sep.len=iris$Sepal.Length,
   sep.wid=iris$Sepal.Width,
   pet.len=iris$Petal.Length,
   pet.wid=iris$Petal.Width
)

When I plot these with ggplot I often want to replace the labels with "user-friendly" column names, e.g.

p <- ggplot(ir, aes(x=sep.len, y=sep.wid, col=sp)) + geom_point() +
  xlab("sepal length") + ylab("sepal width") + 
  scale_color_discrete("species")

Question: Is there some way to specify label mappings to pass into ggplot ?

lazy.labels <- c(
  sp     ='species',
  sep.len='sepal length',
  sep.wid='sepal width',
  pet.len='petal length',
  pet.wid='petal width'
)

And do something like

p + labs(lazy.labels)

or even

p + xlab(lazy.labels[..x..]) + ylab(lazy.labels[..y..])

where ..x.., ..y.. is some automagic ggplot variable holding the name of the current X/Y variable? (then I can put these annotations into a convenience function without having to change them for each graph)

This is particularly useful when I make many plots in reports. I can always rename ir with the "user-friendly" columns, but then I have to do a lot of

ggplot(ir, aes(x=`sepal length`, y=`sepal width`, ...

which is a bit cumbersome because of all the spaces.

mathematical.coffee
  • 55,977
  • 11
  • 154
  • 194
  • Is this something you're looking for https://stackoverflow.com/a/49943976/786542 – Tung Jul 09 '18 at 05:49
  • Few more: https://stackoverflow.com/a/50930640/786542 & https://stackoverflow.com/a/50522928/786542 – Tung Jul 09 '18 at 05:50
  • @Tung that's a similar but not the same issue - that's to do with saving the variable name like `x.var <- 'sep.len'` and having ggplot interpret the variable name correctly as `sep.len` not `x.var` (`aes_string` can solve that problem for me). – mathematical.coffee Jul 09 '18 at 22:25
  • I want to change the title to say “axis/variable titles” instead of “labels”. Yes, the `labs()` function implies that “labels” is an appropriate word choice, but that function is probably not how most users are introduced to this graph component. When using `scale_*()`, the relevant argument is `name`, while the `labels` argument instead chooses labels for the breaks. When using `theme()`, the relevant argument is `axis.title.*`. I think it is best to use the terminology from `theme()` because it has a set of unique arguments corresponding to a nearly-exhaustive set of graph components. – randy Jan 19 '22 at 23:04

2 Answers2

6

I digged into the ggplot object and came up with this: the benefit is that you do not need to know the mapping in advance

library(ggplot2)

ir <- data.frame(
  sp = iris$Species,
  sep.len = iris$Sepal.Length,
  sep.wid = iris$Sepal.Width,
  pet.len = iris$Petal.Length,
  pet.wid = iris$Petal.Width
)

p <- ggplot(ir, aes(x=sep.len, y=sep.wid, col=sp)) +
     geom_point() +
     scale_color_discrete("species")


## for lazy labels

lazy.labels <- c(
  sp     ='species',
  sep.len='sepal length',
  sep.wid='sepal width',
  pet.len='petal length',
  pet.wid='petal width'
)

p$labels <-lapply(p$labels,function(x){as.character(lazy.labels[x])})

Or, using a function:

plot_with_labels <- function(p, l) {
  p$labels <- lapply(p$labels, function(x) { as.character(l[x]) } )
  return(p)
}

plot_with_labels(p, lazy.labels)
Axeman
  • 32,068
  • 8
  • 81
  • 94
TC Zhang
  • 2,757
  • 1
  • 13
  • 19
  • Aha, `p$labels`! Thanks very much! – mathematical.coffee Jul 09 '18 at 22:19
  • as of ggplot2 3.3.5, the function above sets to `NA` labels with the `fallback` attribute. This fixes that: `plot_with_labels_mod <- function(p, l) { swap <- function(x) { if (is.null(attr(x, "fallback"))) { as.character(l[x]) } else { x } } p$labels <- lapply(p$labels, swap) return(p) }` – tiptoebull Oct 29 '21 at 19:01
1

One solution if your graph are always the same is to create labels in advance using a list mapping aesthetics to your new names to replace the default one. Then you can use labs(lazy.labels).

ir <- data.frame(
  sp = iris$Species,
  sep.len = iris$Sepal.Length,
  sep.wid = iris$Sepal.Width,
  pet.len = iris$Petal.Length,
  pet.wid = iris$Petal.Width
)
library(ggplot2)
# mapping aesthetics names to labels
lazy.labels <- list(
  col = 'species',
  x = 'sepal length',
  y ='sepal width'
)
p <- ggplot(ir, aes(x = sep.len, y = sep.wid, col = sp)) + 
  geom_point() +
  labs(lazy.labels)

Created on 2018-07-09 by the reprex package (v0.2.0).

cderv
  • 6,272
  • 1
  • 21
  • 31
  • Thanks! Unfortunately I do not know my labels in advance - I typically will make a lot of plots to explore various effects with different X, Y, colour – mathematical.coffee Jul 09 '18 at 22:19