---
title:      Continuous Glucose Monitoring (CGM) Visualization
author:     Agustin Calatroni <a href='https://github.com/agstn/CGM'> <i style='background-color:white' class='fa fa-github'> Wonderful-Wednesdays </i></a>
date:       "`r format(Sys.Date(), format='%a %d %b %Y')`" 
output: 
  flexdashboard::flex_dashboard:
    self_contained: true
    source_code: embed
---

```{=html}
<style>

element.style {
width: 900px;
height: 550px;
margin-top: 10px;
margin-bottom: 10px;
}

</style>
```

```{r knitr-defaults}
knitr::opts_chunk$set(warning = FALSE, message = FALSE, comment = NA)
knitr::opts_chunk$set(cache = FALSE)
options(width=170)
```

```{r load-packages}
pacman::p_load(tidyverse, rio, gt)
pacman::p_load(labelled)
pacman::p_load(patchwork)
pacman::p_load(iglu)
pacman::p_load(partykit, ggparty)
pacman::p_load(ggdist)
```

```{r import-reshape-label}
CGM_data_1 <- import('https://raw.githubusercontent.com/VIS-SIG/Wonderful-Wednesdays/master/data/2021/2021-08-11/simulated_data.csv')

CGM_data_2 <- CGM_data_1 %>% 
   rename(VISITNUM_N = VISITNUM) %>% 
   mutate(VISITNUM_C = factor(VISITNUM_N, labels = c('Baseline','26-weeks','52-weeks')),
          VISITNUM_M = case_when(VISITNUM_N == 3  ~ '01',
                                 VISITNUM_N == 17 ~ '06',
                                 VISITNUM_N == 21 ~ '12'),
          TREATMENT = factor(TREATMENT ) %>% 
             fct_relevel("SOC","Rx low","Rx medium","Rx high") %>% 
             fct_recode(`Rx-Low` = "Rx low",
                        `Rx-Med` = "Rx medium",
                        `Rx-High` = "Rx high")) %>% 
   rename(VALUE_ORIG = 'Original_CGMValue',
          VALUE_SIM  = 'Simulated_CGMValue',
          TIME = 'CGMTIME',
          DAY = 'CGMDAY') %>% 
   select(SUBJID,
          TREATMENT,
          VISITNUM_N,
          VISITNUM_C,
          VISITNUM_M,
          DAY,
          TIME,
          VALUE_ORIG,
          VALUE_SIM) %>% 
   mutate(DAY_TIME = as.POSIXct(str_glue("2021-{VISITNUM_M}-0{DAY} {TIME}:00")),
          .after = TIME) 

var_label(CGM_data_2) <- list(
   SUBJID     = 'Subject Identification',
   TREATMENT  = 'Treatment Regimen',
   VISITNUM_N = 'Study visit NUM',
   VISITNUM_M = 'Study visit MONTH',
   VISITNUM_C = 'Study Visit NAME',
   DAY        = 'Day the CGM was measured',
   TIME       = 'Time of the day that the CGM value was measured',
   DAY_TIME   = 'Day/Time created',
   VALUE_ORIG =  'Original CGM value',
   VALUE_SIM  =  'Simulated CGM value')

export(CGM_data_2, "CGM_data.rds")
```

