Search code examples
rggplot2r-haven

automagically using labels (haven semantics) in ggplot2 plots


I'm plotting data marked up using haven semantics, i.e. variables and values have labels defined via attributes.

Often, these labels are also what I want in my axis titles and ticks.

library(ggplot2)
mtcars$mpg = haven::labelled(mtcars$mpg, labels = c("low" = 10, "high" = 30))
attributes(mtcars$mpg)$label = "miles per gallon"
ggplot(mtcars, aes(mpg, cyl)) + geom_point() + 
scale_x_continuous(attributes(mtcars$mpg)$label, 
     breaks = attributes(mtcars$mpg)$labels, 
     labels = names(attributes(mtcars$mpg)$labels))

Could I write a helper that replaces that laborious scale_x_continuous statement with something that can more easily be iterated? E.g. something like scale_x_continuous(label_from_attr, breaks = breaks_from_attr, labels = value_labels_from_attr). Or maybe even + add_labels_from_attributes() to replace the whole thing?

I'm aware that I can write/use helpers like Hmisc::label to slightly shorten the attribute-code above, but that's not what I want here.


Solution

  • I don't have a good scale, but you can use a function like this:

    label_x <- function(p) {
      b <- ggplot_build(p)
      x <- b$plot$data[[b$plot$labels$x]]
      
      p + scale_x_continuous(
        attributes(x)$label, 
        breaks = attributes(x)$labels, 
        labels = names(attributes(x)$labels)
      )
    }
    

    Then use as (+ won't do):

    p <- ggplot(mtcars, aes(mpg, cyl)) + geom_point()
    label_x(p)
    

    Alternatively, use a pipe:

    mtcars %>% { ggplot(., aes(mpg, cyl)) + geom_point() } %>% label_x()
    

    enter image description here


    Old solution

    use_labelled <- function(l, axis = "x") {
        if (axis == "x")  {
            scale_x_continuous(attributes(l)$label, 
                               breaks = attributes(l)$labels, 
                               labels = names(attributes(l)$labels))
        } 
        if (axis == "y") {
            scale_y_continuous(attributes(l)$label, 
                              breaks = attributes(l)$labels, 
                              labels = names(attributes(l)$labels))
        }
    }
    

    Then you just give:

    ggplot(mtcars, aes(mpg, cyl)) + geom_point() + use_labelled(mtcars$cyl)
    

    Or for the y-axis:

    ggplot(mtcars, aes(cyl, mpg)) + geom_point() + use_labelled(mtcars$cyl, "y")