--- 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)