```{r iglue-function}
plot_ranges_2 <- function (data) {
   
   gl = id = below_54 = below_70 = in_range_70_180 = above_180 = above_250 = percent = NULL
   
   rm(list = c("gl", "id", "below_54", "below_70", "in_range_70_180", "above_180", "above_250", "percent"))
   subject = unique(data$id)
   ns = length(subject)
   if (ns > 1) {
      subject = subject[1]
      warning(paste("The provided data have", ns, "subjects. The plot will only be created for subject", 
                    subject))
      data = data %>% dplyr::filter(id == subject)
   }
   
   ranges <- agp_metrics(data, shinyformat = FALSE) %>% 
      dplyr::select(-c("id", "active_percent", "mean", "GMI", "CV")) %>% 
      dplyr::summarise(range = c("very_low", "low", "target", "high", "very_high"), 
                       percent = c(below_54, below_70 - below_54, in_range_70_180, above_180 - above_250, above_250))
   
   ranges = ranges %>% 
      dplyr::mutate(range = factor(range, levels = c("very_high",  "high", "target", "low", "very_low")))
   
   colors <- c("#F9B500", "#F9F000", "#48BA3C", "#F92D00", "#8E1B1B")
   
   ggplot(data = ranges, mapping = aes(y = '', fill = range, x = percent)) + 
      geom_bar(stat = "identity") + 
      scale_fill_manual(values = colors, 
                        drop = FALSE,
                        labels = c("Very High\n>250", 
                                   "High\n181-250", 
                                   "Target\n70-180", 
                                   "Low\n54-69", 
                                   "Very Low\n<54")) + 
      scale_x_continuous(breaks = seq(0, 100, 25)) + 
      labs(x = NULL,
           y = NULL,
           fill = "Percent (%) Time spent in \nstandardized glycemic ranges") + 
      scale_y_discrete(breaks = NULL) +
      guides(fill = guide_legend(reverse = TRUE,
                                 label.position = 'bottom')) 
}
```

```{r iglu-derive}
options(warn=-1)

CGM_iglu_data <- CGM_data_2 %>% 
   mutate(studyid = SUBJID) %>% 
   process_data(id = "SUBJID", timestamp = "DAY_TIME", glu = "VALUE_ORIG") %>% 
   select(-visitnum_n, -visitnum_m, -time.1, -value_sim, -day) %>% 
   rename(visit = visitnum_c) %>% 
   nest_by(studyid, treatment, visit)

CGM_iglu_data %>% 
   ungroup() %>% 
   count(studyid) %>% 
   filter(n == 3) %>% 
   pull(studyid) -> CGM_n3

export(CGM_n3, "CGM_n3.rds")

CGM_iglu_metrics <- CGM_iglu_data %>%
   rowwise() %>% 
   mutate(all_metrics  = list( data %>% data.frame() %>% all_metrics() )) %>% 
   mutate(panel     = list( 
      (plot_ranges_2(data)) / 
         (guide_area()) / 
         (plot_agp(data)   + ylim(39, 401)) / 
         (plot_daily(data) + ylim(39, 401) +
             geom_ribbon(aes(reltime, ymin = 70, ymax = 180), fill = "#48BA3C", alpha = 0.3) +
             geom_hline(yintercept = c(70, 180), color = "#48BA3C")) /
         plot_layout(heights = c(1, 1, 3, 3),
                     guides = 'collect') &
         theme_bw() &
         theme(legend.position='bottom',
               legend.key.height = unit(0.3, 'cm'),
               legend.key.width  = unit(1.5, 'cm'),
               strip.background = element_blank(), 
               strip.text = element_blank(),
               legend.title=element_text(size=9))
      
   ) 
   ) %>%
   unnest(c(all_metrics))

export(CGM_iglu_metrics, "CGM_iglu_metrics.rds")
```

# VISUALIZATION {data-navmenu="AGP"}

```{r iglu-trelliscope}
pacman::p_load(trelliscopejs)

CGM_iglu_metrics %>% 
   select(studyid, treatment, visit,
          ADRR, AUC, COGI, Conga, eA1C, GMI, GVP, HBGI, LBGI, IGC,
          panel) %>% 
   ungroup() %>% 
   set_labels(list(ADRR = 'average daily risk range', 
                   AUC = 'Area Under Curve', 
                   COGI = 'Continuous GlucoseMonitoring Index', 
                   Conga = 'Continuous Overall Net Glycemic Action', 
                   eA1C = 'Estimated A1c', 
                   GMI = 'Glucose Management Indicator', 
                   GVP = 'Glucose Variability Percentage', 
                   HBGI = 'High Blood Glucose Index', 
                   LBGI = 'Low Blood Glucose Index', 
                   IGC = 'Index of Glycemic Control')) %>%
   mutate(across(where(is.numeric), ~round(.x, 2))) %>% 
   trelliscope(name = 'CGM: Continuous Glucose Monitoring Visualization',
               desc = 'Display Ambulatory Glucose Profile (AGP) statistics (for subjects with ALL 3 visits)',
               panel_col = 'panel',
               path = './CGM-trelliscope',
               ncol = 3,
               nrow = 1,
               height = 900,
               width  = 700,
               state = list(sort = list(sort_spec('studyid')))
   )
```

