Skip to content

Commit 6783acc

Browse files
authored
Merge pull request #36 from mathesong/cran_requirements
Add time-based functionality for start end and t*, and fix notes on devtools::check
2 parents b16a069 + ecbf7af commit 6783acc

36 files changed

+667
-189
lines changed

DESCRIPTION

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Package: kinfitr
22
Title: Kinetic Modelling of PET Time Activity Curves
3-
Date: 2024-08-14
4-
Version: 0.8.0
3+
Date: 2025-10-14
4+
Version: 0.9.0
55
Authors@R: person("Granville", "Matheson", email = "[email protected]", role = c("aut", "cre"))
6-
Description: This package calculates outcome parameters for PET data using time activity curves (TACs). The will allow for more reproducible PET modelling research.
6+
Description: This package calculates outcome parameters for PET data using time activity curves (TACs). This will allow for more reproducible PET modelling research.
77
Depends:
88
R (>= 3.4.0)
99
License: MIT + file LICENSE
@@ -15,7 +15,6 @@ Imports:
1515
minpack.lm,
1616
forcats,
1717
RColorBrewer,
18-
plyr,
1918
tidyr,
2019
magrittr,
2120
scales,

NAMESPACE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,27 @@ export(weights_create)
146146
export(weights_create_bids)
147147
import(ggplot2)
148148
importFrom(dplyr,"%>%")
149+
importFrom(grDevices,dev.off)
150+
importFrom(grDevices,jpeg)
151+
importFrom(graphics,lines)
149152
importFrom(magrittr,"%>%")
153+
importFrom(rlang,":=")
154+
importFrom(stats,AIC)
155+
importFrom(stats,as.formula)
156+
importFrom(stats,coef)
157+
importFrom(stats,fitted)
158+
importFrom(stats,lag)
159+
importFrom(stats,lm)
160+
importFrom(stats,median)
161+
importFrom(stats,na.omit)
162+
importFrom(stats,pgamma)
163+
importFrom(stats,predict)
164+
importFrom(stats,residuals)
165+
importFrom(stats,start)
166+
importFrom(stats,time)
167+
importFrom(stats,weights)
168+
importFrom(utils,data)
169+
importFrom(utils,head)
170+
importFrom(utils,modifyList)
171+
importFrom(utils,read.delim)
172+
importFrom(utils,tail)

R/kinfitr_SUV.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
#' fit1 <- SUV(tac, t_tac, injRad = 150, bodymass = 85)
2828
#' fit2 <- SUV(tac, dur_tac = dur_tac, injRad = 150, bodymass = 85)
2929
#' fit3 <- SUV(tac, t_tac = t_tac, dur_tac = dur_tac, injRad = 150, bodymass = 85)
30-
#' fit4 <- SUV(tac, t_tac = t_tac, dur_tac = dur_tac, injRad = 150, bodymass = 85, frameStartEnd = c(1,5))
30+
#' fit4 <- SUV(tac, t_tac = t_tac, dur_tac = dur_tac, injRad = 150, bodymass = 85,
31+
#' frameStartEnd = c(1,5))
3132
#' @author Granville J Matheson, \email{mathesong@@gmail.com}
3233
#'
3334
#' @export

