knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width=6, fig.height=4, out.width="100%", dpi = 200)
PCR data appear to be simple to work with at the outset - QuantStudio can output barcharts, and it even readily outputs the data in tabular formats. However, some tasks, like omitting a particular measurement, no longer make the results valid. One must remember to omit it in QuantStudio, recalculate the values, then plot the results - or risk having an inaccurate plot!
Additionally, the plots output by QuantStudio are fairly ugly and inflexible. Outputting them is tedious, as is rearranging columns.
In this vignette, I'll perform a routine analysis on a rather untidy dataset using the pcr_*
suite of functions. The pcr_*
suite of functions seek to make life a little easier and a lot more reproducible by allowing many of the previously QuantStudio specific tasks to be done in R.
library(amplify) library(dplyr) library(ggplot2) library(stringr)
We have a particular advantage because although the data are untidy, they are untidy in a very specific way. Reading in data is as simple as running read_pcr
and scrub
(re-exports from the mop
package), which is given a path to the pcr .xls(x) file. If no path is given, an interactive file explorer window will appear for the user to choose the file.
dat <- system.file("extdata", "untidy-pcr-example-2.xlsx", package = "amplify") |> read_pcr() |> scrub() dat
The typical format of PCR data is woefully non-rectangular. amplify
fixes this by skipping to the good bits, but also pulling out useful metadata supplied in the header and footer of the dataset - like the last few columns:
select(dat, analysis_type:reference_sample)
pcr_plate_view
pcr_plate_view
makes it very easy to get a bird's-eye view of the plate:
pcr_plate_view(dat)
This high level overview lets us see there's something curious going on with A1. Additionally, some wells at the bottom - likely non-targeting controls - only have two instead of three wells ascribed to them.
What about the sample layout?
pcr_plate_view(dat, sample_name)
We can also look at CT:
pcr_plate_view(dat, fill = ct) + scale_color_viridis_c(end = 0.9)
Looks like some didn't amplify at all.
You might consider looking at it with rq
but...
pcr_plate_view(dat, fill = rq) + scale_color_viridis_c()
Immediately we see a loss of information: Not only are the scales between cell lines wildly different, but some of the targets aren't even there! What's going on?
If we remember back, our reference sample was RT112, which does not appear to express one of the targets at all. Therefore a quantity relative to 0 doesn't make any sense!
pcr_plot
We can naively plot all of the data at once using pcr_plot
pcr_plot(dat)
We notice the differences between cell lines, but the large dynamic range makes it difficult to look at differences between conditions. We can split the data up by cell line and then recalculate rqs individually.
pcr_rq
First, we need to extract the cell line from the sample name. Additionally, I don't like how it says "Zeb1" and "Zeb2" instead of "ZEB1" and "ZEB2" (the capitalization may mislead people into thinking this is murine, when it is in fact human). I'll change that here.
dat <- dat |> mutate(cell_line = str_extract(sample_name, "^.*(?=[:space:])")) |> mutate(target_name = str_replace(target_name, "Zeb", "ZEB"))
As an example, let's look at UC14:
uc14 <- dat |> filter(cell_line == "UC14") |> pcr_rq("UC14 PBS") pcr_plot(uc14)
I personally prefer it when the control is on the left and the experimental conditions are on the right - let's flip them. While we're at it, let's get rid of the legend - it doesn't tell us any extra information and is just taking up space.
uc14 <- uc14 |> mutate(sample_name = factor(sample_name, levels = c("UC14 PBS", "UC14 Drug"))) pcr_plot(uc14) + theme(legend.position = "none")
The same kind of reorganization can be done with target_names
as well - if you wanted to put the control target (here PPIA) at the end.
Suppose you have reason to believe that one of your colleagues (or perhaps you yourself) spit into your C22 well (the spit was very accurate). If we naively remove it, this is what we get:
naive <- uc14 |> filter(well_position != "C24") pcr_plot(naive)
Umm...it doesn't look any different. And that's what we should expect: the plotting function doesn't do any calculations: It only plots the values already stored within it. To get updated values, we need to use pcr_rq
again:
wise <- uc14 |> filter(well_position != "C24") |> pcr_rq("UC14 PBS") pcr_plot(wise)
Now, we see that the ZEB1 values have updated to reflect the omission we made.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.