# PLOT AGP {data-navmenu="AGP"}
```{r, out.width="1000px", out.extra="data-external=1"}
pacman::p_load(webshot)
knitr::include_url("https://irinagain.github.io/iglu/reference/plot_agp.html", height = "800px")
```

# PLOT RANGES {data-navmenu="AGP"}
```{r, out.width="1000px", out.extra="data-external=1"}
knitr::include_url("https://irinagain.github.io/iglu/reference/plot_ranges.html", height = "800px")
```

# PLOT DAILY {data-navmenu="AGP"}
```{r, out.width="1000px", out.extra="data-external=1"}
knitr::include_url("https://irinagain.github.io/iglu/reference/plot_daily.html", height = "800px")
```

# MODEL RESULTS

```{r party-model}
CGM_data_m1 <- CGM_iglu_metrics %>%
   select(studyid, treatment, visit, data) %>%
   rowwise() %>% 
   mutate(below_percent(data, targets_below = 53.9)[2], 
          below_percent(data, targets_below = 69.9)[2], 
          in_range_percent(data, target_ranges = list(c(70, 180)))[2], 
          above_percent(data, targets_above = 180.1)[2], 
          above_percent(data, targets_above = 250.1)[2]) %>% 
   mutate(below_69.9 = below_69.9 - below_53.9, 
          above_180.1 = above_180.1 - above_250.1) %>%
   select(-data) %>% 
   pivot_longer(cols = -c(1:3),
                names_to = 'state',
                values_to = 'pct') %>% 
   mutate(state = as.factor(state) %>% 
             fct_relevel('below_53.9',
                         'below_69.9',
                         'in_range_70_180',
                         'above_180.1',
                         'above_250.1') %>% 
             fct_rev()) 

target_plot <- CGM_data_m1 %>% 
   lmtree(pct ~ state | treatment + visit, data = .,
          alpha = 0.10, bonferroni  = FALSE) %>% 
   ggparty(terminal_space = 0.6, horizontal = TRUE) +
   geom_edge() +
   geom_edge_label() +
   geom_node_label(line_list = list(aes(label = splitvar),
                                    aes(label = gtsummary::style_pvalue(p.value, digits = 2, prepend_p = TRUE))),
                   line_gpar = list(list(size = 9),
                                    list(size = 9, fontface = 'bold')),
                   ids = "inner") +
   geom_node_plot(
      gglist = list(
         geom_bar(aes(x = pct, y = "", fill = state),
                  position = 'stack', stat = "summary", fun = "mean"),
         scale_y_discrete(breaks = NULL),
         scale_fill_manual(values = c("#F9B500", "#F9F000", "#48BA3C", "#F92D00", "#8E1B1B"), 
                           drop = FALSE, 
                           labels = c("Very High\n>250", 
                                      "High\n181-250", 
                                      "Target\n70-180", 
                                      "Low\n54-69", 
                                      "Very Low\n<54"),
                           guide = guide_legend(reverse = TRUE,
                                                label.position = 'bottom')),
         labs(y = NULL,
              x = "Percent (%)",
              fill = "Percent (%) Time spent in \nstandardized glycemic ranges"),
         theme_bw(),
         theme(legend.position='bottom',
               legend.key.height = unit(0.3, 'cm'),
               legend.key.width  = unit(1.5, 'cm'),
               strip.background = element_blank(), 
               strip.text = element_blank(),
               legend.title=element_text(size=9))),
      ids = "terminal",
      shared_axis_labels = TRUE
   )

ggsave(str_glue("CGM-models/CGM_target.png"),
       plot = target_plot,
       scale = 4,
       width = 900, height = 600, units = 'px')
```

![party-model](CGM-models/CGM_target.png){width="75%", height="75%"}

# DEFINITIONS {data-navmenu="OTHER METRICS"}