R/kinfitr_blooddata.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ bd_tidy_times <- function(blooddata,
584584
interpPoints = 6000) {
585585

586586
# Check that it actually is a blooddata object, even if old
587-
if( class(blooddata) != "blooddata" ) {
587+
if( !inherits(blooddata, "blooddata") ) {
588588
stop("The input data does not appear to be a blooddata object. Please make
589589
sure that the input data is correct.")
590590
}

R/kinfitr_bloodfuncs.R

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,14 @@ blood_interp <- function(t_blood, blood,
118118

119119
interptime <- pracma::linspace(0, maxtime, interpPoints)
120120

121-
interpcurves <- plyr::dlply(
122-
input, "Measure",
123-
function(x) pracma::interp1(x$Time,
124-
x$Value,
121+
interpcurves <- input %>%
122+
dplyr::group_split(Measure) %>%
123+
purrr::map(~ pracma::interp1(.x$Time,
124+
.x$Value,
125125
interptime,
126126
method = "linear"
127-
)
128-
)
127+
)) %>%
128+
purrr::set_names(unique(input$Measure))
129129

130130
if(is.null(aif)) {
131131

R/kinfitr_frtm.R

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,12 @@ plot_frtmfit <- function(frtmout, roiname = NULL, refname = NULL) {
285285
refname <- "Reference"
286286
}
287287

288-
measured <- plyr::rename(measured, c(
289-
"ROI.measured" = paste0(roiname, ".measured"),
290-
"Reference" = refname
291-
))
288+
measured <- dplyr::rename(measured,
289+
!!paste0(roiname, ".measured") := ROI.measured,
290+
!!refname := Reference
291+
)
292292

293-
fitted <- plyr::rename(fitted, c("ROI.fitted" = paste0(roiname, ".fitted")))
293+
fitted <- dplyr::rename(fitted, !!paste0(roiname, ".fitted") := ROI.fitted)
294294

295295
tidymeasured <- tidyr::gather(
296296
measured,

R/kinfitr_lin2tcm.R

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@
2424
#' not included, the integrals will be calculated using trapezoidal
2525
#' integration.
2626
#' @param frameStartEnd Optional: This allows one to specify the beginning and
27-
#' final frame to use for modelling, e.g. c(1,20). This can be used to assess time stability for example.
28-
#' @param timeStartEnd Optional. This allows one to specify the beginning and end time point instead of defining the frame numbers using frameStartEnd. This function will restrict the model to all time frames whose t_tac is between the values, i.e. c(0,5) will select all frames with midtimes during the first 5 minutes.
27+
#' final frame to use for modelling, e.g. c(1,20). This can be used to assess
28+
#' time stability for example.
29+
#' @param timeStartEnd Optional. This allows one to specify the beginning and
30+
#' end time point instead of defining the frame numbers using frameStartEnd.
31+
#' This function will restrict the model to all time frames whose t_tac is
32+
#' between the values, i.e. c(0,5) will select all frames with midtimes during
33+
#' the first 5 minutes.
2934
#'
3035
#' @return A list with a data frame of the fitted parameters \code{out$par}, the
3136
#' model fit object \code{out$fit}, a dataframe containing the TACs of the
@@ -55,10 +60,10 @@
5560
#' @author Granville J Matheson, \email{mathesong@@gmail.com}
5661
#'
5762
#' @references Oikonen, V (2003). Multilinear solution for 4-compartment model:
58-
#' I. Tissue compartments in series. Gjedde A, Wong DF 1990. Modeling
59-
#' neuroreceptor binding of radioligands in vivo. In: Quantitative imaging:
60-
#' neuroreceptors, neurotransmitters, and enzymes. (Eds. Frost JJ, Wagner HM
61-
#' Jr). Raven Press, 51-79.
63+
#' I. Tissue compartments in series. Gjedde A, Wong DF 1990. Modeling
64+
#' neuroreceptor binding of radioligands in vivo. In: Quantitative imaging:
65+
#' neuroreceptors, neurotransmitters, and enzymes. (Eds. Frost JJ, Wagner HM
66+
#' Jr). Raven Press, 51-79.
6267
#'
6368
#' @export
6469
lin2tcm <- function(t_tac, tac, input, weights = NULL, inpshift = 0,
@@ -67,7 +72,7 @@ lin2tcm <- function(t_tac, tac, input, weights = NULL, inpshift = 0,
6772

6873
# Convert timeStartEnd to frameStartEnd if needed
6974
if (is.null(frameStartEnd) && !is.null(timeStartEnd)) {
70-
frameStartEnd <- c(which(t_tac >= timeStartEnd[1])[1],
75+
frameStartEnd <- c(which(t_tac >= timeStartEnd[1])[1],
7176
tail(which(t_tac <= timeStartEnd[2]), 1))
7277
}
7378

@@ -347,8 +352,13 @@ plot_lin2tcmfit <- function(lin2tcmout, roiname = NULL) {
347352
#' not included, the integrals will be calculated using trapezoidal
348353
#' integration.
349354
#' @param frameStartEnd Optional: This allows one to specify the beginning and
350-
#' final frame to use for modelling, e.g. c(1,20). This can be used to assess time stability for example.
351-
#' @param timeStartEnd Optional. This allows one to specify the beginning and end time point instead of defining the frame numbers using frameStartEnd. This function will restrict the model to all time frames whose t_tac is between the values, i.e. c(0,5) will select all frames with midtimes during the first 5 minutes.
355+
#' final frame to use for modelling, e.g. c(1,20). This can be used to assess
356+
#' time stability for example.
357+
#' @param timeStartEnd Optional. This allows one to specify the beginning and
358+
#' end time point instead of defining the frame numbers using frameStartEnd.
359+
#' This function will restrict the model to all time frames whose t_tac is
360+
#' between the values, i.e. c(0,5) will select all frames with midtimes during
361+
#' the first 5 minutes.
352362
#' @param inpshift_vals Optional. The values of the inpshift to assess with the
353363
#' grid. By default, a grid between -1 and 1 with spacing of 0.01 will be
354364
#' used.
@@ -379,10 +389,10 @@ plot_lin2tcmfit <- function(lin2tcmout, roiname = NULL) {
379389
#' @author Granville J Matheson, \email{mathesong@@gmail.com}
380390
#'
381391
#' @references Oikonen, V (2003). Multilinear solution for 4-compartment model:
382-
#' I. Tissue compartments in series. Gjedde A, Wong DF 1990. Modeling
383-
#' neuroreceptor binding of radioligands in vivo. In: Quantitative imaging:
384-
#' neuroreceptors, neurotransmitters, and enzymes. (Eds. Frost JJ, Wagner HM
385-
#' Jr). Raven Press, 51-79.
392+
#' I. Tissue compartments in series. Gjedde A, Wong DF 1990. Modeling
393+
#' neuroreceptor binding of radioligands in vivo. In: Quantitative imaging:
394+
#' neuroreceptors, neurotransmitters, and enzymes. (Eds. Frost JJ, Wagner HM
395+
#' Jr). Raven Press, 51-79.
386396
#'
387397
#' @export
388398
lin2tcm_inpshiftProfile <- function(t_tac, tac, input, weights = NULL, vB = NULL,
@@ -391,7 +401,7 @@ lin2tcm_inpshiftProfile <- function(t_tac, tac, input, weights = NULL, vB = NULL
391401

392402
# Convert timeStartEnd to frameStartEnd if needed
393403
if (is.null(frameStartEnd) && !is.null(timeStartEnd)) {
394-
frameStartEnd <- c(which(t_tac >= timeStartEnd[1])[1],
404+
frameStartEnd <- c(which(t_tac >= timeStartEnd[1])[1],
395405
tail(which(t_tac <= timeStartEnd[2]), 1))
396406
}
397407

R/kinfitr_loganplot.R

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
#' @param input Data frame containing the blood, plasma, and parent fraction
1212
#' concentrations over time. This can be generated using the
1313
#' \code{blood_interp} function.
14-
#' @param tstarIncludedFrames The number of frames to be used in the regression
15-
#' model, i.e. the number of frames for which the function is linear after
16-
#' pseudo-equilibrium is reached. This is a count from the end of the
17-
#' measurement, so a value of 10 means that last 10 frames will be used. This
18-
#' value can be estimated using \code{Logan_tstar}.
14+
#' @param tstar The t* specification for regression. If tstar_type="frames",
15+
#' this is the number of frames from the end to include (e.g., 10 means last 10 frames).
16+
#' If tstar_type="time", this is the time point (in minutes) after which all frames
17+
#' with midpoints later than this time are included. This value can be estimated using \code{Logan_tstar}.
18+
#' @param tstar_type Either "frames" (default) or "time", specifying how to interpret tstar.
19+
#' @param tstarIncludedFrames Deprecated. Use 'tstar' with 'tstar_type="frames"' instead.
1920
#' @param weights Optional. Numeric vector of the weights assigned to each frame
2021
#' in the fitting. We include zero at time zero: if not included, it is added.
2122
#' If not specified, uniform weights will be used.
@@ -70,15 +71,44 @@
7071
#'
7172
#' @export
7273

73-
Loganplot <- function(t_tac, tac, input, tstarIncludedFrames, weights = NULL,
74-
inpshift = 0, vB = 0, dur = NULL, frameStartEnd = NULL, timeStartEnd = NULL) {
74+
Loganplot <- function(t_tac, tac, input, tstar, weights = NULL,
75+
inpshift = 0, vB = 0, dur = NULL, frameStartEnd = NULL, timeStartEnd = NULL,
76+
tstar_type = "frames", tstarIncludedFrames = NULL) {
7577

7678
# Convert timeStartEnd to frameStartEnd if needed
7779
if (is.null(frameStartEnd) && !is.null(timeStartEnd)) {
7880
frameStartEnd <- c(which(t_tac >= timeStartEnd[1])[1],
7981
tail(which(t_tac <= timeStartEnd[2]), 1))
8082
}
8183

84+
# Handle deprecated parameter
85+
if (!is.null(tstarIncludedFrames)) {
86+
warning("tstarIncludedFrames is deprecated and will be removed in a future version. Use 'tstar' with 'tstar_type=\"frames\"' instead", call. = FALSE)
87+
if (!missing(tstar)) {
88+
stop("Cannot specify both 'tstar' and 'tstarIncludedFrames'")
89+
}
90+
tstar <- tstarIncludedFrames
91+
tstar_type <- "frames"
92+
}
93+
94+
# Validate tstar_type
95+
tstar_type <- match.arg(tstar_type, c("frames", "time"))
96+
97+
# Handle missing tstar
98+
if (missing(tstar)) {
99+
tstar <- length(t_tac)
100+
tstar_type <- "frames"
101+
warning("No value specified for tstar: defaulting to including all frames. This may produce biased outcomes.", call. = FALSE)
102+
}
103+
104+
# Convert tstar based on type
105+
if (tstar_type == "time") {
106+
frames_after_tstar <- which(t_tac >= tstar)
107+
tstarIncludedFrames <- length(frames_after_tstar)
108+
} else {
109+
tstarIncludedFrames <- tstar
110+
}
111+
82112
# Tidying
83113

84114
tidyinput <- tidyinput_art(t_tac, tac, weights, frameStartEnd)

R/kinfitr_ma1.R

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
#' zero: if not included, it is added.
99
#' @param input Data frame containing the blood, plasma, and parent fraction concentrations over time. This can be generated
1010
#' using the \code{blood_interp} function.
11-
#' @param tstarIncludedFrames The number of frames to be used in the regression model, i.e. the number of frames for which
12-
#' the function is linear after pseudo-equilibrium is reached. This is a count from the end of the measurement, so a value of
13-
#' 10 means that last 10 frames will be used. This value can be estimated using \code{ma1_tstar}.
11+
#' @param tstar The t* specification for regression. If tstar_type="frames",
12+
#' this is the number of frames from the end to include (e.g., 10 means last 10 frames).
13+
#' If tstar_type="time", this is the time point (in minutes) after which all frames
14+
#' with midpoints later than this time are included. This value can be estimated using \code{ma1_tstar}.
15+
#' @param tstar_type Either "frames" (default) or "time", specifying how to interpret tstar.
16+
#' @param tstarIncludedFrames Deprecated. Use 'tstar' with 'tstar_type="frames"' instead.
1417
#' @param weights Optional. Numeric vector of the weights assigned to each frame in the fitting. We include zero at time zero:
1518
#' if not included, it is added. If not specified, uniform weights will be used.
1619
#' @param inpshift Optional. The number of minutes by which to shift the timing of the input data frame forwards or backwards.
@@ -53,8 +56,9 @@
5356
#'
5457
#' @export
5558

56-
ma1 <- function(t_tac, tac, input, tstarIncludedFrames, weights = NULL,
57-
inpshift = 0, vB = 0, dur = NULL, frameStartEnd = NULL, timeStartEnd = NULL) {
59+
ma1 <- function(t_tac, tac, input, tstar, weights = NULL,
60+
inpshift = 0, vB = 0, dur = NULL, frameStartEnd = NULL, timeStartEnd = NULL,
61+
tstar_type = "frames", tstarIncludedFrames = NULL) {
5862

5963

6064
# Convert timeStartEnd to frameStartEnd if needed
@@ -63,6 +67,34 @@ ma1 <- function(t_tac, tac, input, tstarIncludedFrames, weights = NULL,
6367
tail(which(t_tac <= timeStartEnd[2]), 1))
6468
}
6569

70+
# Handle deprecated parameter
71+
if (!is.null(tstarIncludedFrames)) {
72+
warning("tstarIncludedFrames is deprecated and will be removed in a future version. Use 'tstar' with 'tstar_type=\"frames\"' instead", call. = FALSE)
73+
if (!missing(tstar)) {
74+
stop("Cannot specify both 'tstar' and 'tstarIncludedFrames'")
75+
}
76+
tstar <- tstarIncludedFrames
77+
tstar_type <- "frames"
78+
}
79+
80+
# Validate tstar_type
81+
tstar_type <- match.arg(tstar_type, c("frames", "time"))
82+
83+
# Handle missing tstar
84+
if (missing(tstar)) {
85+
tstar <- length(t_tac)
86+
tstar_type <- "frames"
87+
warning("No value specified for tstar: defaulting to including all frames. This may produce biased outcomes.", call. = FALSE)
88+
}
89+
90+
# Convert tstar based on type
91+
if (tstar_type == "time") {
92+
frames_after_tstar <- which(t_tac >= tstar)
93+
tstarIncludedFrames <- length(frames_after_tstar)
94+
} else {
95+
tstarIncludedFrames <- tstar
96+
}
97+
6698
# Tidying
6799

68100
tidyinput <- tidyinput_art(t_tac, tac, weights, frameStartEnd)
@@ -210,9 +242,9 @@ plot_ma1fit <- function(ma1out, roiname = NULL) {
210242
roiname <- "ROI"
211243
}
212244

213-
measured <- plyr::rename(measured, c("Target.measured" = paste0(roiname, ".measured")))
245+
measured <- dplyr::rename(measured, !!paste0(roiname, ".measured") := Target.measured)
214246

215-
fitted <- plyr::rename(fitted, c("Target.fitted" = paste0(roiname, ".fitted")))
247+
fitted <- dplyr::rename(fitted, !!paste0(roiname, ".fitted") := Target.fitted)
216248

217249
tidymeasured <- tidyr::gather(
218250
measured,

R/kinfitr_miscfuncs.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ fix_multstartpars <- function(start, lower, upper, multstart_iter, multstart_low
397397

398398
### Adding multstart boundaries
399399
if (!is.null(multstart_lower)) {
400-
if (class(multstart_lower) != "list" ||
400+
if (!inherits(multstart_lower, "list") ||
401401
sum(!(names(multstart_lower) %in% parnames)) > 0) { # Are there any names not in start?
402402
stop("multstart_lower should be a named list whose names match the parameters to be fitted")
403403
}
@@ -408,7 +408,7 @@ fix_multstartpars <- function(start, lower, upper, multstart_iter, multstart_low
408408
}
409409

410410
if (!is.null(multstart_upper)) {
411-
if (class(multstart_upper) != "list" ||
411+
if (!inherits(multstart_upper, "list") ||
412412
sum(!(names(multstart_upper) %in% parnames)) > 0) { # Are there any names not in start?
413413
stop("multstart_upper should be a named list whose names match the parameters to be fitted")
414414
}

0 commit comments

Comments
 (0)