mathesong / bloodstream Goto Github PK
View Code? Open in Web Editor NEWA PET BIDS blood-processing tool
License: Other
A PET BIDS blood-processing tool
License: Other
According to the PET BIDS specification for blood data, the time column is required to be in column 1. However, if the json entries and the tsv entries are not aligned, but are all there in each json and tsv, I get the following error:
bloodstream('/Users/martinnorgaard/Downloads/COX-1','/Users/martinnorgaard/Downloads/COX-1/code/config_2023-06-14_id-ZiU9.json')
processing file: template.rmd
|....... | 8% [subsetting]
Quitting from lines 83-114 [subsetting] (template.rmd)
Error in dplyr::filter()
:
ℹ In argument: extension == "json" || extension == "tsv"
.
Caused by error in extension == "json" || extension == "tsv"
:
! 'length = 56' in coercion to 'logical(1)'
Backtrace:
Due to issues with rendering the quarto output document in the derivatives folder, I've had to render the output using rmarkdown. I think this is an issue with quarto itself, so this has been left for now. But ideally it would be nice for everything to be in quarto at a later point to be able to take advantage of future developments on that front.
Behavior:
processing file: template.rmd
|....... | 8% [subsetting]
Quitting from lines 83-114 [subsetting] (template.rmd)
Error in dplyr::filter()
:
ℹ In argument: extension == "json" || extension == "tsv"
.
Caused by error in extension == "json" || extension == "tsv"
:
! 'length = 56' in coercion to 'logical(1)'
Backtrace:
Currently, the output of the blood data is in Bq/mL which is in line with the PET-BIDS specification. However, on multiple occasions I have experienced the PET data being in kBq/mL and not Bq/mL. It would be nice if a check could be made with the _pet.json file "Units" to verify that PET data and blood data units are consistent. Ideally, the output of the blood data should be similar to the units in the PET data.
I'm getting an error in aif-fengconv
. Perhaps it's an environment issue? I'm using the container from PR #9.
Running bloodstream on ds004230 using the following config file:
{
"Subsets": {
"sub": [""],
"ses": [""],
"rec": [""],
"task": [""],
"run": [""],
"TracerName": [""],
"ModeOfAdministration": [""],
"InstitutionName": [""],
"PharmaceuticalName": [""]
},
"Model": {
"ParentFraction": {
"Method": ["Fit Hierarchically: HGAM"],
"set_ppf0": [true],
"starttime": [0],
"endtime": ["Inf"],
"gam_k": ["6"],
"hgam_formula": ["s(time, k=8) + s(time, sub, bs='fs', k=5) + s(time, pet, bs='fs', k=5)"]
},
"BPR": {
"Method": ["Fit Hierarchically: HGAM"],
"starttime": [0],
"endtime": ["Inf"],
"gam_k": [6],
"hgam_formula": ["s(time, k=8) + s(time, sub, bs='fs', k=5) + s(time, pet, bs='fs', k=5)"]
},
"AIF": {
"Method": ["Fit Individually: FengConv"],
"starttime": [0],
"endtime": ["Inf"],
"expdecay_props": ["NA", "NA"],
"inftime": ["NA"],
"spline_kb": [""],
"spline_ka_m": [""],
"spline_ka_a": [""]
},
"WholeBlood": {
"Method": ["Interpolation"],
"dispcor": [false],
"starttime": [0],
"endtime": ["Inf"],
"spline_kb": [""],
"spline_ka_m": [""],
"spline_ka_a": [""]
}
}
}
Generates the following error:
Quitting from lines 1054-1110 [aif-fengconv] (template.rmd)
Error in `mutate()`:
ℹ In argument: `aif_fit = map(aif, ~blmod_fengconv(time = .x$time, activity = .x$aif, Method = .x$Method))`.
Caused by error in `map()`:
ℹ In index: 1.
Caused by error in `if (startpars$t0 < 0) ...`:
! missing value where TRUE/FALSE needed
Traceback:
1. bloodstream(studypath = studypath, configpath = configfile)
2. rmarkdown::render(input = paste0(system.file(package = "bloodstream"),
. "/rmd/template.rmd"), output_file = paste0(studypath, "/derivatives/bloodstream",
. config_suffix, "/", "bloodstream_report_config", ifelse(stringr::str_length(config_suffix) >
. 0, yes = "-", no = ""), config_suffix, ".html"), params = list(configpath = configpath,
. studypath = studypath), knit_root_dir = studypath)
3. knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
4. process_file(text, output)
5. withCallingHandlers(withCallingHandlers(if (tangle) process_tangle(group) else process_group(group),
. error = function(e) if (xfun::pkg_available("rlang", "1.0.0")) rlang::entrace(e)),
. error = function(e) {
. setwd(wd)
. write_utf8(res, output %n% stdout())
. message("\nQuitting from lines ", paste(current_lines(i),
. collapse = "-"), if (labels[i] != "")
. sprintf(" [%s]", labels[i]), sprintf(" (%s)", knit_concord$get("infile")))
. })
6. withCallingHandlers(if (tangle) process_tangle(group) else process_group(group),
. error = function(e) if (xfun::pkg_available("rlang", "1.0.0")) rlang::entrace(e))
7. process_group(group)
8. process_group.block(group)
9. call_block(x)
10. block_exec(params)
11. eng_r(options)
12. in_input_dir(evaluate(code, envir = env, new_device = FALSE,
. keep_warning = if (is.numeric(options$warning)) TRUE else options$warning,
. keep_message = if (is.numeric(options$message)) TRUE else options$message,
. stop_on_error = if (is.numeric(options$error)) options$error else {
. if (options$error && options$include)
. 0L
. else 2L
. }, output_handler = knit_handlers(options$render, options)))
13. in_dir(input_dir(), expr)
14. evaluate(code, envir = env, new_device = FALSE, keep_warning = if (is.numeric(options$warning)) TRUE else options$warning,
. keep_message = if (is.numeric(options$message)) TRUE else options$message,
. stop_on_error = if (is.numeric(options$error)) options$error else {
. if (options$error && options$include)
. 0L
. else 2L
. }, output_handler = knit_handlers(options$render, options))
15. evaluate::evaluate(...)
16. evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos,
. debug = debug, last = i == length(out), use_try = stop_on_error !=
. 2L, keep_warning = keep_warning, keep_message = keep_message,
. log_echo = log_echo, log_warning = log_warning, output_handler = output_handler,
. include_timing = include_timing)
17. timing_fn(handle(ev <- withCallingHandlers(withVisible(eval_with_user_handlers(expr,
. envir, enclos, user_handlers)), warning = wHandler, error = eHandler,
. message = mHandler)))
18. handle(ev <- withCallingHandlers(withVisible(eval_with_user_handlers(expr,
. envir, enclos, user_handlers)), warning = wHandler, error = eHandler,
. message = mHandler))
19. withCallingHandlers(withVisible(eval_with_user_handlers(expr,
. envir, enclos, user_handlers)), warning = wHandler, error = eHandler,
. message = mHandler)
20. withVisible(eval_with_user_handlers(expr, envir, enclos, user_handlers))
21. eval_with_user_handlers(expr, envir, enclos, user_handlers)
22. eval(expr, envir, enclos)
23. eval(expr, envir, enclos)
24. aif_data %>% mutate(aif_fit = map(aif, ~blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method))) # at line 20-22 of file <text>
25. mutate(., aif_fit = map(aif, ~blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method)))
26. mutate.data.frame(., aif_fit = map(aif, ~blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method)))
27. mutate_cols(.data, dplyr_quosures(...), by)
28. withCallingHandlers(for (i in seq_along(dots)) {
. poke_error_context(dots, i, mask = mask)
. context_poke("column", old_current_column)
. new_columns <- mutate_col(dots[[i]], data, mask, new_columns)
. }, error = dplyr_error_handler(dots = dots, mask = mask, bullets = mutate_bullets,
. error_call = error_call, error_class = "dplyr:::mutate_error"),
. warning = dplyr_warning_handler(state = warnings_state, mask = mask,
. error_call = error_call))
29. mutate_col(dots[[i]], data, mask, new_columns)
30. mask$eval_all_mutate(quo)
31. eval()
32. map(aif, ~blmod_fengconv(time = .x$time, activity = .x$aif, Method = .x$Method))
33. map_("list", .x, .f, ..., .progress = .progress)
34. with_indexed_errors(i = i, names = names, error_call = .purrr_error_call,
. call_with_cleanup(map_impl, environment(), .type, .progress,
. n, names, i))
35. withCallingHandlers(expr, error = function(cnd) {
. if (i == 0L) {
. }
. else {
. message <- c(i = "In index: {i}.")
. if (!is.null(names) && !is.na(names[[i]]) && names[[i]] !=
. "") {
. name <- names[[i]]
. message <- c(message, i = "With name: {name}.")
. }
. else {
. name <- NULL
. }
. cli::cli_abort(message, location = i, name = name, parent = cnd,
. call = error_call, class = "purrr_error_indexed")
. }
. })
36. call_with_cleanup(map_impl, environment(), .type, .progress,
. n, names, i)
37. .f(.x[[i]], ...)
38. blmod_fengconv(time = .x$time, activity = .x$aif, Method = .x$Method)
39. blmod_feng_startpars(time, activity, expdecay_props)
40. .handleSimpleError(function (cnd)
. {
. if (i == 0L) {
. }
. else {
. message <- c(i = "In index: {i}.")
. if (!is.null(names) && !is.na(names[[i]]) && names[[i]] !=
. "") {
. name <- names[[i]]
. message <- c(message, i = "With name: {name}.")
. }
. else {
. name <- NULL
. }
. cli::cli_abort(message, location = i, name = name, parent = cnd,
. call = error_call, class = "purrr_error_indexed")
. }
. }, "missing value where TRUE/FALSE needed", base::quote(if (startpars$t0 <
. 0) {
. bloodrise <- bloodrise[blood$activity >= 0.1 * startpars$peakval,
. ]
. rise_lm <- lm(activity ~ time, data = bloodrise)
. rise_coef <- coef(rise_lm)
. startpars$t0 <- as.numeric(-1 * (rise_coef[1]/rise_coef[2]))
. }))
41. h(simpleError(msg, call))
42. cli::cli_abort(message, location = i, name = name, parent = cnd,
. call = error_call, class = "purrr_error_indexed")
43. rlang::abort(message, ..., call = call, use_cli_format = TRUE,
. .frame = .frame)
44. signal_abort(cnd, .file)
45. signalCondition(cnd)
46. (function (cnd)
. {
. local_error_context(dots, i = frame[[i_sym]], mask = mask)
. if (inherits(cnd, "dplyr:::internal_error")) {
. parent <- error_cnd(message = bullets(cnd))
. }
. else {
. parent <- cnd
. }
. message <- c(cnd_bullet_header(action), i = if (has_active_group_context(mask)) cnd_bullet_cur_group_label())
. abort(message, class = error_class, parent = parent, call = error_call)
. })(structure(list(message = c(i = "In index: 1."), trace = structure(list(
. call = list(aif_data %>% mutate(aif_fit = map(aif, ~blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method))), mutate(., aif_fit = map(aif,
. ~blmod_fengconv(time = .x$time, activity = .x$aif, Method = .x$Method))),
. mutate.data.frame(., aif_fit = map(aif, ~blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method))), mutate_cols(.data,
. dplyr_quosures(...), by), withCallingHandlers(for (i in seq_along(dots)) {
. poke_error_context(dots, i, mask = mask)
. context_poke("column", old_current_column)
. new_columns <- mutate_col(dots[[i]], data, mask,
. new_columns)
. }, error = dplyr_error_handler(dots = dots, mask = mask,
. bullets = mutate_bullets, error_call = error_call,
. error_class = "dplyr:::mutate_error"), warning = dplyr_warning_handler(state = warnings_state,
. mask = mask, error_call = error_call)), mutate_col(dots[[i]],
. data, mask, new_columns), mask$eval_all_mutate(quo),
. eval(), map(aif, ~blmod_fengconv(time = .x$time, activity = .x$aif,
. Method = .x$Method)), map_("list", .x, .f, ..., .progress = .progress),
. with_indexed_errors(i = i, names = names, error_call = .purrr_error_call,
. call_with_cleanup(map_impl, environment(), .type,
. .progress, n, names, i)), withCallingHandlers(expr,
. error = function(cnd) {
. if (i == 0L) {
. }
. else {
. message <- c(i = "In index: {i}.")
. if (!is.null(names) && !is.na(names[[i]]) &&
. names[[i]] != "") {
. name <- names[[i]]
. message <- c(message, i = "With name: {name}.")
. }
. else {
. name <- NULL
. }
. cli::cli_abort(message, location = i, name = name,
. parent = cnd, call = error_call, class = "purrr_error_indexed")
. }
. }), call_with_cleanup(map_impl, environment(), .type,
. .progress, n, names, i), .f(.x[[i]], ...), blmod_fengconv(time = .x$time,
. activity = .x$aif, Method = .x$Method), blmod_feng_startpars(time,
. activity, expdecay_props), .handleSimpleError(`<fn>`,
. "missing value where TRUE/FALSE needed", base::quote(if (startpars$t0 <
. 0) {
. bloodrise <- bloodrise[blood$activity >= 0.1 *
. startpars$peakval, ]
. rise_lm <- lm(activity ~ time, data = bloodrise)
. rise_coef <- coef(rise_lm)
. startpars$t0 <- as.numeric(-1 * (rise_coef[1]/rise_coef[2]))
. })), h(simpleError(msg, call)), cli::cli_abort(message,
. location = i, name = name, parent = cnd, call = error_call,
. class = "purrr_error_indexed"), rlang::abort(message,
. ..., call = call, use_cli_format = TRUE, .frame = .frame)),
. parent = c(0L, 0L, 0L, 3L, 4L, 4L, 6L, 7L, 0L, 9L, 10L, 11L,
. 10L, 10L, 14L, 15L, 0L, 17L, 18L, 19L), visible = c(TRUE,
. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
. TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE),
. namespace = c(NA, "dplyr", "dplyr", "dplyr", "base", "dplyr",
. NA, "dplyr", "purrr", "purrr", "purrr", "base", "purrr",
. "bloodstream", "kinfitr", "kinfitr", "base", "purrr", "cli",
. "rlang"), scope = c(NA, "::", ":::", ":::", "::", ":::",
. NA, "local", "::", ":::", ":::", "::", ":::", "local", "::",
. "::", "::", "local", "::", "::"), error_frame = c(FALSE,
. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,
. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
. FALSE)), row.names = c(NA, -20L), version = 2L, class = c("rlang_trace",
. "rlib_trace", "tbl", "data.frame")), parent = structure(list(
. message = "missing value where TRUE/FALSE needed", call = if (startpars$t0 <
. 0) {
. bloodrise <- bloodrise[blood$activity >= 0.1 * startpars$peakval,
. ]
. rise_lm <- lm(activity ~ time, data = bloodrise)
. rise_coef <- coef(rise_lm)
. startpars$t0 <- as.numeric(-1 * (rise_coef[1]/rise_coef[2]))
. }), class = c("simpleError", "error", "condition")), location = 1L,
. name = NULL, rlang = list(inherit = TRUE), call = map(aif,
. ~blmod_fengconv(time = .x$time, activity = .x$aif, Method = .x$Method)),
. use_cli_format = TRUE), class = c("purrr_error_indexed",
. "rlang_error", "error", "condition")))
47. abort(message, class = error_class, parent = parent, call = error_call)
48. signal_abort(cnd, .file)
Currently there are no tests. Developing a set of good tests should include tests for the individual functions, but should also include a mini fake dataset which can be parsed and read.
I want to add the possibility of including no config file at all, or including a named config file. This is not currently possible in the docker container. It should be a very easy fix, but I just need to make sure that the dockerfile doesn't error out on the command in which the config file is included.
When there are multiple Institution tags, bloodstream's parsing seems to pick all of them up and complains about multiple matches. Example in the MC1 data. The institutional tags are from dcm2niix and not part of default BIDS, but it's worthwhile fixing this so that the parser is more robust.
Some ideas to improve the outputs
ti
values from FengConv for instance.When running bloodstream in docker with the following on ubuntu 22 LTS:
docker run -v $HOME/ds004869:/data/ --user $(id -u):$(id -g) bloodstream
I get the following:
156/157 [sessioninfo]
157/157
Error in file(con, "w") : cannot open the connection
Calls: bloodstream ... <Anonymous> -> <Anonymous> -> write_utf8 -> writeLines -> file
In addition: Warning message:
In file(con, "w") : cannot open file 'template.knit.md': Permission denied
The documentations is a bit of a mess. It ought to be fixed up for if users wish to use the functions as standalones, and also to remember what all the pieces do when debugging..
Blood modelling weights are important for some models or some tracers. I need to add the option to have weights in both the web app, as well as in the kinfitr functions.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.