```{r}
CGM_metric <- import("CGM_metric.csv")

CGM_metric %>% 
   gt() %>% 
   cols_move_to_end(Metric_Time_dependent) %>% 
   cols_label(Metric_Name = "Name",
              Metric_Iglu = "iglu R function",
              Metric_Time_dependent = "Time Dependent") %>% 
   fmt_missing(Reference, missing_text = "-") %>% 
   fmt_markdown(c(Reference, Metric_Iglu)) %>% 
   cols_align('left') %>% 
   cols_width(Metric_Name ~ px(450),
              Metric_Iglu ~ px(250),
              Reference ~ px(250)) %>% 
   tab_options(table.font.size = "medium", 
               data_row.padding = px(2), 
               footnotes.padding = px(2), 
               source_notes.padding = px(2))
```

# MODEL RESULTS {data-navmenu="OTHER METRICS"}

```{r party-mod-viz}
# trick: https://www.johannesbgruber.eu/post/2021-07-28-let-users-choose-which-plot-you-want-to-show/

for(i in c("ADRR","AUC", "COGI", "Conga", "eA1C", "GMI", "GVP", "HBGI", "LBGI", "IGC")){
   
   metric_run <- sym(paste(i))
   
   metric_lab <- CGM_metric %>% 
      filter(str_detect(Metric_Name, paste(metric_run))) %>% 
      pull(Metric_Name)
   
   metric_plot <- CGM_iglu_metrics %>% 
      lmtree(formula(str_glue("{metric_run} ~ 1 | treatment +  visit")), 
             data = .,
             alpha = 0.10, bonferroni  = FALSE) %>% 
      ggparty(terminal_space = 0.4, horizontal = TRUE) +
      geom_edge() +
      geom_edge_label() +
      geom_node_label(line_list = list(aes(label = splitvar),
                                       aes(label = gtsummary::style_pvalue(p.value, digits = 2, prepend_p = TRUE))),
                      line_gpar = list(list(size = 9),
                                       list(size = 9, fontface = 'bold')),
                      ids = "inner") +
      geom_node_plot(
         gglist = list(
            stat_halfeye(aes(x = !!metric_run, y = ""), 
                         point_interval = mean_qi,
                         justification = -0.05),
            geom_rug(aes(x = !!metric_run), alpha = 0.25, sides = 't', length = unit(0.05, "npc")),
            geom_boxplot(aes(x = !!metric_run, y = ""), 
                         width = 0.30, outlier.shape = NA,
                         position = position_nudge(y = -0.25)),
            scale_y_discrete(breaks = NULL),
            labs(y = NULL,
                 x = metric_lab),
            theme_bw()),
         ids = "terminal",
         shared_axis_labels = TRUE) 
   
   ggsave(str_glue("CGM-models/{metric_run}.png"),
          plot = metric_plot,
          scale = 4,
          width = 850, height = 600, units = 'px')
   
}
```

<select id="imgList"> 
<option value="CGM-models/ADRR.png">ADRR (average daily risk range)</option>
<option value="CGM-models/AUC.png">AUC (Area Under Curve)</option>
<option value="CGM-models/COGI.png">COGI (Continuous GlucoseMonitoring Index)</option> 
<option value="CGM-models/Conga.png">CONGA (Continuous Overall Net Glycemic Action)</option>
<option value="CGM-models/eA1C.png">eA1c (Estimated A1c)</option>
<option value="CGM-models/GMI.png">GMI (Glucose Management Indicator)</option> 
<option value="CGM-models/GVP.png">GVP (Glucose Variability Percentage)</option>
<option value="CGM-models/HBGI.png">HBGI (High Blood Glucose Index)</option> 
<option value="CGM-models/LBGI.png">LBGI (Low Blood Glucose Index)</option> 
<option value="CGM-models/IGC.png">IGC (Index of Glycemic Control)</option>
</select>
<img src="CGM-models/ADRR.png" id="image" width="75%" height="75%"/>


<script type="text/javascript">             
var img = document.getElementById("image");

function setClass(e) {
  var select = e.target;
  img.src = select.options[select.selectedIndex].value;
  return false;
}

document.getElementById("imgList").onchange = setClass;
</script>

