Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust ylim to display a complete plot #192

Closed
3 tasks done
feiyis1 opened this issue Mar 24, 2023 · 9 comments · Fixed by insightsengineering/teal.goshawk#308
Closed
3 tasks done

Adjust ylim to display a complete plot #192

feiyis1 opened this issue Mar 24, 2023 · 9 comments · Fixed by insightsengineering/teal.goshawk#308
Assignees
Labels
bug Something isn't working core priority

Comments

@feiyis1
Copy link

feiyis1 commented Mar 24, 2023

What happened?

ylim is not allowing to display the complete density distribution plot (in Extrarenal Lupus Data Mart UAT app).
Screen Shot 2023-03-24 at 2 29 11 PM

sessionInfo()

R version 4.1.1 (2021-08-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux

Matrix products: default
BLAS/LAPACK: /usr/lib64/libopenblas-r0.3.3.so

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct.

Contribution Guidelines

  • I agree to follow this project's Contribution Guidelines.

Security Policy

  • I agree to follow this project's Security Policy.
@feiyis1 feiyis1 added the bug Something isn't working label Mar 24, 2023
@feiyis1
Copy link
Author

feiyis1 commented Mar 24, 2023

Failed to assign the issue to myself and to the "NEST Program Roadmap" project after applying for Insights Engineering User Onboarding and joining in NEST users group.

@npaszty
Copy link
Contributor

npaszty commented Jul 25, 2024

@m7pr

is this something that can be sorted out easily. don't think scientists would want to present a plot that is not fully displayed.

added priority label to keep it highlighted until I hear from you about the magnitude of effort ot fix.

@m7pr
Copy link
Contributor

m7pr commented Jul 26, 2024

Hey @feiyis1 and @npaszty thank you for reporting that and sorry for the late reply.

The outcome of g_density_distribution_plot() is regular ggplot so you can do whathever suits you with the output. Please see below example

#### Data preparations
library(goshawk)
library(stringr)

# original ARM value = dose value
arm_mapping <- list(
  "A: Drug X" = "150mg QD", "B: Placebo" = "Placebo", "C: Combination" = "Combination"
)
color_manual <- c("150mg QD" = "#000000", "Placebo" = "#3498DB", "Combination" = "#E74C3C")

ADLB <- rADLB
var_labels <- lapply(ADLB, function(x) attributes(x)$label)
ADLB <- ADLB %>%
  mutate(AVISITCD = case_when(
    AVISIT == "SCREENING" ~ "SCR",
    AVISIT == "BASELINE" ~ "BL",
    grepl("WEEK", AVISIT) ~
      paste(
        "W",
        trimws(
          substr(
            AVISIT,
            start = 6,
            stop = str_locate(AVISIT, "DAY") - 1
          )
        )
      ),
    TRUE ~ NA_character_
  )) %>%
  mutate(AVISITCDN = case_when(
    AVISITCD == "SCR" ~ -2,
    AVISITCD == "BL" ~ 0,
    grepl("W", AVISITCD) ~ as.numeric(gsub("\\D+", "", AVISITCD)),
    TRUE ~ NA_real_
  )) %>%
  # use ARMCD values to order treatment in visualization legend
  mutate(TRTORD = ifelse(grepl("C", ARMCD), 1,
                         ifelse(grepl("B", ARMCD), 2,
                                ifelse(grepl("A", ARMCD), 3, NA)
                         )
  )) %>%
  mutate(ARM = as.character(arm_mapping[match(ARM, names(arm_mapping))])) %>%
  mutate(ARM = factor(ARM) %>%
           reorder(TRTORD))
attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]


#### Plot creation
g_density_distribution_plot(
  label = "Density Distribution Plot",
  data = ADLB,
  param_var = "PARAMCD",
  param = c("CRP"),
  xaxis_var = "AVAL",
  unit = "AVALU",
  color_manual = color_manual,
  color_comb = "#39ff14",
  comb_line = FALSE,
  facet_var = "AVISITCD",
  facet_ncol = 2
) -> plot
plot
image

The above ylim is set to c(0, 0.5) and you can scale it with ggplot2::coord_cartesian https://ggplot2.tidyverse.org/reference/coord_cartesian.html

plot + ggplot2::coord_cartesian(ylim = c(0, 2))
image

