Introduction to rosettR

This package implements a high-throughput and affordable growth phenotyping assay for plate grown seedlings. Briefly, plants are grown on solid medium in tissue culture plates and photographed at regular intervals. Images are then analyzed using the functions implemented in this package to estimate area and relative growth rate of the seedlings over time. These estimated areas can then used to compare the differences between genotypes and the effect of applied treatments.

In this vignette, the creation of a new experiment, analysis of images, and generation of template statistical reports are described. Useful experimental details are given as block quotes. The examples are reproducible and with a working installation of rosettR you can copy-paste code to your R terminal to try it out. All functions have their own specific documentation and you can reach those documentation pages in R by typing ?function_name.

Installation

This package is not yet available on CRAN so the easiest way to install it is to use the devtools package.

library(devtools)
install_github("hredestig/rosettR", subdir="pkg")

The package is tested on Windows 7 and Linux.

Experiment design

A new experiment is started by loading the package and creating a meta-data object that details the specifics of the experiment. The information that is needed is:

NB: Avoid using special characters such as greek letters. If you must have spaces within an element, make sure to quote it as "genotype with space".

As a toy-example, let's study genotypes named foo, bar, baz, and qux subjected to two treatments: control condition and osmotic stress. The meta-data object (a simple list with key-value pairs) is created with

library(rosettR)
meta <- metaTemplate(genotypes=c("foo", "bar", "baz", "qux"),
                     treatments=c("control", "osmotic_stress"),
                     timepoints=c(11, 14, 16, 18),
                     nblocks=3,
                     reference="foo",
                     description="a test experiment")

The plates used are 150 x 25 mm tissue culture dishes, supplied with a grid that divides the plate in 32 boxes (aka wells). In our test experiment, we have only four genotypes so all plates have the same layout. Each plate is divided in four regions with 8 boxes each, of which all are occupied by a single seed of the same genotype.

rosettR allows the testing of a wide variety of treatments. Stress treatments like heat, darkness, or different light regimes (intensity, light quality, etc) can be tested by simply moving the plates to the desired condition. Other treatments like testing different sugars or sugar concentrations, salt, or osmotic stress require the addition of the chemical to the medium. These type of treatments can either be applied from germination, by placing the seeds directly on top of the medium with the desired addition, or at a later point in the experiment. For the latter, the use of sefar membranes is required. They are placed on top of the solidified medium, and the seeds placed on top of the membranes. When the treatment needs to be applied, new plates are made with the desired addition, and the membranes with the seedlings on top are transferred to the new plates.

Next we 'create' the experiment which generates the metadata-file, which is the directory structure in which to place the taken pictures, and the manifest file that defines the randomized block design.

pathToExperiment <- "rosettrTest"
newExperiment(pathToExperiment, meta)

The manifest file can be opened in your favorite spread-sheet editor or just inspected directly by

head(readManifest(pathToExperiment))
##          plate treatment GENOTYPE genotype_region BLOCK position timepoint
## 1 plate001.jpg   control      foo               c     3        2        11
## 2 plate001.jpg   control      bar               d     3        2        11
## 3 plate001.jpg   control      baz               b     3        2        11
## 4 plate001.jpg   control      qux               a     3        2        11
## 5 plate002.jpg   control      foo               c     2        1        11
## 6 plate002.jpg   control      bar               d     2        1        11
##   label              image
## 1    C2 ./D11/plate001.jpg
## 2    C2 ./D11/plate001.jpg
## 3    C2 ./D11/plate001.jpg
## 4    C2 ./D11/plate001.jpg
## 5    B1 ./D11/plate002.jpg
## 6    B1 ./D11/plate002.jpg

To obtain an overview of the created experiment, to support preparing the plates, compile the template 'layout' report (the use of the quiet=TRUE argument here is solely to avoid cluttering the vignette, in actual use you can safely ignore that argument).

makeReport(pathToExperiment, "layout", quiet=TRUE)

