perimetry_helpers.R 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # redmont data helper functions
  2. #
  3. # ds 2019-07-05
  4. # ds 2021-03-01, tidied up.
  5. require(tidyverse)
  6. require(jsonlite)
  7. #' get_s_name
  8. #'
  9. #' get the name from the dataframe
  10. get_s_name <- function(d) {
  11. # theDate <- d$MedmontStudioExportFile$M600ThresholdExam$EntryDate[1]
  12. n <- tolower(
  13. paste0(
  14. d$MedmontStudioExportFile$Patient$LastName, "_",
  15. d$MedmontStudioExportFile$Patient$FirstName
  16. )
  17. )
  18. }
  19. #' convert medmont JSON to data frame
  20. #'
  21. #' returns
  22. #' list(result, the_points, d)
  23. #'
  24. read_medmont <- function(fname) {
  25. # get data
  26. j <- jsonlite::read_json(fname)
  27. d <- fromJSON(fname)
  28. # unpack what’s in JSON structure -----------------------------------------
  29. exam <- d$MedmontStudioExportFile[4]
  30. test <- exam$M600ThresholdExam$ThresholdTest$Test
  31. # e.g.
  32. # test$BlindSpot
  33. # Now look for the experiment data ----------------------------------------
  34. # test points are inside here
  35. n_points <- parse_integer(test$TestPoints$elements)
  36. the_points <- test$TestPoints$ThresholdTestPoint
  37. # exporting to CSV (tidy) style format --------------------------------------
  38. # this is how two write out a subset to CSV file...
  39. # make sure to take last set of measurements (if it's a list)
  40. # also length less than 5 (which is the right order of mag for ATTEMPTS, rather than points)
  41. # if there is only 1 test, a previous version of the check didn't seem to do the right thing/
  42. if (is_list(the_points) && length(the_points) < 5) {
  43. the_points <- the_points[[length(the_points)]]
  44. }
  45. result <- the_points %>%
  46. mutate(
  47. ecc = parse_double(Position$Ring),
  48. pa = parse_double(Position$Meridian),
  49. pa_rad = pi* pa / 180,
  50. Value = parse_double(Value)
  51. )
  52. }
  53. # plotting function -------------------------------------------------------
  54. plot_medmont <- function(the_points) {
  55. # NB-- the coord_polar step requires setting the starting point for 0 radians / 0 degrees...
  56. # to be offset from 12 o'clock
  57. the_points %>%
  58. mutate(
  59. xcoord = ecc * cos(pa_rad),
  60. ycoord = ecc * sin(pa_rad)
  61. ) %>%
  62. filter(State != "TS_UNTESTED") %>%
  63. ggplot(aes(x = xcoord, y = ycoord, size = Value, colour=State)) +
  64. geom_point(alpha = 0.9) +
  65. coord_fixed() +
  66. scale_colour_manual(values = c("red", "black", "gray")) + # "TS_SEEN" "TS_UNTESTED" "TS_NOT_SEEN"
  67. # coord_polar is kind of broken...
  68. # https://community.rstudio.com/t/making-coord-polar-behave-like-standard-polar-coordinate-plotting/3762/6
  69. # coord_polar(theta = "x", start = -pi/4, direction = -1) +
  70. theme_minimal()
  71. }
  72. # convert - combined function ---------------------------------------------
  73. #' read, make filename, write
  74. #'
  75. convert_medmont <- function(fname) {
  76. # read the data file
  77. data_list <- read_medmont(fname)
  78. # list(result, the_points, d)
  79. # filename from within?
  80. new_fname <- file.path(dirname(fname), paste0(get_s_name(data_list[[3]]), "-visualField", ".csv"))
  81. write_csv(data_list[[1]], new_fname)
  82. print(paste("wrote file:", new_fname))
  83. }