You can always extend ylim axis in another way, directly in the plot settings with a trick - there is a parameter hline_arb = that adds a horizontal line, which also extends ylim axis

g_density_distribution_plot(
  label = "Density Distribution Plot",
  data = ADLB,
  param_var = "PARAMCD",
  param = c("CRP"),
  xaxis_var = "AVAL",
  unit = "AVALU",
  color_manual = color_manual,
  color_comb = "#39ff14",
  comb_line = FALSE,
  hline_arb = 1.75,
  facet_var = "AVISITCD",
  facet_ncol = 2
)
image

But this adds a red line and an extra legend, so I would advice to call below to remove the legend and minimize the visibility of the line (hline_arb_color, hline_arb_label) ggplot2::guides(color = "none")

g_density_distribution_plot(
  label = "Density Distribution Plot",
  data = ADLB,
  param_var = "PARAMCD",
  param = c("CRP"),
  xaxis_var = "AVAL",
  unit = "AVALU",
  color_manual = color_manual,
  color_comb = "#39ff14",
  comb_line = FALSE,
  hline_arb = 1.75,
  hline_arb_color = "grey",
  hline_arb_label = "",
  facet_var = "AVISITCD",
  facet_ncol = 2
) + ggplot2::guides(color = "none")
image

@m7pr
Copy link
Contributor

m7pr commented Jul 26, 2024

When it comes to working with this plot in a teal app with tm_g_gh_density_distribution_plot you can always use Y-Axis Range Zoom from Plot Aesthetic Settings panel.

image

Click Toggle to be able to provide your own limits

image image

The code for the testing app that I used

# Example using ADaM structure analysis dataset.
data <- teal_data()
data <- within(data, {
  library(dplyr)
  library(stringr)
  
  # original ARM value = dose value
  arm_mapping <- list(
    "A: Drug X" = "150mg QD",
    "B: Placebo" = "Placebo",
    "C: Combination" = "Combination"
  )
  ADSL <- rADSL
  ADLB <- rADLB
  var_labels <- lapply(ADLB, function(x) attributes(x)$label)
  ADLB <- ADLB %>%
    mutate(
      AVISITCD = case_when(
        AVISIT == "SCREENING" ~ "SCR",
        AVISIT == "BASELINE" ~ "BL",
        grepl("WEEK", AVISIT) ~ paste("W", str_extract(AVISIT, "(?<=(WEEK ))[0-9]+")),
        TRUE ~ as.character(NA)
      ),
      AVISITCDN = case_when(
        AVISITCD == "SCR" ~ -2,
        AVISITCD == "BL" ~ 0,
        grepl("W", AVISITCD) ~ as.numeric(gsub("[^0-9]*", "", AVISITCD)),
        TRUE ~ as.numeric(NA)
      ),
      AVISITCD = factor(AVISITCD) %>% reorder(AVISITCDN),
      TRTORD = case_when(
        ARMCD == "ARM C" ~ 1,
        ARMCD == "ARM B" ~ 2,
        ARMCD == "ARM A" ~ 3
      ),
      ARM = as.character(arm_mapping[match(ARM, names(arm_mapping))]),
      ARM = factor(ARM) %>% reorder(TRTORD),
      ACTARM = as.character(arm_mapping[match(ACTARM, names(arm_mapping))]),
      ACTARM = factor(ACTARM) %>% reorder(TRTORD)
    )
  
  attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
  attr(ADLB[["ACTARM"]], "label") <- var_labels[["ACTARM"]]
})

datanames <- c("ADSL", "ADLB")
datanames(data) <- datanames
join_keys(data) <- default_cdisc_join_keys[datanames]

