---
layout: post
title:  "Automatic units in axis labels"
date:  "Sep 29, 2016; updated Dec 2, 2016"
comments: true
author: Edzer Pebesma
categories: r
---

TOC

This blog post concerns the development version of units, installed by
```{r eval=FALSE}
devtools::install_github("edzer/units")
```

[DOWNLOADHERE]

Have you ever tried to properly add measurement units to R plots? It might go like this:

```{r fig=TRUE, fig.path = "images/", label="plot-units1"}
xlab = parse(text = "temperature ~~ group('[', degree * C, ']')")
ylab = parse(text = "speed ~~ group('[', m * ~~ s^-1, ']')")
par(mar = par("mar") + c(0, .3, 0, 0)) # avoids cutting of superscript
plot(3 + 1:10 + 2 * rnorm(10), xlab = xlab, ylab = ylab)
```

The main observation is, of course that _it can be done_. However, 

* it looks geeky, and not quite intuitive
* you would typically postpone this work to just before submitting the paper, or during review
* you need this so infrequently that you tend to forget how it works.

Although well-written help is found in `?plotmath`, all three observations cause frustration.

The [original paper](http://www.stat.washington.edu/fritz/DATAFILES498B2008/MathinR.pdf) desribing `plotmath` is by Paul Murrell and Ross Ihaka. [R core](https://www.r-project.org/contributors.html) member Paul Murrell also wrote package `grid`, part of base R. Few people use it directly, but without it [ggplot2](https://cran.r-project.org/package=ggplot2) or [lattice](https://cran.r-project.org/package=lattice) could not exist.

## Automatic unit handling

The new [units](https://cran.r-project.org/package=units) CRAN package now makes working with units

* easier
* automatic, and
* less error-prone

Here is an example using `mtcars`. First, we specify the imperial units to those known in the [udunits2](https://www.unidata.ucar.edu/software/udunits/udunits-2.2.20/doc/udunits/udunits2.html#Database) database:

```{r}
library(units)
gallon = make_unit("gallon")
consumption = mtcars$mpg * with(ud_units, mi/gallon)
displacement = mtcars$disp * ud_units[["in"]]^3
```

For `displacement`, we cannot use the normal lookup in the database

```{r eval=FALSE}
displacement = mtcars$disp * with(ud_units, in)
```

because `in` (inch) is also a reserved word in R.

We convert these values to SI units by

```{r}
units(displacement) = with(ud_units, cm^3)
units(consumption) = with(ud_units, km/l)
consumption[1:5]
```

## Automatic measurement units in axis labels

We can plot these numeric variabes of type `units` by
```{r fig=TRUE, fig.path = "images/", label="plot-units2"}
par(mar = par("mar") + c(0, .1, 0, 0)) # avoids cutting of brackets at lhs
plot(displacement, consumption)
```

The units automatically appear in axis labels! If we want to have
negative power instead of division bars, we can set a global option

```{r}
units_options(negative_power = TRUE) # division becomes ^-1
```

Expressions such as
```{r}
1/displacement [1:10]
```

automatically convert units, which also happens in plots (note the converted units symbols):

```{r fig=TRUE, fig.path = "images/", label="plot-units3"}
par(mar = par("mar") + c(0, .3, 0, 0))
plot(1/displacement, 1/consumption)
```

## How to do this with ggplot?

We can of course plot these data by dropping units:

```{r fig=TRUE, fig.path = "images/", label="plot-units4"}
library(ggplot2)
ggplot() + geom_point(aes(x = as.numeric(displacement), 
    y = as.numeric(consumption)))
```

but that doesn't show us units. Giving the units as variables gives an error:

```{r error=TRUE, fig=FALSE}
ggplot() + geom_point(aes(x = displacement, y = consumption))
```
(I could make that error go away by letting `units` drop the
requirement that in a comparison both sides should have compatible
units, which of course would be wrong.)

We can then go all the way with
```{r fig=TRUE, fig.path = "images/", label="plot-units5"}
ggplot() + geom_point(aes(x = as.numeric(displacement), 
	y = as.numeric(consumption))) +
	xlab(make_unit_label("displacement", displacement)) +
	ylab(make_unit_label("consumption", consumption))
```

which at least doesn't cut off the left label, but feels too
convoluted and error-prone.

Oh ggplot gurus, who can help us out, here? How can we obtain that
last plot by

```{r eval=FALSE}
ggplot() + geom_point(aes(x = displacement, y = consumption))
```

?

## Update of Dec 2, 2016 

Thanks to ggguru [Thomas Lin
Pedersen](https://github.com/thomasp85), automatic units
in axis labels of ggplots are now provided by CRAN package
[ggforce](https://cran.r-project.org/package=ggforce): 

```{r,fig=TRUE, fig.path = "images/", label="plot-units6"}
library(ggforce)
ggplot() + geom_point(aes(x = displacement, y = consumption))
```

and see [this vignette](https://cran.r-project.org/web/packages/ggforce/vignettes/Visual_Guide.html#units) for more examples.
In addition to printing units in default axes labels, it allows for on-the-fly unit conversion in ggplot expressions:

```{r,fig=TRUE, fig.path = "images/", label="plot-units7"}
dm = with(ud_units, dm)
gallon = with(ud_units, gallon)
mi = with(ud_units, mi)
ggplot() + geom_point(aes(x = displacement, y = consumption)) +
    scale_x_unit(unit = dm^3) + scale_y_unit(unit = mi/gallon)
```

## Related posts/articles

* [Does R understand physical quantities?](http://r-spatial.org/r/2016/06/10/units.html)
* [Measurement units in R now simplify](http://r-spatial.org/r/2016/08/16/units2.html)
* [Measurement units for R](https://cran.r-project.org/web/packages/units/vignettes/measurement_units_in_R.pdf) (R Journal draft manuscript, package vignette)
