Please send questions to wambaugh.john@epa.gov
This vignette provides the code used to generate the figures in Wambaugh et al. (2018) “Evaluating In Vitro-In Vivo Extrapolation of Toxicokinetics”
John F Wambaugh, Michael F Hughes, Caroline L Ring, Denise K MacMillan, Jermaine Ford, Timothy R Fennell, Sherry R Black, Rodney W Snyder, Nisha S Sipes, Barbara A Wetmore, Joost Westerhout, R Woodrow Setzer, Robert G Pearce, Jane Ellen Simmons, Russell S Thomas
Toxicological Sciences, Volume 163, Issue 1, May 2018, Pages 152-169,
https://doi.org/10.1093/toxsci/kfy020
Prioritizing the risk posed by thousands of chemicals potentially present in the environment requires exposure, toxicity, and toxicokinetic (TK) data, which are often unavailable. Relatively high-throughput, in vitro TK (HTTK) assays and in vitro-to-in vivo extrapolation (IVIVE) methods have been developed to predict TK, but most of the in vivo TK data available to benchmark these methods are from pharmaceuticals. Here we report on new, in vivo rat TK experiments for 26 non-pharmaceutical chemicals with environmental relevance. Both intravenous and oral dosing were used to calculate bioavailability. These chemicals, and an additional 19 chemicals (including some pharmaceuticals) from previously published in vivo rat studies, were systematically analyzed to estimate in vivo TK parameters (e.g., volume of distribution [Vd], elimination rate). For each of the chemicals, rat-specific HTTK data were available and key TK predictions were examined: oral bioavailability, clearance, Vd, and uncertainty. For the non-pharmaceutical chemicals, predictions for bioavailability were not effective. While no pharmaceutical was absorbed at less than 10%, the fraction bioavailable for non-pharmaceutical chemicals was as low as 0.3%. Total clearance was generally more under-estimated for nonpharmaceuticals and Vd methods calibrated to pharmaceuticals may not be appropriate for other chemicals. However, the steady-state, peak, and time-integrated plasma concentrations of non-pharmaceuticals were predicted with reasonable accuracy. The plasma concentration predictions improved when experimental measurements of bioavailability were incorporated. In summary, HTTK and IVIVE methods are adequately robust to be applied to high-throughput in vitro toxicity screening data of environmentally relevant chemicals for prioritizing based on human health risks.
This vignette was created with httk v1.8. Although we attempt to maintain backward compatibility, if you encounter issues with the latest release of httk and cannot easily address the changes, historical versions of httk are available from: https://cran.r-project.org/src/contrib/Archive/httk/
R package knitr generates html and PDF documents from this RMarkdown file, Each bit of code that follows is known as a “chunk”. We start by telling knitr how we want our chunks to look.
It is a bad idea to let variables and other information from previous R sessions float around, so we first remove everything in the R memory.
rm(list=ls())
If you are using the RMarkdown version of this vignette (extension, .RMD) you will be able to see that several chunks of code in this vignette have the statement “eval = execute.vignette”. The next chunk of code, by default, sets execute.vignette = FALSE. This means that the code is included (and necessary) but was not run when the vignette was built. We do this because some steps require extensive computing time and the checks on CRAN limit how long we can spend building the package. If you want this vignette to work, you must run all code, either by cutting and pasting it into R. Or, if viewing the .RMD file, you can either change execute.vignette to TRUE or press “play” (the green arrow) on each chunk in RStudio.
# Set whether or not the following chunks will be executed (run):
<- FALSE execute.vignette
To use the code in this vignette, you’ll first need to load a few packages. If you get the message “Error in library(X) : there is no package called ‘X’” then you will need to install that package:
From the R command prompt:
install.packages(“X”)
Or, if using RStudio, look for ‘Install Packages’ under ‘Tools’ tab.
library(scales)
library(ggplot2)
library(data.table)
library(httk)
library(RColorBrewer)
library(grid)
library(gplots)
The data we analyze were originally generated with the R package invivoPKfit, but all the outputs of that analysis are provided with httk >v1.8.
These functions, which have been cobbled together from the internet, are reused in multiple figure to make things look nice.
# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot objects)
# - cols: Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
#
<- function(..., plotlist=NULL, file, cols=1, layout=NULL, widths=unit(rep_len(1, cols), "null")) {
multiplot
# Make a list from the ... arguments and plotlist
<- c(list(...), plotlist)
plots
= length(plots)
numPlots
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
<- matrix(seq(1, cols * ceiling(numPlots/cols)),
layout ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
else {
} # Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout),widths=widths)))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
<- as.data.frame(which(layout == i, arr.ind = TRUE))
matchidx
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
<- function(x) {
scientific_10 <- gsub("1e", "10^", scientific_format()(x))
out <- gsub("\\+","",out)
out <- gsub("10\\^01","10",out)
out <- parse(text=gsub("10\\^00","1",out))
out
}
<- function(m,prefix=NULL){
lm_R2 <- substitute("MSE = "~mse*","~~italic(R)^2~"="~r2,
out list(mse = signif(mean(m$residuals^2),3),
r2 = format(summary(m)$adj.r.squared, digits = 2)))
paste(prefix,as.character(as.expression(out)))
}
.3 <- function(x,
heatmapRowv = TRUE, Colv = if (symm) "Rowv" else TRUE,
distfun = dist,
hclustfun = hclust,
dendrogram = c("both","row", "column", "none"),
symm = FALSE,
scale = c("none","row", "column"),
na.rm = TRUE,
revC = identical(Colv,"Rowv"),
add.expr,
breaks,symbreaks = max(x < 0, na.rm = TRUE) || scale != "none",
col = "heat.colors",
colsep,
rowsep,sepcolor = "white",
sepwidth = c(0.05, 0.05),
cellnote,notecex = 1,
notecol = "cyan",
na.color = par("bg"),
trace = c("none", "column","row", "both"),
tracecol = "cyan",
hline = median(breaks),
vline = median(breaks),
linecol = tracecol,
margins = c(5,5),
ColSideColors,
RowSideColors,side.height.fraction=0.3,
cexRow = 0.2 + 1/log10(nr),
cexCol = 0.2 + 1/log10(nc),
labRow = NULL,
labCol = NULL,
key = TRUE,
keysize = 1.5,
density.info = c("none", "histogram", "density"),
denscol = tracecol,
symkey = max(x < 0, na.rm = TRUE) || symbreaks,
densadj = 0.25,
main = NULL,
xlab = NULL,
ylab = NULL,
lmat = NULL,
lhei = NULL,
lwid = NULL,
ColSideColorsSize = 1,
RowSideColorsSize = 1,
KeyValueName="Value",...){
<- function (x) {
invalid if (missing(x) || is.null(x) || length(x) == 0)
return(TRUE)
if (is.list(x))
return(all(sapply(x, invalid)))
else if (is.vector(x))
return(all(is.na(x)))
else return(FALSE)
}
<- as.matrix(x)
x <- function(x, low = min(x), high = max(x)) {
scale01 <- (x - low)/(high - low)
x
x
}<- list()
retval <- if (symm && missing(scale))
scale "none"
else match.arg(scale)
<- match.arg(dendrogram)
dendrogram <- match.arg(trace)
trace <- match.arg(density.info)
density.info if (length(col) == 1 && is.character(col))
<- get(col, mode = "function")
col if (!missing(breaks) && (scale != "none"))
warning("Using scale=\"row\" or scale=\"column\" when breaks are",
"specified can produce unpredictable results.", "Please consider using only one or the other.")
if (is.null(Rowv) || is.na(Rowv))
<- FALSE
Rowv if (is.null(Colv) || is.na(Colv))
<- FALSE
Colv else if (Colv == "Rowv" && !isTRUE(Rowv))
<- FALSE
Colv if (length(di <- dim(x)) != 2 || !is.numeric(x))
stop("`x' must be a numeric matrix")
<- di[1]
nr <- di[2]
nc if (nr <= 1 || nc <= 1)
stop("`x' must have at least 2 rows and 2 columns")
if (!is.numeric(margins) || length(margins) != 2)
stop("`margins' must be a numeric vector of length 2")
if (missing(cellnote))
<- matrix("", ncol = ncol(x), nrow = nrow(x))
cellnote if (!inherits(Rowv, "dendrogram")) {
if (((!isTRUE(Rowv)) || (is.null(Rowv))) && (dendrogram %in%
c("both", "row"))) {
if (is.logical(Colv) && (Colv))
<- "column"
dendrogram else dedrogram <- "none"
warning("Discrepancy: Rowv is FALSE, while dendrogram is `",
"'. Omitting row dendogram.")
dendrogram,
}
}if (!inherits(Colv, "dendrogram")) {
if (((!isTRUE(Colv)) || (is.null(Colv))) && (dendrogram %in%
c("both", "column"))) {
if (is.logical(Rowv) && (Rowv))
<- "row"
dendrogram else dendrogram <- "none"
warning("Discrepancy: Colv is FALSE, while dendrogram is `",
"'. Omitting column dendogram.")
dendrogram,
}
}if (inherits(Rowv, "dendrogram")) {
<- Rowv
ddr <- order.dendrogram(ddr)
rowInd
}else if (is.integer(Rowv)) {
<- hclustfun(distfun(x))
hcr <- as.dendrogram(hcr)
ddr <- reorder(ddr, Rowv)
ddr <- order.dendrogram(ddr)
rowInd if (nr != length(rowInd))
stop("row dendrogram ordering gave index of wrong length")
}else if (isTRUE(Rowv)) {
<- rowMeans(x, na.rm = na.rm)
Rowv <- hclustfun(distfun(x))
hcr <- as.dendrogram(hcr)
ddr <- reorder(ddr, Rowv)
ddr <- order.dendrogram(ddr)
rowInd if (nr != length(rowInd))
stop("row dendrogram ordering gave index of wrong length")
}else {
<- nr:1
rowInd
}if (inherits(Colv, "dendrogram")) {
<- Colv
ddc <- order.dendrogram(ddc)
colInd
}else if (identical(Colv, "Rowv")) {
if (nr != nc)
stop("Colv = \"Rowv\" but nrow(x) != ncol(x)")
if (exists("ddr")) {
<- ddr
ddc <- order.dendrogram(ddc)
colInd
}else colInd <- rowInd
}else if (is.integer(Colv)) {
<- hclustfun(distfun(if (symm)
hcc
xelse t(x)))
<- as.dendrogram(hcc)
ddc <- reorder(ddc, Colv)
ddc <- order.dendrogram(ddc)
colInd if (nc != length(colInd))
stop("column dendrogram ordering gave index of wrong length")
}else if (isTRUE(Colv)) {
<- colMeans(x, na.rm = na.rm)
Colv <- hclustfun(distfun(if (symm)
hcc
xelse t(x)))
<- as.dendrogram(hcc)
ddc <- reorder(ddc, Colv)
ddc <- order.dendrogram(ddc)
colInd if (nc != length(colInd))
stop("column dendrogram ordering gave index of wrong length")
}else {
<- 1:nc
colInd
}$rowInd <- rowInd
retval$colInd <- colInd
retval$call <- match.call()
retval<- x[rowInd, colInd]
x <- x
x.unscaled <- cellnote[rowInd, colInd]
cellnote if (is.null(labRow))
<- if (is.null(rownames(x)))
labRow 1:nr)[rowInd]
(else rownames(x)
else labRow <- labRow[rowInd]
if (is.null(labCol))
<- if (is.null(colnames(x)))
labCol 1:nc)[colInd]
(else colnames(x)
else labCol <- labCol[colInd]
if (scale == "row") {
$rowMeans <- rm <- rowMeans(x, na.rm = na.rm)
retval<- sweep(x, 1, rm)
x $rowSDs <- sx <- apply(x, 1, sd, na.rm = na.rm)
retval<- sweep(x, 1, sx, "/")
x
}else if (scale == "column") {
$colMeans <- rm <- colMeans(x, na.rm = na.rm)
retval<- sweep(x, 2, rm)
x $colSDs <- sx <- apply(x, 2, sd, na.rm = na.rm)
retval<- sweep(x, 2, sx, "/")
x
}if (missing(breaks) || is.null(breaks) || length(breaks) < 1) {
if (missing(col) || is.function(col))
<- 16
breaks else breaks <- length(col) + 1
}if (length(breaks) == 1) {
if (!symbreaks)
<- seq(min(x, na.rm = na.rm), max(x, na.rm = na.rm),
breaks length = breaks)
else {
<- max(abs(x), na.rm = TRUE)
extreme <- seq(-extreme, extreme, length = breaks)
breaks
}
}<- length(breaks)
nbr <- length(breaks) - 1
ncol if (class(col) == "function")
<- col(ncol)
col <- min(breaks)
min.breaks <- max(breaks)
max.breaks < min.breaks] <- min.breaks
x[x > max.breaks] <- max.breaks
x[x if (missing(lhei) || is.null(lhei))
<- c(keysize, 4)
lhei if (missing(lwid) || is.null(lwid))
<- c(keysize, 4)
lwid if (missing(lmat) || is.null(lmat)) {
<- rbind(4:3, 2:1)
lmat
if (!missing(ColSideColors)) {
#if (!is.matrix(ColSideColors))
#stop("'ColSideColors' must be a matrix")
if (!is.character(ColSideColors) || nrow(ColSideColors) != nc)
stop("'ColSideColors' must be a matrix of nrow(x) rows")
<- rbind(lmat[1, ] + 1, c(NA, 1), lmat[2, ] + 1)
lmat #lhei <- c(lhei[1], 0.2, lhei[2])
=c(lhei[1], side.height.fraction*ColSideColorsSize/2, lhei[2])
lhei
}
if (!missing(RowSideColors)) {
#if (!is.matrix(RowSideColors))
#stop("'RowSideColors' must be a matrix")
if (!is.character(RowSideColors) || ncol(RowSideColors) != nr)
stop("'RowSideColors' must be a matrix of ncol(x) columns")
<- cbind(lmat[, 1] + 1, c(rep(NA, nrow(lmat) - 1), 1), lmat[,2] + 1)
lmat #lwid <- c(lwid[1], 0.2, lwid[2])
<- c(lwid[1], side.height.fraction*RowSideColorsSize/2, lwid[2])
lwid
}is.na(lmat)] <- 0
lmat[
}
if (length(lhei) != nrow(lmat))
stop("lhei must have length = nrow(lmat) = ", nrow(lmat))
if (length(lwid) != ncol(lmat))
stop("lwid must have length = ncol(lmat) =", ncol(lmat))
<- par(no.readonly = TRUE)
op on.exit(par(op))
layout(lmat, widths = lwid, heights = lhei, respect = FALSE)
if (!missing(RowSideColors)) {
if (!is.matrix(RowSideColors)){
par(mar = c(margins[1], 0, 0, 0.5))
image(rbind(1:nr), col = RowSideColors[rowInd], axes = FALSE)
else {
} par(mar = c(margins[1], 0, 0, 0.5))
= t(RowSideColors[,rowInd, drop=FALSE])
rsc = matrix()
rsc.colors = names(table(rsc))
rsc.names = 1
rsc.i for (rsc.name in rsc.names) {
= rsc.name
rsc.colors[rsc.i] == rsc.name] = rsc.i
rsc[rsc = rsc.i + 1
rsc.i
}= matrix(as.numeric(rsc), nrow = dim(rsc)[1])
rsc image(t(rsc), col = as.vector(rsc.colors), axes = FALSE)
if (length(rownames(RowSideColors)) > 0) {
axis(1, 0:(dim(rsc)[2] - 1)/max(1,(dim(rsc)[2] - 1)), rownames(RowSideColors), las = 2, tick = FALSE)
}
}
}
if (!missing(ColSideColors)) {
if (!is.matrix(ColSideColors)){
par(mar = c(0.5, 0, 0, margins[2]))
image(cbind(1:nc), col = ColSideColors[colInd], axes = FALSE)
else {
} par(mar = c(0.5, 0, 0, margins[2]))
= ColSideColors[colInd, , drop=FALSE]
csc = matrix()
csc.colors = names(table(csc))
csc.names = 1
csc.i for (csc.name in csc.names) {
= csc.name
csc.colors[csc.i] == csc.name] = csc.i
csc[csc = csc.i + 1
csc.i
}= matrix(as.numeric(csc), nrow = dim(csc)[1])
csc image(csc, col = as.vector(csc.colors), axes = FALSE)
if (length(colnames(ColSideColors)) > 0) {
axis(2, 0:(dim(csc)[2] - 1)/max(1,(dim(csc)[2] - 1)), colnames(ColSideColors), las = 2, tick = FALSE)
}
}
}
par(mar = c(margins[1], 0, 0, margins[2]))
<- t(x)
x <- t(cellnote)
cellnote if (revC) {
<- nr:1
iy if (exists("ddr"))
<- rev(ddr)
ddr <- x[, iy]
x <- cellnote[, iy]
cellnote
}else iy <- 1:nr
image(1:nc, 1:nr, x, xlim = 0.5 + c(0, nc), ylim = 0.5 + c(0, nr), axes = FALSE, xlab = "", ylab = "", col = col, breaks = breaks, ...)
$carpet <- x
retvalif (exists("ddr"))
$rowDendrogram <- ddr
retvalif (exists("ddc"))
$colDendrogram <- ddc
retval$breaks <- breaks
retval$col <- col
retvalif (!invalid(na.color) & any(is.na(x))) { # load library(gplots)
<- ifelse(is.na(x), 1, NA)
mmat image(1:nc, 1:nr, mmat, axes = FALSE, xlab = "", ylab = "",
col = na.color, add = TRUE)
}axis(1, 1:nc, labels = labCol, las = 2, line = -0.5, tick = 0,
cex.axis = cexCol)
if (!is.null(xlab))
mtext(xlab, side = 1, line = margins[1] - 1.25)
axis(4, iy, labels = labRow, las = 2, line = -0.5, tick = 0,
cex.axis = cexRow)
if (!is.null(ylab))
mtext(ylab, side = 4, line = margins[2] - 1.25)
if (!missing(add.expr))
eval(substitute(add.expr))
if (!missing(colsep))
for (csep in colsep) rect(xleft = csep + 0.5, ybottom = rep(0, length(csep)), xright = csep + 0.5 + sepwidth[1], ytop = rep(ncol(x) + 1, csep), lty = 1, lwd = 1, col = sepcolor, border = sepcolor)
if (!missing(rowsep))
for (rsep in rowsep) rect(xleft = 0, ybottom = (ncol(x) + 1 - rsep) - 0.5, xright = nrow(x) + 1, ytop = (ncol(x) + 1 - rsep) - 0.5 - sepwidth[2], lty = 1, lwd = 1, col = sepcolor, border = sepcolor)
<- min(breaks)
min.scale <- max(breaks)
max.scale <- scale01(t(x), min.scale, max.scale)
x.scaled if (trace %in% c("both", "column")) {
$vline <- vline
retval<- scale01(vline, min.scale, max.scale)
vline.vals for (i in colInd) {
if (!is.null(vline)) {
abline(v = i - 0.5 + vline.vals, col = linecol,
lty = 2)
}<- rep(i, nrow(x.scaled)) + x.scaled[, i] - 0.5
xv <- c(xv[1], xv)
xv <- 1:length(xv) - 0.5
yv lines(x = xv, y = yv, lwd = 1, col = tracecol, type = "s")
}
}if (trace %in% c("both", "row")) {
$hline <- hline
retval<- scale01(hline, min.scale, max.scale)
hline.vals for (i in rowInd) {
if (!is.null(hline)) {
abline(h = i + hline, col = linecol, lty = 2)
}<- rep(i, ncol(x.scaled)) + x.scaled[i, ] - 0.5
yv <- rev(c(yv[1], yv))
yv <- length(yv):1 - 0.5
xv lines(x = xv, y = yv, lwd = 1, col = tracecol, type = "s")
}
}if (!missing(cellnote))
text(x = c(row(cellnote)), y = c(col(cellnote)), labels = c(cellnote),
col = notecol, cex = notecex)
par(mar = c(margins[1], 0, 0, 0))
if (dendrogram %in% c("both", "row")) {
plot(ddr, horiz = TRUE, axes = FALSE, yaxs = "i", leaflab = "none")
}else plot.new()
par(mar = c(0, 0, if (!is.null(main)) 5 else 0, margins[2]))
if (dendrogram %in% c("both", "column")) {
plot(ddc, axes = FALSE, xaxs = "i", leaflab = "none")
}else plot.new()
if (!is.null(main))
title(main, cex.main = 1.5 * op[["cex.main"]])
if (key) {
par(mar = c(5, 4, 2, 1), cex = 0.75)
<- breaks
tmpbreaks if (symkey) {
<- max(abs(c(x, breaks)), na.rm = TRUE)
max.raw <- -max.raw
min.raw 1] <- -max(abs(x), na.rm = TRUE)
tmpbreaks[length(tmpbreaks)] <- max(abs(x), na.rm = TRUE)
tmpbreaks[
}else {
<- min(x, na.rm = TRUE)
min.raw <- max(x, na.rm = TRUE)
max.raw
}
<- seq(min.raw, max.raw, length = length(col))
z image(z = matrix(z, ncol = 1), col = col, breaks = tmpbreaks,
xaxt = "n", yaxt = "n")
par(usr = c(0, 1, 0, 1))
<- pretty(breaks)
lv <- scale01(as.numeric(lv), min.raw, max.raw)
xv axis(1, at = xv, labels = lv)
if (scale == "row")
mtext(side = 1, "Row Z-Score", line = 2)
else if (scale == "column")
mtext(side = 1, "Column Z-Score", line = 2)
else mtext(side = 1, KeyValueName, line = 2)
if (density.info == "density") {
<- density(x, adjust = densadj, na.rm = TRUE)
dens <- dens$x < min(breaks) | dens$x > max(breaks)
omit $x <- dens$x[-omit]
dens$y <- dens$y[-omit]
dens$x <- scale01(dens$x, min.raw, max.raw)
denslines(dens$x, dens$y/max(dens$y) * 0.95, col = denscol,
lwd = 1)
axis(2, at = pretty(dens$y)/max(dens$y) * 0.95, pretty(dens$y))
title("Color Key\nand Density Plot")
par(cex = 0.5)
mtext(side = 2, "Density", line = 2)
}else if (density.info == "histogram") {
<- hist(x, plot = FALSE, breaks = breaks)
h <- scale01(breaks, min.raw, max.raw)
hx <- c(h$counts, h$counts[length(h$counts)])
hy lines(hx, hy/max(hy) * 0.95, lwd = 1, type = "s",
col = denscol)
axis(2, at = pretty(hy)/max(hy) * 0.95, pretty(hy))
title("Color Key\nand Histogram")
par(cex = 0.5)
mtext(side = 2, "Count", line = 2)
}else title("Color Key")
}else plot.new()
$colorTable <- data.frame(low = retval$breaks[-length(retval$breaks)],
retvalhigh = retval$breaks[-1], color = retval$col)
invisible(retval)
}
<- function(c)
myclust
{hclust(c,method="average")
}
<- function(x,method="euclidian",...)
na.dist
{<- dist(x,...)
t.dist <- as.matrix(t.dist)
t.dist <- 1.1*max(t.dist,na.rm=TRUE)
t.limit is.na(t.dist)] <- t.limit
t.dist[<- as.dist(t.dist)
t.dist return(t.dist)
}
A “heatmap” of physico-chemical properties, in vitro TK parameters (Wetmore, et al., 2013), and TK parameters estimated from in vivo plasma concentration. Rows (chemicals) are clustered by Euclidean distance so that adjacent rows are more similar to each other. Each column (chemical properties) was scaled by the standard deviation of the column and the mean value was subtracted, such that a value of 0 corresponds to the mean and values of -1 or 1 correspond to values one standard deviation above or below the chemicals, respectively. In some cases, TK parameters could not be estimated (e.g., no oral data available for estimating Fbio and kgutabs). Fraction of the compound that is neutral, positively, or negatively ionized at pH 7.4 is indicated by “neutral ph74”, “positive ph74” and “negative ph74”. The color bar at the left-hand side indicates pharmaceuticals in grey and other chemicals in black.
<- chem.invivo.PK.aggregate.data[,c("MW",
physprop.matrix "logP",
"WaterSol",
"Neutral.pH74",
"Positive.pH74",
"Negative.pH74",
"Clint",
"Fup",
"Vdist",
"kelim",
"kgutabs",
"Fbio")]
<- chem.invivo.PK.aggregate.data$Compound
rnames =="Bensulide"] <- c("Bensulide.Joint","Bensulide.NHEERL","Bensulide.RTI")
rnames[rnames=="Propyzamide"] <- c("Propyzamide.Joint","Propyzamide.NHEERL","Propyzamide.RTI")
rnames[rnamesrownames(physprop.matrix) <- rnames
<- rep("Black",dim(physprop.matrix)[1])
row.side.cols sapply(chem.invivo.PK.aggregate.data$CAS,is.pharma)] <- "Grey"
row.side.cols[
apply(physprop.matrix,2,function(x) mean(x,na.rm=TRUE))
for (this.col in c(c(1,3,7,9:11),c(4:6,8,12))) physprop.matrix[,this.col] <- log10(10^-6+physprop.matrix[,this.col])
<- apply(physprop.matrix,2,function(x) (x-mean(x,na.rm=TRUE))/sd(x,na.rm=TRUE)) physprop.matrix
="in vivo Toxicokinetic Parameters"
main_titleheatmap.2(physprop.matrix,
hclustfun=myclust,
Colv=FALSE,
distfun=na.dist,
na.rm = TRUE,
scale="none",
trace="none",
RowSideColors=row.side.cols,
col=brewer.pal(11,"Spectral"),
margins=c(8,10))
# The following has to be adjusted manually:
rect(0.65, 0.01, 0.87, 0.78, border="blue")
text(0.75,0.81,expression(paste("Estimated from ",italic("In Vivo")," Data")))
The original scripts used a data.table called FitData that contains a lot of stuff we don’t need to make these figures. We recreate it from the httk object chem.invivo.PK.aggregate.data:
# Use joint analysis data from both labs:
<- subset(chem.invivo.PK.aggregate.data,Compound!="Bensulide"|Source=="Wambaugh et al. (2018), NHEERL/RTI")
FitData <- subset(FitData,Compound!="Propyzamide"|Source=="Wambaugh et al. (2018), NHEERL/RTI")
FitData # Rename some columns to match original data files:
$Compound.abbrev <- FitData$Abbrev
FitData# Add a column indicating chemical type:
$Chemical <- "Other"
FitDatasapply(FitData$CAS,is.pharma),"Chemical"] <- "Pharmaceutical" FitData[
Comparison of measured volumes of distribution (Vd) with predictions based upon in vitro data and in silico methods (Pearce, et al., 2017a; Schmitt, 2008). The solid line in each panel indicates the identity line (1:1, perfect predictions). Chemicals can be identified by their chemical abbreviation given in Table 1.
# Get rid of chemicals with Fup < LOD:
<- subset(FitData,!(CAS%in%subset(chem.physical_and_invitro.data,Human.Funbound.plasma==0)$CAS))
FitData.Fup
# Rename some columns to match original data files:
$SelectedVdist <- FitData.Fup$Vdist
FitData.Fup$SelectedVdist.sd <- FitData.Fup$Vdist.sd
FitData.Fup
#Predict volume of Distribution
$Vdist.1comp.pred <- sapply(FitData.Fup$CAS,
FitData.Fupfunction(x) suppressWarnings(calc_vdist(chem.cas=x,
species="Rat",
default.to.human = TRUE,
suppress.messages=TRUE)))
$Vdist.1comp.pred.nocal <- sapply(FitData.Fup$CAS,
FitData.Fupfunction(x) suppressWarnings(calc_vdist(chem.cas=x,
regression=FALSE,
species="Rat",
default.to.human = TRUE,
suppress.messages=TRUE)))
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred),data=subset(FitData.Fup,!is.na(SelectedVdist)&!is.na(Vdist.1comp.pred)))
FigVdista.fit summary(FigVdista.fit)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred),data=subset(FitData.Fup,!is.na(SelectedVdist)&!is.na(Vdist.1comp.pred)),weights=1/SelectedVdist.sd^2)
FigVdista.fit.weighted summary(FigVdista.fit)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred),data=subset(FitData.Fup,Chemical!="Other"&!is.na(Vdist.1comp.pred)))
FigVdista.fit.pharm summary(FigVdista.fit.pharm)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred),data=subset(FitData.Fup,Chemical=="Other"&!is.na(Vdist.1comp.pred)))
FigVdista.fit.other summary(FigVdista.fit.other)
dim(subset(FitData.Fup,!is.na(SelectedVdist.sd)&!is.na(Vdist.1comp.pred)))[1]
<- ggplot(data=subset(FitData.Fup,!is.na(Vdist.1comp.pred))) +
FigVdista geom_segment(color="Grey",aes(x=Vdist.1comp.pred,y=exp(log(SelectedVdist)-SelectedVdist.sd),xend=Vdist.1comp.pred,yend=exp(log(SelectedVdist)+SelectedVdist.sd)))+
geom_text(aes_string(y="SelectedVdist",
x="Vdist.1comp.pred",
label="Compound.abbrev",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(5*10^-2, 10^2)) +
scale_x_log10(label=scientific_10,limits = c(5*10^-2, 10^2)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
annotate("text", x = 1*10^-1, y = 3*10^1, label = "A",size=6) +
ylab(expression(paste(italic("In vivo")," estimated Volume of Distribution (L/kg)"))) +
xlab(expression(paste("Calibrated ",italic("In vitro")," predicted ",V[d]," (L/kg)"))) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred.nocal),data=subset(FitData.Fup,!is.na(Vdist.1comp.pred)))
FigVdistb.fit summary(FigVdistb.fit)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred.nocal),data=subset(FitData.Fup,!is.na(Vdist.1comp.pred)),weights=1/SelectedVdist.sd^2)
FigVdistb.fit.weighted summary(FigVdistb.fit)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred.nocal),data=subset(FitData.Fup,Chemical!="Other"&!is.na(Vdist.1comp.pred)))
FigVdistb.fit.pharm summary(FigVdistb.fit.pharm)
<- lm(log(SelectedVdist)~log(Vdist.1comp.pred.nocal),data=subset(FitData.Fup,Chemical=="Other"&!is.na(Vdist.1comp.pred)))
FigVdistb.fit.othersummary(FigVdistb.fit.other)
<- ggplot(data=subset(FitData.Fup,!is.na(Vdist.1comp.pred.nocal))) +
FigVdistb geom_segment(color="Grey",aes(x=Vdist.1comp.pred.nocal,y=exp(log(SelectedVdist)-SelectedVdist.sd),xend=Vdist.1comp.pred.nocal,yend=exp(log(SelectedVdist)+SelectedVdist.sd)))+
geom_text(aes_string(y="SelectedVdist",
x="Vdist.1comp.pred.nocal",
label="Compound.abbrev",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(5*10^-2, 10^2)) +
scale_x_log10(label=scientific_10,limits = c(5*10^-2, 10^2)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
annotate("text", x = 1*10^-1, y = 3*10^1, label = "B",size=6) +
ylab(expression(paste(italic("In vivo")," estimated Volume of Distribution (L/kg)"))) +
xlab(expression(paste("Original ",italic("In vitro")," predicted ",V[d]," (L/kg)"))) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=10,height=6)
multiplot(FigVdista,FigVdistb,cols=2,widths=c(1.75,1.75))
<- subset(FitData.Fup,!is.na(SelectedVdist)&!is.na(Vdist.1comp.pred))
Fig4a.data <- mean((log(Fig4a.data$Vdist.1comp.pred)-log(Fig4a.data$SelectedVdist))^2)
Fig4a.MSE
<- subset(FitData.Fup,!is.na(SelectedVdist)&!is.na(Vdist.1comp.pred.nocal))
Fig4b.data <- mean((log(Fig4b.data$Vdist.1comp.pred.nocal)-log(Fig4b.data$SelectedVdist))^2) Fig4b.MSE
Comparison of the TK clearance estimated from the in vivo data with the clearance predictions made using HTTK data. The more likely empirical TK model (either one or two-compartments, as in Figure 2) is selected for each chemical using the AIC (Akaike, 1974). A non-compartmental estimate of clearance is used if neither model is selected. Estimated standard deviation is indicated by a vertical line, and is often smaller than the plot point. The solid line indicates the identity line (1:1, perfect predictions), while the dotted and dashed lines indicate the linear regression (log-scale) trend-lines for pharmaceuticals and other chemicals, respectively. Chemicals can be identified by their chemical abbreviation given in Table 1.
#FitData.Fup$CLtot.1comp <- FitData.Fup$Vdist.1comp.meas*FitData.Fup$kelim.1comp.meas
#FitData.Fup$CLtot.1comp.sd <- (FitData.Fup$Vdist.1comp.meas.sd^2+FitData.Fup$kelim.1comp.meas.sd^2)^(1/2)
#FitData.Fup[is.na(CLtot.1comp.sd)]$CLtot.1comp.sd <- Inf
#FitData.Fup[is.na(SelectedCLtot.sd)]$SelectedClearance.sd <- Inf
$SelectedCLtot <- FitData.Fup$Vdist*FitData.Fup$kelim
FitData.Fup$SelectedCLtot.sd <- (FitData.Fup$Vdist.sd^2 +
FitData.Fup$kelim.sd^2)^(1/2)
FitData.Fup$CLtot.1comp.pred <- sapply(FitData.Fup$CAS,
FitData.Fupfunction(x) calc_total_clearance(chem.cas=x,
species="Rat",
default.to.human = TRUE,
suppress.messages=TRUE))
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,!is.na(SelectedCLtot.sd)))
Fig.SelectedClearance.fit summary(Fig.SelectedClearance.fit)
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,!is.na(SelectedCLtot.sd)),weights=1/SelectedCLtot.sd^2)
Fig.SelectedClearance.fit.weighted summary(Fig.SelectedClearance.fit.weighted)
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,Chemical!="Other"&!is.na(SelectedCLtot.sd)),weights=1/SelectedCLtot.sd^2)
Fig.SelectedClearance.fit.pharma summary(Fig.SelectedClearance.fit.pharma)
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,Chemical=="Other"&!is.na(SelectedCLtot.sd)),weights=1/SelectedCLtot.sd^2)
Fig.SelectedClearance.fit.othersummary(Fig.SelectedClearance.fit.other)
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,Chemical!="Other"))
Fig.SelectedClearance.fit.pharma summary(Fig.SelectedClearance.fit.pharma)
<- lm(log(SelectedCLtot)~log(CLtot.1comp.pred),data=subset(FitData.Fup,Chemical=="Other"))
Fig.SelectedClearance.fit.othersummary(Fig.SelectedClearance.fit.other)
<- ggplot(data=FitData.Fup,aes(y=SelectedCLtot,x=CLtot.1comp.pred)) +
Fig.SelectedClearancegeom_segment(data=subset(FitData.Fup,is.finite(SelectedCLtot.sd)),color="grey",aes(x=CLtot.1comp.pred,y=exp(log(SelectedCLtot)-SelectedCLtot.sd),xend=CLtot.1comp.pred,yend=exp(log(SelectedCLtot)+SelectedCLtot.sd)))+
geom_text(aes_string(y="SelectedCLtot",
x="CLtot.1comp.pred",
label="Compound.abbrev",
color="Chemical"))+
# geom_point(data=twocomp.data,color="White",size=2,aes(shape=Source))+
scale_y_log10(label=scientific_10,limits = c(10^-4, 10^3)) +
scale_x_log10(label=scientific_10,limits = c(10^-4, 10^3)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
geom_line(aes(x = CLtot.1comp.pred, y = exp(Fig.SelectedClearance.fit.pharma$coefficients[1]+Fig.SelectedClearance.fit.pharma$coefficients[2]*log(CLtot.1comp.pred))), colour = "darkturquoise", linetype="dotted", size=1.5) +
geom_line(aes(x = CLtot.1comp.pred, y = exp(Fig.SelectedClearance.fit.other$coefficients[1]+Fig.SelectedClearance.fit.other$coefficients[2]*log(CLtot.1comp.pred))), colour = "red", linetype="dashed", size=1.5) +
ylab(expression(paste(italic("In vivo")," estimated clearance (mg/L/h)"))) +
xlab(expression(paste(italic("In vitro")," predicted clearance (mg/L/h)"))) +
theme_bw() +
theme(legend.position="bottom")+
annotate("text",x = 10^2/3/3/3, y = 3*3*10^-4,size=4, label = lm_R2(Fig.SelectedClearance.fit.pharma,prefix="Pharmaceutical:"),parse=TRUE)+
annotate("text",x = 10^2/3/3/3, y = 3*3*3*10^-5,size=4, label = lm_R2(Fig.SelectedClearance.fit.other,prefix="Other:"),parse=TRUE)+
theme(plot.margin = unit(c(1,1,1,1), "cm"))+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=6,height=6)
print(Fig.SelectedClearance)
paste("with",with(FitData.Fup,sum(SelectedCLtot<CLtot.1comp.pred,na.rm=TRUE)),"chemicals over-estimated and",with(FitData.Fup,sum(SelectedCLtot>CLtot.1comp.pred,na.rm=TRUE)),"under-estimated")
Distribution of Gut Absorption Rate for Environmental and Pharmaceutical Chemicals.
$Selectedkgutabs <- FitData$kgutabs
FitData# Cutoff from optimizer is 1000:
<- ggplot(subset(FitData,Selectedkgutabs<999), aes(Selectedkgutabs, fill = Chemical)) +
Figkgutabs geom_histogram(binwidth=0.5) +
scale_x_log10(label=scientific_10) +
ylab("Number of Chemicals")+
xlab("Absorption Rate from Gut (1/h)")+
theme_bw() +
theme(legend.position="bottom")
#dev.new(width=6,height=6)
print(Figkgutabs)
mean(subset(FitData,Selectedkgutabs<999)$Selectedkgutabs)
min(subset(FitData,Selectedkgutabs<999)$Selectedkgutabs)
max(subset(FitData,Selectedkgutabs<999)$Selectedkgutabs)
median(subset(FitData,Selectedkgutabs<999)$Selectedkgutabs)
In panel A, the observed fraction of oral dose absorbed from the gut is compared with predictions made using Gastroplus (Simulations Plus, 2017). The solid line indicates the identity line (1:1, perfect predictions). These fractions are distrusted from nearly zero to effectively 100% (Panel B). Chemicals can be identified by their chemical abbreviation given in Table 1.
$SelectedFbio <- FitData$Fbio
FitData
<- ggplot(data=FitData) +
FigFbioa geom_text(aes_string(y="SelectedFbio",
x="Fbio.pred",
label="Compound.abbrev",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits=c(10^-3,1)) +
scale_x_log10(label=scientific_10,limits=c(10^-3,1)) +
# xlim(0, 1)+
# ylim(0, 1)+
annotate("text", x = .015/10, y = 0.55, label = "A",size=6) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated Fraction Bioavailable"))) +
xlab(expression(paste(italic("In silico")," predicted ",F[bio]))) +
# scale_color_brewer(palette="Set2") +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
<- ggplot(FitData, aes(SelectedFbio, fill = Chemical)) +
FigFbiob geom_histogram(binwidth=0.5) +
scale_x_log10(label=scientific_10,limits=c(10^-3,3)) +
annotate("text", x = .001, y = 18, label = "B",size=6) +
ylab("Number of Chemicals")+
xlab(expression(paste(italic("In vivo")," estimated Fraction Bioavailable"))) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),fill=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=10,height=6)
multiplot(FigFbioa,FigFbiob,cols=2,widths=c(1.75,1.75))
summary(lm(log(SelectedFbio)~log(Fbio.pred),data=FitData))
paste("Fbio ranged from",signif(min(FitData[FitData$Chemical=="Pharmaceutical","SelectedFbio"],na.rm=TRUE),2),"to",signif(max(FitData[FitData$Chemical=="Pharmaceutical","SelectedFbio"],na.rm=TRUE),2),"for pharmaceutical compounds, but was observed to be as low as", signif(min(FitData[FitData$Chemical=="Other","SelectedFbio"],na.rm=TRUE),3),"for other compounds.")
min(FitData$SelectedFbio,na.rm=TRUE)
Rat in vivo data were collected for diverse environmental chemicals to evaluate the predictive ability of HTTK, especially with respect to predicting steady-state serum concentration (Css). Chemicals can be identified by their chemical abbreviation given in Table 1. The abbreviations are centered at the measured and predicted values. The solid line indicates the identity line (1:1, perfect predictions). In panel A, the one-compartment model is parameterized with a predicted volume of distribution and clearance, based upon in vitro measured parameters. Fbio is assumed to be 100%. In panel B, the in vivo measured Fbio is used to reduce the amount of the oral dose absorbed in the one-compartment model, to illustrate the improvement possible if Fbio could be predicted accurately.
$SelectedFbio <- FitData$Fbio
FitData$SelectedCss <- FitData$Css
FitData$SelectedCss.sd <- FitData$Css.sd
FitData$Css.1comp.pred <- sapply(FitData$CAS,
FitDatafunction(x) calc_analytic_css(chem.cas=x,
species="Rat",
model="3compartmentss",
suppress.messages=TRUE,
parameterize.args = list(
default.to.human=TRUE,
adjusted.Funbound.plasma=TRUE,
regression=TRUE,
minimum.Funbound.plasma=1e-4)))
.1compCss.fit <- lm(log(SelectedCss)~log(Css.1comp.pred),data=FitData,na.rm=TRUE)
Fig.1compCss.fit.weighted <- lm(log(SelectedCss)~log(Css.1comp.pred),data=FitData,na.rm=TRUE,weights=1/SelectedCss.sd^2)
Fig.1compCss.fit.pharma <- lm(log(SelectedCss)~log(Css.1comp.pred),data=subset(FitData,Chemical!="Other"),na.rm=TRUE)
Fig.1compCss.fit.other <- lm(log(SelectedCss)~log(Css.1comp.pred),data=subset(FitData,Chemical=="Other"),na.rm=TRUE)
Fig
summary(Fig.1compCss.fit)
summary(Fig.1compCss.fit.pharma)
summary(Fig.1compCss.fit.other)
<- 10^-3
textx <- 1*10^1
texty
<- ggplot(data=FitData) +
Fig.Cssa geom_segment(color="grey",aes(x=Css.1comp.pred,y=exp(log(SelectedCss)-SelectedCss.sd),xend=Css.1comp.pred,yend=exp(log(SelectedCss)+SelectedCss.sd)))+
geom_text(size=4,aes_string(y="SelectedCss", x="Css.1comp.pred",label="Compound.abbrev",color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(5*10^-6, 110)) +
scale_x_log10(label=scientific_10,limits = c(5*10^-6, 110)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated ",C[ss]," (mg/L)"))) +
xlab(expression(paste(italic("In vitro")," predicted ",C[ss]," (mg/L)"))) +
# scale_color_brewer(palette="Set2") +
theme_bw() +
theme(legend.position="bottom")+
annotate("text", x = textx/15, y = 5*texty, label = "A",size=6) +
annotate("text",x = textx, y = texty,size=6, label = lm_R2(Fig.1compCss.fit),parse=TRUE)+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
# annotate("text",x = textx/3, y = texty/3,size=4, label = lm_R2(Fig.1compCss.fit.weighted,prefix="Weighted:"),parse=TRUE)
# annotate("text",x = textx, y = texty,size=4, label = lm_R2(Fig.1compCss.fit.pharma,prefix="Pharmaceutical:"),parse=TRUE)
# annotate("text",x = textx, y = texty/3,size=4, label = lm_R2(Fig.1compCss.fit.other,prefix="Other:"),parse=TRUE)
$Css.Bio <- FitData$Css.1comp.pred*FitData$SelectedFbio
FitData.1compCssb.fit <- lm(log(SelectedCss)~log(Css.Bio),data=FitData,na.rm=TRUE)
Fig.1compCssb.fit.weighted <- lm(log(SelectedCss)~log(Css.Bio),data=FitData,na.rm=TRUE,weights=1/SelectedCss.sd^2)
Fig.1compCssb.fit.pharma <- lm(log(SelectedCss)~log(Css.Bio),data=subset(FitData,Chemical!="Other"),na.rm=TRUE)
Fig.1compCssb.fit.other <- lm(log(SelectedCss)~log(Css.Bio),data=subset(FitData,Chemical=="Other"),na.rm=TRUE)
Fig
<- ggplot(data=FitData) +
Fig.Cssb geom_segment(color="grey",aes(x=Css.Bio,y=exp(log(SelectedCss)-SelectedCss.sd),xend=Css.Bio,yend=exp(log(SelectedCss)+SelectedCss.sd)))+
geom_text(size=4,aes_string(y="SelectedCss", x="Css.Bio",label="Compound.abbrev",color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(5*10^-6, 110)) +
scale_x_log10(label=scientific_10,limits = c(5*10^-6, 110)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated ",C[ss]," (mg/L)"))) +
xlab(expression(paste(italic("In vitro")," predicted ",C[ss]," (mg/L) Using Measured ", F[bio]))) +
# scale_color_brewer(palette="Set2") +
theme_bw() +
theme(legend.position="bottom")+
annotate("text", x = textx/15, y = 5*texty, label = "B",size=6) +
annotate("text",x = textx, y = texty,size=6, label = lm_R2(Fig.1compCssb.fit),parse=TRUE)+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=10,height=6)
multiplot(Fig.Cssa,Fig.Cssb,cols=2,widths=c(1.75,1.75))
Evaluation of Wambaugh et al. (2015) classification scheme for predicting errors made when using HTTK data to predict in vivo steady state plasma concentration (Css). Chemicals were placed into categories, depending upon the size of the error. “On the Order” represented the best case, where errors were within 3.2 times over or under the true value. Some chemicals were determined to be problematic due to limitations in the HTTK methods (e.g., plasma protein binding estimation) or failure to come to steady state. Wherever the chemical names overlap the vertical, gray bands, the observed errors are consistent with predicted error. Chemicals can be identified by their chemical abbreviation given in Table 1.
$TriageCat <- FitData$Triage.Call
FitData$CssResidual <- log10(FitData$Css.1comp.pred/FitData$Css)
FitData$TriageCat%in%c("Does Not Reach Steady State","Plasma Binding Assay Failed"),"TriageCat"]<-"Problem"
FitData[FitData$TriageCat <- factor(FitData$TriageCat,levels=c(">10x Underestimated",">3.2x Underestimated","On the Order",">3.2x Overestimated",">10x Overestimated","Problem"))
FitData
<- ggplot(data=subset(FitData,!is.na(TriageCat)&is.finite(CssResidual))) +
Fig.Triage geom_text(size=4,aes_string(y="CssResidual", x="TriageCat",label="Compound.abbrev",color="Chemical"))+
geom_segment(aes(x = factor(">10x Underestimated",levels=levels(FitData$TriageCat)), y = log10(1/10), xend = factor(">10x Underestimated",levels=levels(FitData$TriageCat)), yend = log10(1/30)), size=3,colour = "grey") +
# geom_segment(aes(x = factor(">3.2x Underestimated",levels=levels(FitData$TriageCat)), y = log10(1/10), xend = factor(">3.2x Underestimated",levels=levels(FitData$TriageCat)), yend = log10(1/3.2)), size=3,colour = "grey") +
geom_segment(aes(x = factor("On the Order",levels=levels(FitData$TriageCat)), y = log10(1/3.2), xend = factor("On the Order",levels=levels(FitData$TriageCat)), yend = log10(3.2)), size=3,colour = "grey") +
geom_segment(aes(x = factor(">3.2x Overestimated",levels=levels(FitData$TriageCat)), y = log10(3.2), xend = factor(">3.2x Overestimated",levels=levels(FitData$TriageCat)), yend = log10(10)), size=3,colour = "grey") +
geom_segment(aes(x = factor(">10x Overestimated",levels=levels(FitData$TriageCat)), y = log10(10), xend = factor(">10x Overestimated",levels=levels(FitData$TriageCat)), yend = log10(500)), size=3,colour = "grey") +
geom_hline(yintercept=0)+
geom_hline(yintercept=log10(1/10),linetype="dashed")+
geom_hline(yintercept=log10(1/3.2),linetype="dashed")+
geom_hline(yintercept=log10(3.2),linetype="dashed")+
geom_hline(yintercept=log10(10),linetype="dashed")+
geom_text(size=4,aes_string(y="CssResidual", x="TriageCat",label="Compound.abbrev",color="Chemical"))+
scale_y_continuous(name=expression(paste("Actual error in ",C[ss]," prediction")),breaks=c(log10(1/10),log10(1/3.2),0,log10(3.2),1),labels=c(">10x Under",">3.2x Under","On the Order",">3.2x Over",">10x Over")) +
xlab("Predicted Error") +
theme_bw() +
theme(legend.position="bottom")+
theme(axis.text.x = element_text(angle = 45, hjust = 1))+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=6,height=6)
print(Fig.Triage)
Evaluation of the ability of in vitro HTTK data, coupled with a one-compartment model, to predict important TK statistics like the maximum plasma concentration (Cmax) for characterizing tissue exposure. A single point is plotted for each combination of chemical, dose amount, and dose route, either intravenous (iv) or per oral (po). In panel A, the one-compartment model is parameterized with a predicted volume of distribution and clearance, based upon in vitro measured parameters. Fbio is assumed to be 100%. In panel B, the in vivo measured Fbio is used to reduce the amount of the oral dose absorbed in the one-compartment model, to illustrate the improvement possible if Fbio could be predicted accurately.
<- chem.invivo.PK.summary.data
PKstats # Add a column indicating chemical type:
$Chemical <- "Other"
PKstatssapply(PKstats$CAS,is.pharma),"Chemical"] <- "Pharmaceutical"
PKstats[
<- lm(log(Cmax)~log(Cmax.pred),data=subset(PKstats,is.finite(Cmax)))
FigCmaxa.fit summary(FigCmaxa.fit)
<- ggplot(data=subset(PKstats,is.finite(Cmax))) +
FigCmaxa geom_point(size=3,aes_string(y="Cmax",
x="Cmax.pred",
shape="Route",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(10^-4, 10^4)) +
scale_x_log10(label=scientific_10,limits = c(10^-4, 10^4)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated ",C[max]))) +
xlab(expression(paste(italic("In vitro")," predicted ",C[max]))) +
# scale_color_brewer(palette="Set2") +
annotate("text", x = 10^-3, y = 300, label = "A",size=6) +
annotate("text",x = 3*10^1, y = 10^-3, label = lm_R2(FigCmaxa.fit),parse=TRUE,size=6) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
<- lm(log(Cmax)~log(Cmax.pred.Fbio),data=subset(PKstats,is.finite(Cmax)))
FigCmaxb.fit summary(FigCmaxb.fit)
<- ggplot(data=subset(PKstats,is.finite(Cmax))) +
FigCmaxb geom_point(size=3,aes_string(y="Cmax",
x="Cmax.pred.Fbio",
shape="Route",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(10^-4, 10^4)) +
scale_x_log10(label=scientific_10,limits = c(10^-4, 10^4)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated ",C[max]))) +
xlab(expression(paste("Predicted ", C[max], " Using Measured ", F[bio ]))) +
annotate("text", x = 10^-3, y = 300, label = "B",size=6) +
annotate("text",x = 3*10^1, y = 10^-3, label = lm_R2(FigCmaxb.fit),parse=TRUE,size=6) +
# scale_color_brewer(palette="Set2") +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=10,height=6)
multiplot(FigCmaxa,FigCmaxb,cols=2,widths=c(1.75,1.75))
Evaluation of predictions for the time integrated plasma concentration (i.e., area under the curve or AUC). A single point is plotted for each combination of chemical, dose amount, and dose route, either intravenous (iv) or per oral (po). In panel A, the one-compartment model is parameterized with a predicted volume of distribution and clearance, based upon in vitro measured parameters. Fbio is assumed to be 100%. In panel B, the in vivo measured Fbio is used to reduce the amount of the oral dose absorbed in the one-compartment model, to illustrate the improvement possible if Fbio could be predicted accurately. The solid line in each panel indicates the identity line (1:1, perfect predictions).
<- lm(log(AUC)~log(AUC.pred),data=subset(PKstats,is.finite(log(AUC))))
FigAUCa.fit <- lm(log(AUC)~log(AUC.pred.Fbio),data=subset(PKstats,is.finite(log(AUC))))
FigAUCb.fit summary(FigAUCa.fit)
summary(FigAUCb.fit)
<- ggplot(data=subset(PKstats,is.finite(log(AUC)))) +
FigAUCa geom_point(size=3,aes_string(y="AUC",
x="AUC.pred",
shape="Route",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(10^-3, 10^4)) +
scale_x_log10(label=scientific_10,limits = c(10^-3, 10^4)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated AUC (mg*h/L)"))) +
xlab(expression(paste(italic("In vitro")," predicted Area under the Curve (AUC, mg*h/L)"))) +
annotate("text", x = 10^-2, y = 3000, label = "A",size=6) +
annotate("text",x = 3*10^1, y = 10^-2, label = lm_R2(FigAUCa.fit),parse=TRUE,size=6) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
<- ggplot(data=subset(PKstats,is.finite(log(AUC)))) +
FigAUCb geom_point(size=3,aes_string(y="AUC",
x="AUC.pred.Fbio",
shape="Route",
color="Chemical"))+
scale_y_log10(label=scientific_10,limits = c(10^-3, 10^4)) +
scale_x_log10(label=scientific_10,limits = c(10^-3, 10^4)) +
annotation_logticks() +
geom_abline(slope=1, intercept=0) +
ylab(expression(paste(italic("In vivo")," estimated AUC (mg*h/L)"))) +
xlab(expression(paste("Predicted AUC (mg*h/L) Using Measured ", F[bio]))) +
annotate("text", x = 10^-2, y = 3000, label = "B",size=6) +
annotate("text",x = 3*10^1, y = 10^-2, label = lm_R2(FigAUCb.fit),parse=TRUE,size=6) +
theme_bw() +
theme(legend.position="bottom")+
guides(shape=guide_legend(nrow=2,byrow=TRUE),color=guide_legend(nrow=2,byrow=TRUE))
#dev.new(width=10,height=6)
multiplot(FigAUCa,FigAUCb,cols=2,widths=c(1.75,1.75))