|
| 1 | +#' Convert TrackMate XML file to CSV format |
| 2 | +#' |
| 3 | +#' @description This function reads a TrackMate XML file and save it as a csv |
| 4 | +#' file for use in other contexts. |
| 5 | +#' |
| 6 | +#' There are options to: |
| 7 | +#' - filter out traces with less than n points |
| 8 | +#' - save in a location other than Output/Data |
| 9 | +#' - select columns for export |
| 10 | +#' - x and y can be scaled (default) or converted to pixels |
| 11 | +#' |
| 12 | +#' The typical scenario is that the XML file is in `input_dir` and the |
| 13 | +#' converted csv will be saved to `output_dir`. Any subfolders below |
| 14 | +#' `input_dir` will be recreated in `output_dir`. If a full path is supplied |
| 15 | +#' as the `path`, the `input_dir` should be adjusted to be the directory |
| 16 | +#' containing the XML file or containing the subdirectory containing the XML |
| 17 | +#' file. |
| 18 | +#' |
| 19 | +#' Note: the calibration of the input TrackMate XML file must be correct. |
| 20 | +#' |
| 21 | +#' @param path path to the TrackMate XML file |
| 22 | +#' @param min_points minimum number of points in a trace to be included in the |
| 23 | +#' output csv file (default: 10). Set to 0 to include all traces. |
| 24 | +#' @param input_dir directory where the input XML files are located (default: |
| 25 | +#' "Data/") |
| 26 | +#' @param output_dir directory where the output csv file will be saved (default: |
| 27 | +#' "Output/Data/"). |
| 28 | +#' @param slim logical, if TRUE, only the minimum data required to process the |
| 29 | +#' tracks is read (default: TRUE) |
| 30 | +#' @param columns columns to be included in the output csv file (default: c(" |
| 31 | +#' trace", "frame", "y", "x")). Set to NULL to include all columns from the |
| 32 | +#' TrackMate XML file. |
| 33 | +#' @param pixels logical, if TRUE, x and y will be converted to pixels using the |
| 34 | +#' calibration information from the TrackMate XML file (default: FALSE) |
| 35 | +#' @param no_save logical, if TRUE, the output csv file will not be saved and a |
| 36 | +#' data frame returned to the user (default: FALSE) |
| 37 | +#' |
| 38 | +#' @returns saves a csv file |
| 39 | +#' @export |
| 40 | +#' |
| 41 | +#' @examples |
| 42 | +#' \dontrun{ |
| 43 | +#' files <- list.files(path = "Data", pattern = "\\.xml$", full.names = TRUE) |
| 44 | +#' lapply(files, convert_trackmate_xml_to_csv) |
| 45 | +#' } |
| 46 | +convert_trackmate_xml_to_csv <- function(path = NULL, |
| 47 | + min_points = 10, |
| 48 | + input_dir = "Data/", |
| 49 | + output_dir = "Output/Data/", |
| 50 | + slim = TRUE, |
| 51 | + columns = c("trace", "frame", "y", "x"), |
| 52 | + pixels = FALSE, |
| 53 | + no_save = FALSE) { |
| 54 | + XMLpath <- path |
| 55 | + if (is.null(XMLpath)) { |
| 56 | + stop("Please provide a path to the TrackMate XML file.") |
| 57 | + } |
| 58 | + # determine the subpath of path minus the input_dir |
| 59 | + subpath <- gsub(paste0("^", input_dir), "", XMLpath) |
| 60 | + # if subpath starts with a slash, remove it |
| 61 | + subpath <- gsub("^/", "", subpath) |
| 62 | + # create the output path by combining output_dir with the subpath, but |
| 63 | + # replacing the .xml extension with .csv |
| 64 | + output_csv <- file.path(output_dir, subpath) |
| 65 | + output_csv <- sub("\\.xml$", ".csv", output_csv) |
| 66 | + |
| 67 | + # create output directory if it doesn't exist |
| 68 | + output_dir_full <- dirname(output_csv) |
| 69 | + if (!dir.exists(output_dir_full)) { |
| 70 | + dir.create(output_dir_full, recursive = TRUE) |
| 71 | + } |
| 72 | + |
| 73 | + # now read the trackmate XML file |
| 74 | + df <- readTrackMateXML(XMLpath, slim = TRUE) |
| 75 | + data <- df[[1]] |
| 76 | + calib <- df[[2]] |
| 77 | + |
| 78 | + # filter traces if they have less than min_points |
| 79 | + # and min_points is greater than 0 |
| 80 | + if (min_points > 0) { |
| 81 | + ntrace <- data %>% |
| 82 | + group_by(trace) %>% |
| 83 | + summarise(n = n()) %>% |
| 84 | + filter(n >= min_points) |
| 85 | + tr <- ntrace$trace |
| 86 | + data <- data[data$trace %in% c(tr), ] |
| 87 | + } |
| 88 | + |
| 89 | + # select columns for export |
| 90 | + if (!is.null(columns)) { |
| 91 | + # if user has supplied a list of columns to export, check that they include |
| 92 | + # trace, frame, x and y |
| 93 | + columns_required <- c("trace", "frame", "y", "x") |
| 94 | + columns <- unique(c(columns, columns_required)) |
| 95 | + if (!all(columns %in% colnames(data))) { |
| 96 | + stop("Some columns specified in 'columns' are not present in the |
| 97 | + TrackMate XML data. Please check the column names and try again.") |
| 98 | + } |
| 99 | + data <- data[, columns, drop = FALSE] |
| 100 | + } |
| 101 | + |
| 102 | + # trace names are strings but we will re-embed them as integers and ensure |
| 103 | + # that they are consecutive |
| 104 | + data$trace <- as.integer(as.factor(data$trace)) |
| 105 | + # micron to pixel conversion if required |
| 106 | + if (pixels) { |
| 107 | + cat("Converting x and y to pixels using calibration information from |
| 108 | + TrackMate XML file\n") |
| 109 | + data$y <- round(data$y / calib[1, 1]) |
| 110 | + data$x <- round(data$x / calib[1, 1]) |
| 111 | + } |
| 112 | + if (no_save) { |
| 113 | + return(data) |
| 114 | + } else { |
| 115 | + write.csv(data, file = output_csv, row.names = FALSE) |
| 116 | + } |
| 117 | +} |
0 commit comments