Skip to content

Commit a5640c5

Browse files
authored
Merge pull request #17 from ropensci/devel
Update to v0.3.0
2 parents 1196d5c + e13b84a commit a5640c5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2563
-583
lines changed

.Rbuildignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
^\.travis\.yml$
66
^Meta$
77
^doc$
8+
.buildconfig
89
.git
910
scratch
1011
.gitignore

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ Meta
33
analysis
44
scratch
55
.Rhistory
6+
.buildconfig
67
..Rcheck
78
man/.Rhistory

CRAN-RELEASE

Lines changed: 0 additions & 2 deletions
This file was deleted.

DESCRIPTION

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: tacmagic
22
Type: Package
33
Title: Positron Emission Tomography Time-Activity Curve Analysis
4-
Version: 0.2.1
4+
Version: 0.3.0
55
Authors@R: c(person("Eric", "Brown",
66
role = c("aut", "cre"),
77
email = "[email protected]",
@@ -44,5 +44,6 @@ Suggests:
4444
testthat,
4545
knitr,
4646
rmarkdown,
47-
covr
47+
covr,
48+
vdiffr
4849
VignetteBuilder: knitr

NAMESPACE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Generated by roxygen2: do not edit by hand
22

33
S3method(as.data.frame,tac)
4+
S3method(change_units,numeric)
5+
S3method(change_units,tac)
46
S3method(plot,ref_Logan)
57
S3method(plot,tac)
68
S3method(summary,tac)
@@ -10,6 +12,7 @@ export(as.tac)
1012
export(batch_load)
1113
export(batch_tm)
1214
export(batch_voistat)
15+
export(change_units)
1316
export(cutoff_aiz)
1417
export(dvr)
1518
export(load_tac)
@@ -21,9 +24,11 @@ export(roi_ham_pib)
2124
export(roi_ham_stand)
2225
export(save_tac)
2326
export(split_pvc)
27+
export(suv)
2428
export(suvr)
2529
export(suvr_auc)
2630
export(tac_roi)
31+
export(tac_suv)
2732
importFrom(R.matlab,readMat)
2833
importFrom(grDevices,rainbow)
2934
importFrom(graphics,abline)

NEWS.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
# tacmagic 0.2.1
1+
# tacmagic News
22

3-
## Minor changes
3+
## tacmagic 0.3.0 (2019-06-06)
4+
5+
### Major changes
6+
7+
- Radioactivity unit conversion can now be done for tac objects and numeric objects
8+
- Conversion of a tac object to standardized uptake value (SUV) by controlling for weight and injected dose
9+
- Vignette updated with new features
10+
11+
## tacmagic 0.2.1 (2019-03-06)
12+
13+
### Minor changes
414

515
This version has no changes to features but addresses minor, mostly stylistic, issues for the initial CRAN release.
616

7-
# tacmagic 0.2.0
17+
## tacmagic 0.2.0 (2019-02-26)
818

9-
## Major changes
19+
### Major changes
1020

1121
This is the first release as a complete R package, and the version that has undergone open review with rOpenSci. The main features of tacmagic 0.2.0 are implemented and tested: loading PET time activity curve (tac) data from multiple formats, merging ROIs weighted for volume, calculating binding potential models including SUVR and DVR, basic plotting, and calculation of cut-off values. As tacmagic is still a new package and testing to date is based on few example files, it is essential to verify that all functions are behaving as expected when applied to your own data.

R/SUV.R

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
##################################
2+
## tacmagic - PET Analysis in R ##
3+
## SUV.R ##
4+
## (C) Eric E. Brown 2018-2019 ##
5+
## Beta version--check all work ##
6+
##################################
7+
8+
#' Calculate average SUV over time window, or maximum SUV
9+
#'
10+
#' Calculate the standardized uptake value (SUV) from a tac object, the
11+
#' participant's weight, and the tracer dose. These values may be in the tac
12+
#' object or manually supplied. The weight must be in kg, and the tracer units
13+
#' must be specified. The dose is converted to MBq, the tac is converted to
14+
#' kBq/cc, and the final SUV units are thus in g/cc. Aside from the tac object,
15+
#' the remaining parameters should be left NULL if the required data is in the
16+
#' tac object attributes (as can be done with batch_load()).
17+
#'
18+
#'@export
19+
#'@param tac time-activity curve object (decay-corrected)
20+
#'@param SUV_def vector of start times for window for SUV weighted average, or
21+
#' alternatively, "max" for the maximum ROI SUV value
22+
#'@param dose the injected tracer dose
23+
#'@param dose_unit unit of tracer dose (e.g. "MBq", "kBq", "mCi"...)
24+
#'@param weight_kg the participant's weight in kg
25+
#'@param ... When called from tm_batch, unused parameters may be supplied
26+
#'@return table of SUV values
27+
#'@family SUV functions
28+
#'@examples
29+
#' f <- system.file("extdata", "AD06.tac", package="tacmagic")
30+
#' fv <- system.file("extdata", "AD06_TAC.voistat", package="tacmagic")
31+
#' AD06_tac <- load_tac(f, format="PMOD")
32+
#' AD06_volume <- load_vol(fv, format="voistat")
33+
#' AD06 <- tac_roi(tac=AD06_tac, volumes=AD06_volume, ROI_def=roi_ham_pib(),
34+
#' merge=FALSE, PVC=FALSE)
35+
#' # dose and weight are fabricated for the example
36+
#' AD06_suvmax <- suv(AD06, "max", dose = 9.0, dose_unit = "mCi",
37+
#' weight_kg = 70)
38+
#' AD06_suv <- suv(AD06, c(3000, 3300, 3600), dose = 9.0, dose_unit = "mCi",
39+
#' weight_kg = 70)
40+
suv <- function(tac, SUV_def, dose=NULL, dose_unit=NULL, weight_kg=NULL, ...) {
41+
42+
if (!(any(is.null(attributes(tac)$tracer_dose),
43+
is.null(attributes(tac)$weight_kg),
44+
is.null(attributes(tac)$dose_unit)))) {
45+
46+
dose <- attributes(tac)$tracer_dose
47+
weight_kg <- attributes(tac)$weight_kg
48+
dose_unit <- attributes(tac)$dose_unit
49+
}
50+
51+
validate_suv_params(tac=tac, dose=dose, dose_unit=dose_unit,
52+
weight_kg=weight_kg)
53+
54+
if ( (SUV_def[1] != "max") && (!all(SUV_def %in% tac$start)) ) {
55+
stop("The SUV definition must be valid tac start times or \"max\"")
56+
}
57+
58+
tac <- tac_suv(tac=tac, dose=dose, dose_unit=dose_unit, weight_kg=weight_kg)
59+
60+
SUVtable <- new_table(tac, "SUV")
61+
62+
if (SUV_def[1] == "max") {
63+
for (ROI in names(tac)[-(1:2)]) {
64+
SUVtable[ROI, "SUV"] <- max(tac[,ROI])
65+
}
66+
} else {
67+
68+
frames <- match(SUV_def, tac$start)
69+
frame_weights <- tac$end[frames] - tac$start[frames]
70+
71+
for (ROI in names(tac)[-(1:2)]) {
72+
SUVtable[ROI, "SUV"] <- weighted.mean(tac[frames,][,ROI], frame_weights)
73+
}
74+
75+
}
76+
77+
return(SUVtable)
78+
}
79+
80+
#' Calculate SUV from TAC
81+
#'
82+
#' Calculate the standardized uptake value (SUV) time-activity curve from a tac
83+
#' object, the participant's weight, and the tracer dose. The weight must be in
84+
#' kg, and the tracer dose must be specified. The dose is converted to MBq, the
85+
#' tac is converted to kBq/cc, and the final SUV units are thus in g/cc. Aside
86+
#' from the tac object, the remaining parameters should be left NULL if the
87+
#' required data is in the tac object attributes (as can be done with
88+
#' batch_load().
89+
#'
90+
#'@export
91+
#'@param tac time-activity curve object (decay-corrected)
92+
#'@param dose the injected tracer dose
93+
#'@param dose_unit unit of tracer dose (e.g. "MBq", "kBq", "mCi"...)
94+
#'@param weight_kg the participant's weight in kg
95+
#'@return tac object with SUV values
96+
#'@family SUV functions
97+
#'@examples
98+
#' f <- system.file("extdata", "AD06.tac", package="tacmagic")
99+
#' fv <- system.file("extdata", "AD06_TAC.voistat", package="tacmagic")
100+
#' AD06_tac <- load_tac(f, format="PMOD")
101+
#' AD06_volume <- load_vol(fv, format="voistat")
102+
#' AD06 <- tac_roi(tac=AD06_tac, volumes=AD06_volume, ROI_def=roi_ham_pib(),
103+
#' merge=FALSE, PVC=FALSE)
104+
#' # dose and weight are fabricated for the example
105+
#' AD06_suv <- tac_suv(AD06, dose = 9.0, dose_unit = "mCi", weight_kg = 70)
106+
tac_suv <- function(tac, dose=NULL, dose_unit=NULL, weight_kg=NULL) {
107+
108+
if (!(any(is.null(attributes(tac)$tracer_dose),
109+
is.null(attributes(tac)$weight_kg),
110+
is.null(attributes(tac)$dose_unit)))) {
111+
112+
dose <- attributes(tac)$tracer_dose
113+
weight_kg <- attributes(tac)$weight_kg
114+
dose_unit <- attributes(tac)$dose_unit
115+
}
116+
117+
validate_suv_params(tac, dose, dose_unit, weight_kg)
118+
119+
if (attributes(tac)$activity_unit != "kBq/cc") {
120+
tac <- change_units(tac, to_unit = "kBq/cc")
121+
}
122+
123+
if (dose_unit != "MBq") dose <- change_units(dose, to_unit = "MBq", dose_unit)
124+
125+
tac[,-(1:2)] <- tac[,-(1:2)] / (dose / weight_kg)
126+
127+
attributes(tac)$activity_unit <- "g/mL"
128+
129+
if(!validate_tac(tac)) stop("The resulting tac object did not validate.")
130+
131+
return(tac)
132+
}
133+
134+
#'@noRd
135+
validate_suv_params <- function(tac, dose, dose_unit, weight_kg) {
136+
137+
if (!validate_tac(tac)) stop("Supplied tac file did not validate.")
138+
if (!is.numeric(dose)) stop("Dose must be numeric.")
139+
if (!(dose_unit %in% names(get_activity_unit_index()))) stop("Bad dose unit.")
140+
if (!is.numeric(weight_kg)) stop("Weight must be numeric.")
141+
142+
return(TRUE)
143+
}

R/batch_models.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#' @noRd
1414
model_definitions <- function() {
1515
return(c(SUVR=suvr,
16-
Logan=DVR_all_ref_Logan
16+
Logan=DVR_all_ref_Logan,
17+
SUV=suv
1718
))
1819
}
1920

R/batches.R

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ batch_tm <- function(all_tacs, models, custom_model=NULL, ...) {
8282
#'@param ROI_def Object that defines combined ROIs, see ROI_definitions.R
8383
#'@param PVC For PVC, true where the data is stored as _C in same tac file
8484
#'@param merge Passes value to tac_roi(); T to also incl. original atomic ROIs
85+
#'@param tracer_dose optionally, a vector of tracer doses (in the same order as
86+
#' participants), for SUV
87+
#'@param dose_unit if tracer_dose is specified, note the unit (e.g "MBq")
88+
#'@param weight_kg optionally, a vector of participant weights in kg, for SUV
8589
#'@return A list of data.frames, each is a participant's TACs
8690
#'@family Batch functions
8791
#'@examples
@@ -94,7 +98,8 @@ batch_tm <- function(all_tacs, models, custom_model=NULL, ...) {
9498
batch_load <- function(participants, dir="", tac_file_suffix=".tac",
9599
tac_format="PMOD", roi_m=FALSE, PVC=NULL,
96100
vol_file_suffix=NULL, vol_format=NULL,
97-
merge=NULL, ROI_def=NULL) {
101+
merge=NULL, ROI_def=NULL, tracer_dose=NULL,
102+
dose_unit=NULL, weight_kg=NULL) {
98103

99104
if (!roi_m) {
100105
if (!all(c(is.null(vol_format), is.null(vol_file_suffix), is.null(ROI_def),
@@ -111,9 +116,34 @@ batch_load <- function(participants, dir="", tac_file_suffix=".tac",
111116

112117
names(r) <- participants
113118

119+
if (!is.null(c(tracer_dose, dose_unit, weight_kg))) {
120+
validate_batch_suv_data(participants, tracer_dose, dose_unit, weight_kg)
121+
for (i in seq_along(r)) {
122+
attributes(r[[i]])$tracer_dose <- tracer_dose[[i]]
123+
attributes(r[[i]])$dose_unit <- dose_unit
124+
attributes(r[[i]])$weight_kg <- weight_kg[[i]]
125+
}
126+
}
127+
114128
return(r)
115129
}
116130

131+
#'@noRd
132+
validate_batch_suv_data <- function(participants, tracer_dose, dose_unit,
133+
weight_kg) {
134+
if (length(participants) != length(tracer_dose)) stop("Need tracer dose for
135+
each participant")
136+
if (!is.numeric(tracer_dose)) stop("Dose must be numeric.")
137+
138+
if (length(participants) != length(weight_kg)) stop("Need weight for each
139+
participant")
140+
if (!is.numeric(weight_kg)) stop("Weight must be numeric.")
141+
142+
if (length(dose_unit) != 1) stop("Only provide 1 dose unit.")
143+
if (!(dose_unit %in% names(get_activity_unit_index()))) stop("Bad dose unit.")
144+
145+
}
146+
117147
#' Obtain values from voistat files (using load_voistat() for a batch.
118148
#'
119149
#' For a vector of participant IDs and correspondingly named .voistat files,

R/loading.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,4 @@ load_voistat <- function(filename, ROI_def=NULL, model="VALUE") {
188188
names(VALUEtable) <- model
189189
return(VALUEtable)
190190
}
191+

R/loading_utilities.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ validate_tac <- function(tac) {
3333
status <- FALSE
3434
}
3535

36-
if (!(attributes(tac)$activity_unit %in% c("kBq/cc", "nCi/cc", "Bq/cc"))) {
36+
if (!(attributes(tac)$activity_unit %in% c("kBq/cc", "nCi/cc", "Bq/cc",
37+
"g/mL"))) {
3738
message("TAC data missing attribute activity_unit")
3839
status <- FALSE
3940
}

R/units.R

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
##################################
2+
## tacmagic - PET Analysis in R ##
3+
## units.R ##
4+
## (C) Eric E. Brown 2018-2019 ##
5+
## Beta version--check all work ##
6+
##################################
7+
8+
9+
#' @noRd
10+
get_activity_unit_index <- function() {
11+
# The equivalent to 1 kBq
12+
unit_index <- list(`Bq` = 0.001,
13+
`kBq` = 1,
14+
`MBq` = 1000,
15+
`nCi` = 0.037,
16+
`uCi` = 37,
17+
`mCi` = 37000,
18+
`Ci` = 37000000)
19+
return(unit_index)
20+
}
21+
22+
#' Convert radioactivity units
23+
#'
24+
#' Change the radioactivity units of a tac or numeric object to the specified
25+
#' desired units (e.g. Bq, kBq, MBq, nCi, uCi, mCi, Ci). For convenience, if the
26+
#' unit is per volume ("x/cc" or "x/mL"), the "/cc" part is ignored for the
27+
#' conversion.
28+
#'
29+
#'@export
30+
#'@param x time-activity curve or numeric object
31+
#'@param to_unit the desired unit (e.g. "kBq")
32+
#'@param from_unit not used for tac object (it is in the tac object), but for
33+
#' numeric objects, must be specified (e.g. "nCi")
34+
#'@return the converted object, same type as x
35+
#'@family unit functions
36+
#'@examples
37+
#' f <- system.file("extdata", "AD06.tac", package="tacmagic")
38+
#' AD06_tac <- load_tac(f, format="PMOD")
39+
#' AD06_tac_nCicc <- change_units(AD06_tac, to_unit = "nCi/cc")
40+
#'
41+
#' change_units(5, to_unit = "kBq", from_unit = "nCi")
42+
#' change_units(0.185, to_unit = "nCi", from_unit = "kBq")
43+
change_units <- function(x, to_unit, from_unit) UseMethod("change_units")
44+
45+
#'@noRd
46+
#'@export
47+
change_units.tac <- function(x, to_unit, from_unit = NULL) {
48+
49+
if(!validate_tac(x)) stop("Supplied tac file did not validate.")
50+
if(!is.null(from_unit)) stop("The from_unit is found within the tac object.")
51+
52+
unit_index <- get_activity_unit_index()
53+
54+
from <- sub("([A-Za-z]+).*", "\\1", attributes(x)$activity_unit)
55+
to <- sub("([A-Za-z]+).*", "\\1", to_unit)
56+
57+
x[,-(1:2)] <- x[,-(1:2)] * ( unit_index[[from]] / unit_index[[to]] )
58+
59+
attributes(x)$activity_unit <- to_unit
60+
61+
if(!validate_tac(x)) stop("Converted tac file did not validate.")
62+
63+
return(x)
64+
65+
}
66+
67+
#'@noRd
68+
#'@export
69+
change_units.numeric <- function(x, to_unit, from_unit) {
70+
71+
unit_index <- get_activity_unit_index()
72+
73+
from <- sub("([A-Za-z]+).*", "\\1", from_unit)
74+
to <- sub("([A-Za-z]+).*", "\\1", to_unit)
75+
76+
x <- x * ( unit_index[[from]] / unit_index[[to]] )
77+
78+
return(x)
79+
80+
}
81+

0 commit comments

Comments
 (0)