automeris-io / digitizeR

R package to extract data from plots and other images. Hosts WebPlotDigitizer locally.
GNU General Public License v3.0
81 stars 15 forks source link

Code: Read WebPlotDigitizer JSON data #3

Closed billdenney closed 4 years ago

billdenney commented 8 years ago

Thanks for writing WebPlotDigitizer. The attached function can be used to extract a data.frame with all DataSets in a WebPlotDigitizer JSON file. Hopefully it'll help with the package:

#' Read WebPlotDigitizer JSON data
#' 
#' @param txt Input txt as readable by fromJSON
#' @param include.pixel Include the pixel data in the returned data frame
#' @return A data.frame with colums for \code{x}, \code{y}, and \code{DataSet}
#'   and optionally (if \code{include.pixel=TRUE}) \code{x.pixel} and
#'   \code{y.pixel}.
#' @export
read.wpd <- function(txt, include.pixel=FALSE) {
  if (!requireNamespace("jsonlite"))
    stop("read.wpd requires the jsonlite package.  Please install the package and retry.")
  if (!requireNamespace("dplyr"))
    stop("read.wpd requires the dplyr package.  Please install the package and retry.")
  rawdata <- fromJSON(txt)
  if (!identical(names(rawdata), "wpd"))
    stop("The input does not appear to be WebPlotDigitizer data.")
  rawdata <- rawdata$wpd
  if (!identical(rawdata$version, c(3, 8))) {
    warning("read.wpd has only been tested with WebPlotDigitizer version 3.8")
  }
  if (length(rawdata$dataSeries$name) != length(rawdata$dataSeries$data)) {
    stop("Mismatch between length of data names and data sets.")
  }
  ret <- data.frame()
  for (i in seq_len(length(rawdata$dataSeries$name))) {
    if (nrow(rawdata$dataSeries$data[[i]]) > 0) {
      tmp <-
        dplyr::rename(rawdata$dataSeries$data[[i]],
                      x.pixel=x,
                      y.pixel=y)
      tmp <-
        dplyr::mutate(tmp,
                      x=sapply(tmp$value, FUN=function(x) x[1]),
                      y=sapply(tmp$value, FUN=function(x) x[2]))
      tmp$value <- NULL
      if (!include.pixel) {
        tmp$x.pixel <- tmp$y.pixel <- NULL
      }
      tmp$DataSet <- rawdata$dataSeries$name[i]
      ret <- rbind(ret, tmp)
    } else {
      warning("Data series number ", i, " (", rawdata$dataSeries$name[i], ") has no data.")
    }
  }
  ret
}
ankitrohatgi commented 8 years ago

Thank you for this! I am thinking this might be a good helper code that users can access from the website or the app directly. I'll think about it some more.

billdenney commented 8 years ago

I updated the code a bit to improve the documentation and to handle dataSeries with no data (an empty data frame in jsonlite output).