R and ggplot2: Make zero print as “0”

The aesthetics of R printing zeros with superfluous decimal places (e.g. “0.00” instead of “0”) has always bothered me. I also want to keep the number of decimal places for the other ticks consistent (e.g. “0, 0.5, 1.0,” not “0, 0.5, 1”). I could get prettyNum() to fix the “0” instead of “0.0”, but then it was also giving me “1” instead of “1.0”.

It’s possible to get the desired output, for an arbitrary number of decimal places, without resorting to manually defining the break labels. We first define a function to format the labels how we want, using formatC(). We then supply it to the “labels” argument of scale_*_continuous, which takes the original numeric values calculated for the breaks, and applies the function to them.

# Make zeros print as "0" always
prettyZero <- function(l){
	max.decimals = max(nchar(str_extract(l, "\\.[0-9]+")), na.rm = T)-1
	lnew = formatC(l, replace.zero = T, zero.print = "0",
		digits = max.decimals, format = "f", preserve.width=T)

# Try it out: compare x-axis and y-axis
somedata = tibble(x = runif(n = 100)-0.5, y = runif(n = 100)-0.5)
ggplot(data = somedata, aes(x, y)) +
	geom_point() +
	scale_y_continuous(labels = prettyZero)

ShinyFlan: a replacement for FALCOR (Fluctuation AnaLysis CalculatOR)

FALCOR was for a long time the easiest way to analyse fluctuation test data. Some time ago, the site hosting the FALCOR Java applet went offline.

Enter ShinyFlan, an alternative to FALCOR that uses the R package flan via a Shiny web interface. ShinyFlan was created by Adrian Mazoyer.

Associated with our Journal of Visualized Experiments paper on fluctuation tests, The University of Manchester currently hosts ShinyFlan here:

A tidyverse approach to manipulating BMG Labtech OMGEA and stacker output

Here is some R code for dealing with ASCII files as output by BMG MARS analysis


software, specifically to make use of data spread across different plates as a result of using the BMG Microplate Stacker.

I had a few problems with the stacker jamming when we first got it, but this was solved by (1) lubricating the magazines with a silicon spray (food-grade, not sure if that matters), (2) periodic cleaning with a degreaser, and (3) making the first step of any protocol a ‘restack’ all plates command, so that the plates are positioned more accurately. Since doing these steps, I’ve had minimal problems. In general, I like BMG plate readers for the exact reason most people don’t: the scripting language. Although it isn’t the most sophisticated, the scripting language is powerful enough to design some fairly complex protocols. Combined with the stacker, which can hold either 25 or 50 microplates depending on which magazine set you have, it’s useful for running high-throughput phenotype assays.


# Some functions for importing BMG-style CSV files in a tidy way
BMGtime = function(otime){
# A function to convert BMG's default time format to fractional hours (can also set in MARS)
missing.s=grep("[0-9] s",otime, value=F,invert=T)
missing.m=grep("[0-9] min",otime, value=F,invert=T)
missing.h=grep("[0-9] h",otime, value=F,invert=T)
otime[missing.s]=sub("$"," 0 s", otime[missing.s])
otime[missing.h]=sub("^","0 h ", otime[missing.h])
otime[missing.m]=sub("h", "h 0 min ", otime[missing.m])
otime=period_to_seconds(hms(gsub("[a-z ]+",":", otime)))/3600

# BMG MARS CSV exports have a trailing comma, so this drops the empty last column
read_csv_drop = function(...) read_csv(...) %>% select(-ncol(.))

# Read a single BMG Mars wide-format time series table into long format
readBMG = function(file){
growthdata = read_csv_drop(file, skip=0) %>%
select(-contains("Blank corrected"))
ndescriptors = ifelse("Group"%in%names(growthdata), 4, 3)
header = tolower(gsub("Well ", "", names(growthdata)[1:ndescriptors]))
time = growthdata %>% select(-(1:ndescriptors)) %>% slice(1) %>% t()
if(grepl("[a-z]", time)) time = BMGtime(time)
names(growthdata) = c(header, time)
growthdata = growthdata %>%
slice(2:n()) %>%
type_convert() %>%
# Read multiple files from the same experiment (resulting from a stacker run)
readStack = function(path=NULL, pattern, parse.name=F, prefix=NULL, suffix=NULL, into=NULL, sep=NULL, ...){
stackdata = data_frame(id = list.files(pattern=pattern, path=path, ...), data = map2(id, path, ~readBMG(paste0(.y,"/",.x))))
stackdata = stackdata %>%
mutate(id = gsub(prefix, "", id))
stackdata = stackdata %>%
mutate(id = gsub(suffix, "", id))
stackdata = stackdata %>% separate(id, sep=sep, into=into)
stackdata = stackdata %>% unnest(data) %>% type_convert()

How to make ggplot look like base R graphics

After being steadfastly against anything in R beyond base, I’ve recently been indoctrinated into the tidyverse way of doing things. In particular, ggplot and extensions has made making complicated plots a lot easier than using base graphics (especially ggpubr’s ggarrange() function for labelling panels, which I used to do with mtext()). However, I’ve never been a huge fan of the ggplot aesthetic, being trained from a young age to eschew “chart junk“, like grid lines and unnecessary backgrounds. It’s fairly easy to do, with a few modifications of ggplot’s theme_bw(). Include this code before your ggplot commands:

Continue reading