The layout report gives an overview of the experimental design and important information for the sowing setup. Each genotype is assigned a letter (a to d) and a region in the plate, and the seeds must be placed in the corresponding region. The plates should be numbered and marked so that it is possible to identify the axis of the plate (reference to figure). We further recommend labelling the plates in the margin of the lid, visible to the camera but not covering any plants, so that you can later confirm that the order is correct. Growth medium is poured in the plates in sterile conditions. When the medium solidifies, sterile seeds can be placed in the corresponding well with a Vacuumseed. The plates are then sealed with Urgopore tape, wrapped in groups of 10-15 in transparent foil, and placed at 4 degrees and darkness for three nights for seed stratification. The plates are then placed in the shelf of the growth chamber following the placement setup, according to a random block design where each block will have a unique plate from each combination of genotypes and treatment.

When the seedlings reach the desired age, top-view pictures of all plates are taken (in jpg format) at fixed time points, and image files are then copied to the corresponding folder previously created. pictures of the plates are taken exactly in the order they are listed in the manifest and saved in the designated directories for each monitored day. Make sure that your camera's internal clock is correctly set as the time the photo was taken will be used to match each image to the corresponding line in the manifest. Further ensure that

Auto-correction steps are included in the analysis so it is possible to analyze image also with slight deviations from these rules but the result is likely to be better if they are kept.

Image capturing is performed by placing the plates in a Copy Stands Lighting Equipment (Kaiser Fototechnic). A Canon 450D camera is placed 66.4 cm above the plates, with a Canon 50 mm prime lens, an aperture of F11, and shutter speed of 1/125. The use of fixed camera settings eliminates the need for camera distance calculations.

Image analysis

Before detailing the process of analyzing a whole experiment, we a brief description of the analysis of a single image. This process is defined in the function analyzeImage and consists of the following main steps:

For testing purposes, we first unzip some example images to our example and set the scale directly

meta <- readMeta(pathToExperiment)
meta$pixelsmm <- 7.54 # 7.54 pixels per millimeter
writeMeta(meta, pathToExperiment)
unzip(system.file("examples/rosettrTest.zip", package="rosettR"),
      exdir=".")

When all images have been taken you can generate an overview of them by

makeReport(pathToExperiment, "overview", quiet=TRUE)

If all images look as expected, it is time to analyze them. First however, you should calibrate the scale of the images to get the right pixels to millimeter mapping. Do this by (see ?calibrateScale for further details)

calibrateScale(pathToExperiment)

Which will record the conversion in the meta-data file for future reference.

Next, we analyze the images using processPlateExperiment function.

processPlateExperiment(pathToExperiment, checklocation=FALSE)

we turn off the plate location detection to speedup this test analysis (and for demonstration purposed later in this vignette)

Perform quality control

Once images have been analyzed, statistical analysis can be done by compiling a suitable template report. This is done by running makeReport that creates a report for the experiment in the designated output directory ([path to experiment]/Output/reports/). The first report to compile is typically a quality control report.

makeReport(pathToExperiment, "quality-check", quiet=TRUE)

The final report can then be found in the Output folder of experiment which shows QC images for all plates as well as graphs to indicate the presence of outliers.

In the QC images, the grid is indicated by black boxes and features are shown with randomly chosen colors. Boxes in which features were found that could not be sorted to a distinct box are indicated by a red border. In a successful scenario, all box-frames are black and each box contains a plant of color different from the plants in all neighboring boxes. However, when overlapping plants are identified, corresponding boxes are cut out and all the area estimate of the seedling in that box becomes the sum of all features in the box. This may yield poor area estimates and plates with many ambiguous boxes may be considered for removal using the removeBoxes function, or reprocessed with tuned image analysis (see ?analyzeImage for arguments) parameters.

Re-processing failed images

If the analysis has gone wrong due to e.g the plate location not correctly identified, it is possible to reprocess the picture with improved parameters to image threshold, angle correction, plate displacement etc.

