calibrateR
Introduction
When working at the bench, there are probably certain experiments and/or calculations that you routinely do that you hate doing. There’s no logical reason for why you feel this way. The experiment/calculation isn’t hard per se, you just wish that you didn’t have to do it again.
With this feeling of frustration in mind, I decided to streamline some
of these common calculations so that the heavy lifting is done behind
the scenes (insofar as there is anything truly “heavy” about these
calculations – perhaps “the clicking-and-dragging” is more apt). The
result, calibrateR
, is an easy-to-use R package that
contains functions to help with Gibson assembly reaction setup, protein
concentration determination via colorimetric assays, size exclusion
column calibration, and more. I am happy to expand
calibrateR
’s current functionalities. Please reach out with
other ideas/suggestions!
calibrateR
can be downloaded from
GitHub.
Usage
library(calibrateR)
Colorimetric Assays
I’ll start by describing the way that the package approaches colorimetric assays. For those who might be unfamiliar, colorimetric assays are a very common way of determining the concentration of analytes in solution. There are various types of colorimetric assays, but the general procedure is similar across the board. First, the user must calibrate the assay by measuring the output signal across a range of known analyte concentrations. Then, from the empirically determined relationship between analyte concentration and signal, the concentration of analyte in the experimentally relevant samples can be determined.
In the example below, I start with defined standard analyte
concentrations (conc
) and three replicates
(rep1-3
) of corresponding signal readings. Note that the
signal readings are entered in the same order as the known
concentrations.
conc <- c(2, 1.5, 1, 0.75, 0.5, 0.25, 0.125, 0.025, 0)
rep1 <- c(2.312, 1.786, 1.273, 1.035, 0.744, 0.484, 0.351, 0.237, 0.209)
rep2 <- c(2.249, 1.739, 1.207, 0.984, 0.701, 0.455, 0.338, 0.23, 0.209)
rep3 <- c(2.282, 1.715, 1.204, 0.99, 0.712, 0.484, 0.345, 0.24, 0.208)
Next, I will use the calibrate_colorimetric()
function in
calibrateR
to create a new function, here called
bca()
, to do all of the downstream data analysis for me.
bca <- calibrate_colorimetric(conc = conc,
abs = c( rep1, rep2, rep3 ),
with.blank = TRUE,
nrep = 3)
With the calibrated function defined, we can do one of two things. The
first thing we should do is look at our fit and make sure it’s
reasonable. To do this, we’ll use our concentration values to calculate
expected signal values based on the fit parameters. To do this, call
bca( a = conc, return.conc = FALSE )
. In this instance, we
enter the known concentration values, and tell the function that it is
not returning concentration values (it’s returning signal
values). Because the units of both concentration and signal can vary
widely across assays, I intentionally left units off of the example
plot.
library(ggplot2)
bca.df <- data.frame(conc = conc,
meas = c(rep1, rep2, rep3))
bca.fit.df <- data.frame(conc = conc,
fit = bca(a = conc, return.conc = FALSE))
ggplot(bca.df, aes(x = conc, y = meas)) +
geom_point(shape = 21, color = "black", fill = "gray75", size = 2.5) +
geom_line(data = bca.fit.df, aes(x = conc, y = fit), color = "red", linewidth = 0.75) +
theme_bw() +
theme(axis.text = element_text(size = 14),
axis.title = element_text( size = 16)) +
labs(x = "Concentration", y = "Signal")
The fit seems reasonable. The observed data points lie nicely along the
fitted line. Now that we’ve calibrated the assay and are fairly
confident that the calibration makes sense, we can feed in signal values
from samples of unknown concentration. Here, we’ll assume that we have
five unknown samples and that each unknown sample was measured at a
2-fold dilution. We will use return.conc = TRUE
and
df = 2
in bca()
to tell the function that it
is returning concentration values and to define the dilution
factor(s), respectively. The returned units of concentration are the
same as the units of concentration used to make the standard curve.
set.seed(1234)
unk <- runif(5, min = 0.3, max = 2)
bca(a = unk, return.conc = TRUE, df = 2)
#> [1] 0.5453686 2.2248925 2.1818814 2.2284591 3.0128681
Gibson assembly
To calculate Gibson assembly reaction volumes, you need to define eight parameters for each reaction. These are: insert concentration(s), insert length(s), vector concentration, vector length, the number of fragments in the reaction, the molar ratio of insert to vector, the mass of vector in the reaction (in ng), and the final volume of the reaction before the addition of 2x master mix. Concentration units should be ng/µL (or equivalent) and length units should be bp.
The function can calculate parameters for multiple reactions one fell swoop. Vectors with lengths corresponding to the number of unique reactions must be entered for all parameters except insert concentration and insert length. For each reaction, the function will then extract the relevant parameters from the input vectors and perform the requisite calculations. A list of data frames is returned, where each list element represents a unique reaction.
In the example below, I’m calculating reaction parameters for two reactions. The first reaction has 2 input fragments and the second has 3.
gibson( insert.conc = c(35, 78, 48, 37, 40),
insert.len = c(1894, 2403, 887, 1764, 943),
vec.conc = c(55, 65),
vec.len = c(4710, 5934),
n.frag = c(2, 3),
vec.mass = rep(50, 2),
molar.ratio = rep(3, 2),
final.vol = rep(5, 2),
ids = c("Reaction 1", "Reaction 2"))
#> $`Reaction 1`
#> Volume
#> Fragment 1 1.72
#> Fragment 2 0.98
#> Vector 0.91
#> Water 1.39
#> Master Mix 5.00
#>
#> $`Reaction 2`
#> Volume
#> Fragment 1 0.47
#> Fragment 2 1.21
#> Fragment 3 0.60
#> Vector 0.77
#> Water 1.95
#> Master Mix 5.00
Size exclusion column calibration
Size exclusion chromatography (SEC) is a wildly available technique that can provide useful information about macromolecules. Most commonly, SEC is associated with molecular weight. However, SEC actually separates macromolecules according to their hydrodynamic radius (or Stokes radius). For macromolecules with similar overall shapes, changes in hydrodynamic radius are due predominantly to changes in the number of atoms present in the molecule (i.e., its mass). For macromolecules of different shapes, however, separation based on hydrodynamic radius is a poor indicator of molecular weight. For this reason, it is important to be able to calibrate SEC columns for both radius and mass.
The calibrate_sec()
function in calibrateR
works similarly to the calibrate_colorimetric()
function
described above. The function minimally requires the user to define
three parameters: the measured elution volume of standard analytes, the
masses (yes, just the masses; in Da) of standard analytes, and the
macromolecular parameter of interest – either molecular weight
(mw
) or hydrodynamic radius (rh
).
masses <- c( 670000, 158000, 44000, 17000, 1350 )
rep1 <- c( 13.36, 16.07, 17.56, 18.46, 20.30 )
rep2 <- c( 13.32, 16.03, 17.49, 18.38, 20.23 )
rep3 <- c( 13.38, 16.09, 17.58, 18.48, 20.33 )
sec.rh <- calibrate_sec(vols = c(rep1, rep2, rep3),
masses = masses,
parameter = "rh")
Running calibrate_sec()
returns a function for downstream
number crunching. Setting parameter = “rh”
uses a
previously
published
scaling law to convert the provided mass values to radius values.
Convention for SEC column calibration plots is to plot $\log{(M)}$ or
$\log{(R_H)}$ vs. volume. Here, I will create a sequence of dummy
elution volumes between the observed elution volumes for the standard
analytes. Because I calibrated the column based on hydrodynamic radius
instead of mass, I will use the function mass_to_radius()
to convert the standard analyte masses to hydrodynamic radii. Then, I
will use the calibration to calculate the expected radii of analytes
eluting at each of the dummy elution volumes. Non-normalized elution
volumes are typically entered in mL units. Because these units don’t
strictly matter, however, I’ve left those units off of the plot. The
y-axis values are log-transformed. By default, however, the function
automatically re-transforms the expected values to the linear scale.
Note that the input mass units must be g/mol (Daltons). Calculated mass
values are returned in the same units. Hydrodynamic radius values are
returned in nm.
sec.df <- data.frame(vols = c(rep1, rep2, rep3),
rads = mass_to_radius(masses = masses))
sec.fit <- data.frame(vols = seq(13, 21, 0.01),
fit = sec.rh(seq( 13, 21, 0.01)))
ggplot(sec.df, aes(x = vols, y = log(rads))) +
geom_point(shape = 21, color = "black", fill = "gray75", size = 2.5) +
geom_line(data = sec.fit, aes(x = vols, y = log(fit)), color = "red", linewidth = 0.75) +
theme_bw() +
theme(axis.text = element_text(size = 14),
axis.title = element_text(size = 16)) +
labs(x = "Elution Volume", y = "log(Rh)")
To apply the calibrated function to analytes of unknown mass/radius,
simply enter the empirical elution volume of the analyte into the
function. If the column calibration was done using normalized elution
volumes, the function normalize_ev()
will normalize the
analyte elution volumes based on the column’s void and column volumes.
sec.rh(16.495)
#> a
#> 3.9831
UV/Vis
Concentration determination by UV/Vis spectroscopy is very common in the
lab. The calibrateR
function uv_vis()
takes as
input the measured absorbance at the desired wavelength, the extinction
coefficient of the molecule of interest, the dilution factor of the
measurement, the path length of light, and the type of molecule being
measured. If the type of molecule being measured is “protein”, the
extinction coefficient must be defined. If the type of molecule is one
of dsDNA, ssDNA, or ssRNA, the extinction coefficient can be
NULL
, and the standard (average) extinction coefficients
for these macromolecules are used. The path length defaults to 1 cm.
In the example below, a two-fold dilution of a purified protein with an
extinction coefficient of 35000 M-1cm-1 was
measured to have an absorbance of 0.491 at 280 nm. uv_vis()
returns concentrations in same concentration units used in the
extinction coefficient. In the example, that is molar units.
uv_vis(abs = 0.491,
ext = 35000,
df = 2,
type = "protein")
#> [1] 2.805714e-05