app <- init(
  data = data,
  modules = modules(
    tm_g_gh_density_distribution_plot(
      label = "Density Distribution Plot",
      dataname = "ADLB",
      param_var = "PARAMCD",
      param = choices_selected(c("ALT", "CRP", "IGA"), "ALT"),
      xaxis_var = choices_selected(c("AVAL", "BASE", "CHG", "PCHG"), "AVAL"),
      trt_group = choices_selected(c("ARM", "ACTARM"), "ARM"),
      color_manual = c(
        "150mg QD" = "#000000",
        "Placebo" = "#3498DB",
        "Combination" = "#E74C3C"
      ),
      color_comb = "#39ff14",
      comb_line = TRUE,
      plot_height = c(500, 200, 2000),
      font_size = c(12, 8, 20),
      line_size = c(1, .25, 3),
      hline_arb = c(.02, .05),
      hline_arb_color = c("red", "black"),
      hline_arb_label = c("Horizontal Line A", "Horizontal Line B")
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

@donyunardi
Copy link
Contributor

@m7pr

I dug deeper into the issue and found the root cause.

The problem is in teal.goshawk, specifically in the code generating the Y-Axis Range Zoom slider.

This slider is generated using all visits in the data when calculating density and is applied directly to the plot as the ylim argument as the module is loaded:
https://github.com/insightsengineering/teal.goshawk/blob/edfdbba63c1460e2e225cb927bca981c44546d6b/R/tm_g_gh_density_distribution_plot.R#L333

However, the density values differ when calculated for all visits versus specific visits.

For example, this is the max density when calculated with all visits:
Screenshot 2024-07-26 at 4 39 41 PM

And here is the max density value for specific visit, i.e. Baseline:
Screenshot 2024-07-26 at 3 50 22 PM

The Baseline max density is much higher than the value used to generate the slider's max value.
This is what causing the curve to be cut off for some visits.

One possible solution is to group the analysis by visits, determine the maximum density value for each group, and then apply the highest value to the Y-Axis Range Zoom slider's max value.

The function to generate the min and max of the slider for the density is here:
https://github.com/insightsengineering/teal.goshawk/blob/edfdbba63c1460e2e225cb927bca981c44546d6b/R/utils-keep_range_slider_updated.r#L27-L30

Code to play around if needed
library(dplyr)
library(goshawk)
library(shiny)
library(teal.code)
library(teal.data)
library(teal.slice)
library(teal)
library(teal.transform)
library(teal.goshawk)

library(dplyr)
arm_mapping <- list(`A: Drug X` = "150mg QD", `B: Placebo` = "Placebo", `C: Combination` = "Combination")
ADSL <- goshawk::rADSL
ADLB <- goshawk::rADLB
var_labels <- lapply(ADLB, function(x) attributes(x)$label)
ADLB <- ADLB %>% dplyr::mutate(AVISITCD = dplyr::case_when(AVISIT == "SCREENING" ~ "SCR", AVISIT == "BASELINE" ~ "BL", grepl("WEEK", AVISIT) ~ paste("W", stringr::str_extract(AVISIT, "(?<=(WEEK ))[0-9]+")), TRUE ~ as.character(NA)), AVISITCDN = dplyr::case_when(AVISITCD == "SCR" ~ -2, AVISITCD == "BL" ~ 0, grepl("W", AVISITCD) ~ as.numeric(gsub("[^0-9]*", "", AVISITCD)), TRUE ~ as.numeric(NA)), AVISITCD = factor(AVISITCD) %>% reorder(AVISITCDN), TRTORD = dplyr::case_when(ARMCD == "ARM C" ~ 1, ARMCD == 
    "ARM B" ~ 2, ARMCD == "ARM A" ~ 3), ARM = as.character(arm_mapping[match(ARM, names(arm_mapping))]), ARM = factor(ARM) %>% reorder(TRTORD), ACTARM = as.character(arm_mapping[match(ACTARM, names(arm_mapping))]), ACTARM = factor(ACTARM) %>% reorder(TRTORD))
attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
attr(ADLB[["ACTARM"]], "label") <- var_labels[["ACTARM"]]

stopifnot(rlang::hash(ADSL) == "843e317c3d4aeb88062cd39a9c62fe8a")
stopifnot(rlang::hash(ADLB) == "806dd83c79701cfc734f61ea83f8555e")

ADLB <- dplyr::inner_join(x = ADLB, y = ADSL[, c("STUDYID", "USUBJID"), drop = FALSE], by = c("STUDYID", "USUBJID"))

ANL <- ADLB
ANL <- ADLB %>% dplyr::filter(PARAMCD == "IGA")
p <- goshawk::g_density_distribution_plot(data = ANL, param_var = "PARAMCD", param = "IGA", xaxis_var = "PCHG", trt_group = "ARM", xlim = c(-17, 19), ylim = c(0, 0.24764), color_manual = c(`150mg QD` = "#000000", Placebo = "#3498DB", Combination = "#E74C3C"), color_comb = "#39ff14", font_size = 12, line_size = 1, facet_ncol = 2, comb_line = TRUE, hline_arb = c(0.02, 0.05), hline_arb_label = c("Horizontal Line A", "Horizontal Line B"), hline_arb_color = c("red", "black"), rug_plot = FALSE)
tbl <- goshawk::t_summarytable(data = ANL, trt_group = "ARM", param_var = "PARAMCD", param = "IGA", xaxis_var = "PCHG", font_size = 12)

@donyunardi
Copy link
Contributor

Acceptance Criteria

  • Graph lines should show appropriately when app is loaded for density distribution plot
  • When app loaded, the max value of Y-Axis Range Zoom slider should be to maximum density value when data is subsetted by AVISITCD

@donyunardi donyunardi added the core label Aug 8, 2024
@m7pr m7pr self-assigned this Sep 16, 2024
@m7pr
Copy link
Contributor

m7pr commented Sep 17, 2024

Confirming that the error still occurs and that I was able to reproduce with

Set filters to: ADSL -> SEX -> Male, ADSL -> AGE -> 32,36

pkgload::load_all("/teal.widgets")
pkgload::load_all("/teal")
pkgload::load_all("/teal.goshawk")

data <- teal_data()
data <- within(data, {
  library(dplyr)
  library(stringr)
  
  # original ARM value = dose value
  arm_mapping <- list(
    "A: Drug X" = "150mg QD",
    "B: Placebo" = "Placebo",
    "C: Combination" = "Combination"
  )
  ADSL <- rADSL
  ADLB <- rADLB
  var_labels <- lapply(ADLB, function(x) attributes(x)$label)
  ADLB <- ADLB %>%
    mutate(
      AVISITCD = case_when(
        AVISIT == "SCREENING" ~ "SCR",
        AVISIT == "BASELINE" ~ "BL",
        grepl("WEEK", AVISIT) ~ paste("W", str_extract(AVISIT, "(?<=(WEEK ))[0-9]+")),
        TRUE ~ as.character(NA)
      ),
      AVISITCDN = case_when(
        AVISITCD == "SCR" ~ -2,
        AVISITCD == "BL" ~ 0,
        grepl("W", AVISITCD) ~ as.numeric(gsub("[^0-9]*", "", AVISITCD)),
        TRUE ~ as.numeric(NA)
      ),
      AVISITCD = factor(AVISITCD) %>% reorder(AVISITCDN),
      TRTORD = case_when(
        ARMCD == "ARM C" ~ 1,
        ARMCD == "ARM B" ~ 2,
        ARMCD == "ARM A" ~ 3
      ),
      ARM = as.character(arm_mapping[match(ARM, names(arm_mapping))]),
      ARM = factor(ARM) %>% reorder(TRTORD),
      ACTARM = as.character(arm_mapping[match(ACTARM, names(arm_mapping))]),
      ACTARM = factor(ACTARM) %>% reorder(TRTORD)
    )
  
  attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
  attr(ADLB[["ACTARM"]], "label") <- var_labels[["ACTARM"]]
})

datanames <- c("ADSL", "ADLB")
datanames(data) <- datanames
join_keys(data) <- default_cdisc_join_keys[datanames]

app <- init(
  data = data,
  modules = modules(
    tm_g_gh_density_distribution_plot(
      label = "Density Distribution Plot",
      dataname = "ADLB",
      param_var = "PARAMCD",
      param = choices_selected(c("ALT", "CRP", "IGA"), "ALT"),
      xaxis_var = choices_selected(c("AVAL", "BASE", "CHG", "PCHG"), "AVAL"),
      trt_group = choices_selected(c("ARM", "ACTARM"), "ARM"),
      color_manual = c(
        "150mg QD" = "#000000",
        "Placebo" = "#3498DB",
        "Combination" = "#E74C3C"
      ),
      color_comb = "#39ff14",
      comb_line = TRUE,
      plot_height = c(500, 200, 2000),
      font_size = c(12, 8, 20),
      line_size = c(1, .25, 3),
      hline_arb = c(.02, .05),
      hline_arb_color = c("red", "black"),
      hline_arb_label = c("Horizontal Line A", "Horizontal Line B")
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

image

@m7pr
Copy link
Contributor

m7pr commented Sep 17, 2024

Created a PR that solved the issue insightsengineering/teal.goshawk#308

@m7pr
Copy link
Contributor

m7pr commented Sep 18, 2024

Fixed here insightsengineering/teal.goshawk#308

@m7pr m7pr closed this as completed Sep 18, 2024
m7pr added a commit to insightsengineering/teal.goshawk that referenced this issue Sep 18, 2024
…TCD for density plot (#308)

Fixes insightsengineering/goshawk#192

For proper density calculations, you need to calculate ranges within
groups inside the plot. Groups are created based on treatment variable
and based on AVICITCD plot. So the max ranges need to be calculated in
each group, and the max needs to be extracted.

> Set filters to: ADSL -> SEX -> Male, ADSL -> AGE -> 31.41, 35

# How it looked before

<img width="665" alt="image"
src="https://github.com/user-attachments/assets/344d408e-5357-4ebc-b037-7fa483b0e052">


# How it looks now

<img width="664" alt="image"
src="https://github.com/user-attachments/assets/d84fd7b1-6a06-43f9-8ff4-97310dcc629a">

# Example code

<details><summary> Example from `?tm_g_gh_density_distribution_plot`
</summary>

```r
pkgload::load_all("../teal.widgets")
pkgload::load_all("../teal")
pkgload::load_all(".")

data <- teal_data()
data <- within(data, {
  library(dplyr)
  library(stringr)
  
  # original ARM value = dose value
  arm_mapping <- list(
    "A: Drug X" = "150mg QD",
    "B: Placebo" = "Placebo",
    "C: Combination" = "Combination"
  )
  ADSL <- rADSL
  ADLB <- rADLB
  var_labels <- lapply(ADLB, function(x) attributes(x)$label)
  ADLB <- ADLB %>%
    mutate(
      AVISITCD = case_when(
        AVISIT == "SCREENING" ~ "SCR",
        AVISIT == "BASELINE" ~ "BL",
        grepl("WEEK", AVISIT) ~ paste("W", str_extract(AVISIT, "(?<=(WEEK ))[0-9]+")),
        TRUE ~ as.character(NA)
      ),
      AVISITCDN = case_when(
        AVISITCD == "SCR" ~ -2,
        AVISITCD == "BL" ~ 0,
        grepl("W", AVISITCD) ~ as.numeric(gsub("[^0-9]*", "", AVISITCD)),
        TRUE ~ as.numeric(NA)
      ),
      AVISITCD = factor(AVISITCD) %>% reorder(AVISITCDN),
      TRTORD = case_when(
        ARMCD == "ARM C" ~ 1,
        ARMCD == "ARM B" ~ 2,
        ARMCD == "ARM A" ~ 3
      ),
      ARM = as.character(arm_mapping[match(ARM, names(arm_mapping))]),
      ARM = factor(ARM) %>% reorder(TRTORD),
      ACTARM = as.character(arm_mapping[match(ACTARM, names(arm_mapping))]),
      ACTARM = factor(ACTARM) %>% reorder(TRTORD)
    )
  
  attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
  attr(ADLB[["ACTARM"]], "label") <- var_labels[["ACTARM"]]
})

datanames <- c("ADSL", "ADLB")
datanames(data) <- datanames
join_keys(data) <- default_cdisc_join_keys[datanames]

app <- init(
  data = data,
  modules = modules(
    tm_g_gh_density_distribution_plot(
      label = "Density Distribution Plot",
      dataname = "ADLB",
      param_var = "PARAMCD",
      param = choices_selected(c("ALT", "CRP", "IGA"), "ALT"),
      xaxis_var = choices_selected(c("AVAL", "BASE", "CHG", "PCHG"), "AVAL"),
      trt_group = choices_selected(c("ARM", "ACTARM"), "ARM"),
      color_manual = c(
        "150mg QD" = "#000000",
        "Placebo" = "#3498DB",
        "Combination" = "#E74C3C"
      ),
      color_comb = "#39ff14",
      comb_line = TRUE,
      plot_height = c(500, 200, 2000),
      font_size = c(12, 8, 20),
      line_size = c(1, .25, 3),
      hline_arb = c(.02, .05),
      hline_arb_color = c("red", "black"),
      hline_arb_label = c("Horizontal Line A", "Horizontal Line B")
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}


```


</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working core priority
Projects
None yet
4 participants