As can be seen when studying the QC images of our example experiment, one image failed since it was excessively out of the centre of the image.

pda <- readPhenodata(pathToExperiment)
qcpic <- subset(pda, timepoint == 11 & plate == "plate003.jpg")$qc[1]
library(EBImage)
qcPath <- file.path(pathToExperiment, qcpic)
qcImage <- readImage(qcPath)
display(qcImage, method="raster")

plot of chunk excentric

To resolve this problem, we reprocess that single image but this time with the location correction turned on.

mf <- readManifest(pathToExperiment)
mf <- subset(mf, timepoint == 11 & plate  == "plate003.jpg")
## reprocess the plate where using the plate location correction
pda <- reprocessPlateImages(pathToExperiment, mf, checklocation=TRUE)

Inspect the result

pda <- readPhenodata(pathToExperiment)
qcpic <- subset(pda, timepoint == 11 & plate == "plate002.jpg")$qc[1]
display(readImage(file.path(pathToExperiment, qcpic)), method="raster")

plot of chunk inspect-fix

See the documenation for analyzeImage for other parameters that can be adjusted during image analysis.

We can then re-compile the quality control report

makeReport(pathToExperiment, "quality-check", quiet=TRUE)

Interpretation

To obtain the final results from the experiment, compile the report to compare areas by plots and by ANOVA.

makeReport(pathToExperiment, "compare-areas", quiet=TRUE)

You can also simply run

readPhenodata(pathToExperiment)

to get a dataframe with the results with which you can perform your own tailored statistical analysis.

Additional topics

Failed plates

In the event of contamination, e.g. fungal growth on the plate you may want to prematurely discard plates. In that case, it is important to take place-holder images to get the order of images right. The recomendation is to replace the bad plate with an empty one and keep taking images of that empty plate. Such empty plates are detected during image analysis and areas are indicated as missing values. The QC picture will be replace by a place holder indicated that the plate was empty.

Parallel computing

Image analysis can be done in parallel to speed up computation considerably. The rosettR package uses plyr which support using multiple CPUs on a single host via the doParallel package. Simply register a parallel backend by for using e.g. 4 CPUs by

library(doParallel)
registerDoParallel(cores=4)

and then processing images adding the argument .parallel=TRUE. The memory consumption is quite low so you can safely use as many CPUs as you have minus 1 (to not make your computer unresponsive).

Session info

Here is the output of sessionInfo() on the system on which this document was compiled:

## R version 3.2.1 (2015-06-18)
## Platform: x86_64-unknown-linux-gnu (64-bit)
## Running under: Red Hat Enterprise Linux Server release 6.7 (Santiago)
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C              
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] EBImage_4.8.3  ggplot2_1.0.1  plyr_1.8.3     reshape2_1.4.1
## [5] rosettR_0.0.5  knitr_1.11    
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.3         highr_0.5.1         formatR_1.2.1      
##  [4] tools_3.2.1         digest_0.6.8        jsonlite_0.9.19    
##  [7] evaluate_0.8        gtable_0.1.2        lattice_0.20-33    
## [10] png_0.1-7           parallel_3.2.1      mvtnorm_1.0-3      
## [13] proto_0.3-10        stringr_1.0.0       locfit_1.5-9.1     
## [16] grid_3.2.1          jpeg_0.1-8          survival_2.38-3    
## [19] multcomp_1.4-1      TH.data_1.0-6       magrittr_1.5       
## [22] MASS_7.3-44         scales_0.3.0        codetools_0.2-14   
## [25] splines_3.2.1       BiocGenerics_0.14.0 abind_1.4-3        
## [28] mime_0.4            xtable_1.8-0        colorspace_1.2-6   
## [31] tiff_0.1-5          labeling_0.3        sandwich_2.3-4     
## [34] stringi_1.0-1       munsell_0.4.2       markdown_0.7.7     
## [37] zoo_1.7-12