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

Line plot module: control symbol size #238

Open
3 tasks done
npaszty opened this issue Sep 5, 2023 · 5 comments
Open
3 tasks done

Line plot module: control symbol size #238

npaszty opened this issue Sep 5, 2023 · 5 comments
Labels
enhancement New feature or request

Comments

@npaszty
Copy link
Contributor

npaszty commented Sep 5, 2023

Feature description

stakeholders report that it is difficult to easily see the difference between the line plot lines when using a splitting variable. there are number of reasons for this. here are three ideas to help address. suggested order is hopefully simplest to more complicated. happy to hop on a call to discuss further and goshawk function would need updated but didn't open and issue in that package.

  1. Lines within a treatment arm are the same color and the same type. here's an example from the sample app filtering to only one treatment group and choosing SEX as the line splitting variable
    image

Feature: would it be straight forward to include a UI element like what is in boxplot to increase the size of the line plot symbols?
image

  1. Another idea to help differentiate within the line splitting context was to be able to set different line color within a treatment group. currently the line color and type selector functions within a treatment group.
    image

Feature: I fear this would be quite complicated to add a nested line color and type selector within the treatment group value to control the split line aesthetics.

  1. Another idea was to have the line type set automatically when a splitting variable is chosen. currently the line type is set to solid but this can be changed manually. however we observed when setting different line type it doesn't look like that is reflected in the legend. maybe the legend symbol/line is not big enough to show the line type.
    image

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.
@npaszty npaszty added the enhancement New feature or request label Sep 5, 2023
@npaszty
Copy link
Contributor Author

npaszty commented Feb 29, 2024

is there an update on this issue? thanks.

@npaszty
Copy link
Contributor Author

npaszty commented Sep 5, 2024

@donyunardi

is there an update on this issue? thanks.

@donyunardi
Copy link
Contributor

Hi @npaszty,

Thetm_g_gh_lineplot module has aesthetic setting, i.e. dot size, symbols, colors, position dodge, etc.

Here's what it looks like once I played around with this:
image

Is the user aware of these settings? If not, could you review my output and let me know your thoughts?
If this isn’t sufficient, we can discuss potential directions to explore to resolve this.

Steps to reproduce:

  1. Go to https://genentech.shinyapps.io/nest_longitudinal_stable/
  2. Filter by ARMCD, only select "C: Combination"
  3. Select "SEX" from "Select Line Splitting Variable" in the encoding area.
    image
R Code to reproduce
# Add any code to install/load your NEST environment here

library(shiny)
library(dplyr)
library(goshawk)
library(teal.code)
library(teal.data)
library(teal.slice)
library(teal)
library(teal.transform)
library(teal.goshawk)
library(formatters)
library(magrittr)
library(rtables)
library(tern)
library(teal.modules.clinical)
library(ggplot2)
library(ggmosaic)
library(teal.modules.general)
library(DescTools)
library(random.cdisc.data)
library(stringr)
library(sparkline)

library(DescTools)
library(magrittr)
library(dplyr)
library(random.cdisc.data)
library(stringr)
library(sparkline)
ADSL <- radsl(seed = 1)
ADLB <- radlb(ADSL, seed = 1)
exclude_l2 <- c("")
exclude_chg <- c("")
arm_mapping <- list(`A: Drug X` = "Drug X 100mg", `C: Combination` = "Combination 100mg", `B: Placebo` = "Placebo")
ADSL <- ADSL %>% filter(ITTFL == "Y") %>% mutate(TRTORD = case_when(TRT01P == "A: Drug X" ~ 1, TRT01P == "C: Combination" ~ 2, TRT01P == "B: Placebo" ~ 3, TRUE ~ as.numeric(NA)), TRTORD = TRTORD %make_label% "Treatment Order", TRT01P = as.character(arm_mapping[match(TRT01P, names(arm_mapping))]), TRT01P = factor(ARM) %>% reorder(TRTORD), TRT01P = TRT01P %make_label% "Planned Treatment for Period 01")
char_vars_adsl <- names(Filter(isTRUE, sapply(ADSL, is.character)))
ADSL <- ADSL %>% mutate_at(char_vars_adsl, factor)
ADLB_SUBSET <- ADLB %>% filter(!is.na(AVAL)) %>% filter(ITTFL == "Y" & toupper(AVISIT) %like any% c("SCREEN%", "BASE%", "%WEEK%", "%FOLLOW%")) %>% select(c("STUDYID", "USUBJID", "ITTFL", "ARM", "ARMCD", "ACTARM", "ACTARMCD", "TRT01P", "TRT01A", "AVISIT", "AVISITN", "ADY", "PARAM", "PARAMCD", "AVAL", "AVALU", "BASE", "CHG", "PCHG", "ANRLO", "ANRHI", "LBSTRESC", "SEX", "RACE", "LOQFL")) %>% mutate(AVISITCD = case_when(toupper(AVISIT) == "SCREENING" ~ "SCR", toupper(AVISIT) == "BASELINE" ~ "BL", grepl("WEEK", 
    toupper(AVISIT)) ~ paste("W", trimws(substr(AVISIT, start = 6, stop = stringr::str_locate(AVISIT, "DAY") - 1))), grepl("FOLLOW", toupper(AVISIT)) ~ "FU", TRUE ~ as.character(NA)), AVISITCDN = case_when(AVISITCD == "SCR" ~ -2, AVISITCD == "BL" ~ 0, grepl("W", AVISITCD) ~ as.numeric(gsub("[^0-9]+", "", AVISITCD)) * 7, AVISITCD == "FU" ~ 100, TRUE ~ as.numeric(NA)), TRTORD = case_when(TRT01P == "A: Drug X" ~ 1, TRT01P == "C: Combination" ~ 2, TRT01P == "B: Placebo" ~ 3, TRUE ~ as.numeric(NA)), LOQFL = if_else(as.character(LOQFL) == 
    "Y", as.character(LOQFL), "N"), BASE2 = NA, CHG2 = NA, PCHG2 = NA) %>% rowwise() %>% group_by(PARAMCD) %>% mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE), paste("<", round(runif(1, min = 25, max = 30))), LBSTRESC)) %>% mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE), paste(">", round(runif(1, min = 70, max = 75))), LBSTRESC)) %>% ungroup()
attr(ADLB_SUBSET[["LBSTRESC"]], "label") <- "Character Result/Finding in Std Format"
attr(ADLB_SUBSET[["ANRLO"]], "label") <- "Analysis Normal Range Lower Limit"
attr(ADLB_SUBSET[["ANRHI"]], "label") <- "Analysis Normal Range Upper Limit"
PARAM_MINS <- ADLB_SUBSET %>% select(USUBJID, PARAMCD, AVAL) %>% group_by(PARAMCD) %>% summarise(AVAL_MIN = min(AVAL, na.rm = TRUE), .groups = "drop") %>% mutate(PARAMCD = PARAMCD %make_label% "Parameter Code")
ADLB_SUPED1 <- ADLB_SUBSET %>% mutate(BASE2 = ifelse(toupper(AVISIT) == "SCREENING" & is.na(BASE2), AVAL, BASE2) %keep_label% BASE2) %>% mutate(CHG2 = ifelse(toupper(AVISIT) == "SCREENING" & is.na(CHG2), 0, CHG2) %keep_label% CHG2) %>% mutate(PCHG2 = ifelse(toupper(AVISIT) == "SCREENING" & is.na(PCHG2), 0, PCHG2) %keep_label% PCHG2) %>% mutate(BASE = ifelse(toupper(AVISIT) == "BASELINE" & is.na(BASE), AVAL, BASE) %keep_label% BASE) %>% mutate(CHG = ifelse(toupper(AVISIT) == "BASELINE" & is.na(CHG), 
    0, CHG) %keep_label% CHG) %>% mutate(PCHG = ifelse(toupper(AVISIT) == "BASELINE" & is.na(PCHG), 0, PCHG) %keep_label% PCHG) %>% mutate(TRTORD = TRTORD %make_label% "Treatment Order")
ADLB_SUPED2 <- inner_join(PARAM_MINS, ADLB_SUPED1, by = "PARAMCD")[, union(names(ADLB_SUPED1), names(PARAM_MINS))] %>% mutate(AVALL2 = ifelse(PARAMCD %in% exclude_l2, AVAL, ifelse(PARAMCD %in% exclude_chg, NA, ifelse(AVAL == 0 & AVAL_MIN > 0, log2(AVAL_MIN/2), ifelse(AVAL == 0 & AVAL_MIN <= 0, NA, ifelse(AVAL > 0, log2(AVAL), NA))))) %make_label% "Log2 of AVAL") %>% mutate(BASEL2 = ifelse(PARAMCD %in% exclude_l2, BASE, ifelse(PARAMCD %in% exclude_chg, NA, ifelse(BASE == 0 & AVAL_MIN > 0, log2(AVAL_MIN/2), 
    ifelse(BASE == 0 & AVAL_MIN <= 0, NA, ifelse(BASE > 0, log2(BASE), NA))))) %make_label% "Log2 of BASE") %>% mutate(BASE2L2 = ifelse(PARAMCD %in% exclude_l2, BASE2, ifelse(PARAMCD %in% exclude_chg, NA, ifelse(BASE2 == 0 & AVAL_MIN > 0, log2(AVAL_MIN/2), ifelse(BASE2 == 0 & AVAL_MIN <= 0, NA, ifelse(BASE2 > 0, log2(BASE2), NA))))) %make_label% "Log2 of BASE2") %>% mutate(AVAL_MIN = AVAL_MIN %make_label% "Minimum AVAL Within PARAMCD")
ADLB <- ADLB_SUPED2 %>% mutate(TRT01P = as.character(arm_mapping[match(TRT01P, names(arm_mapping))]), TRT01P = factor(TRT01P) %>% reorder(TRTORD) %make_label% "Planned Treatment for Period 01", TRT01A = as.character(arm_mapping[match(TRT01A, names(arm_mapping))]), TRT01A = factor(TRT01A) %>% reorder(TRTORD) %make_label% "Actual Treatment for Period 01", LOQFL = LOQFL %make_label% "Limit of Quantification", AVISITCD = factor(AVISITCD) %>% reorder(AVISITCDN) %make_label% "Analysis Visit Window Code", 
    AVISITCDN = AVISITCDN %make_label% "Analysis Visit Window Code (N)", BASE2 = BASE2 %make_label% "Screening Value", CHG2 = CHG2 %make_label% "Absolute Change from Screening", PCHG2 = PCHG2 %make_label% "Percent Change from Screening")
ADLB_LOQS <- goshawk:::h_identify_loq_values(ADLB, flag_var = "LOQFL")
ADLB <- left_join(ADLB, ADLB_LOQS, by = "PARAM")

stopifnot(rlang::hash(ADSL) == "6a0d37a2dc4a81d7ff62dd65e4bc324a")
stopifnot(rlang::hash(ADLB) == "3c8a641b2a2df269fbc095cacf0a4360")

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

ANL <- ADLB
ANL <- ADLB %>% dplyr::filter(PARAMCD == "ALT")
keep_index <- which(c(-2, 0, 7, 14, 21, 28, 35) %in% ANL[["AVISITCDN"]])
xtick <- (c(-2, 0, 7, 14, 21, 28, 35))[keep_index]
xlabel <- (c("Screening", "Baseline", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5"))[keep_index]
p <- goshawk::g_lineplot(data = ANL[stats::complete.cases(ANL[, c("AVAL", "AVISITCDN")]), ], biomarker_var = "PARAMCD", biomarker_var_label = "PARAM", biomarker = "ALT", value_var = "AVAL", ylim = c(14.125, 24.575), trt_group = "TRT01A", trt_group_level = NULL, shape = "SEX", shape_type = c(F = "circle", M = "square"), time = "AVISITCDN", time_level = NULL, color_manual = c(`Drug X 100mg` = "#1e90ff", `Combination 100mg` = "#bb9990", Placebo = "#ffa07a"), line_type = c(`Drug X 100mg` = "solid", `Combination 100mg` = "solid", 
Placebo = "solid"), median = FALSE, hline_arb = numeric(0), hline_arb_label = character(0), hline_arb_color = character(0), xtick = xtick, xlabel = xlabel, rotate_xlab = TRUE, plot_height = 1000, plot_font_size = 12, dot_size = 2, dodge = 0.4, count_threshold = 0, table_font_size = 12, display_center_tbl = TRUE)
print(p)

@m7pr
Copy link
Contributor

m7pr commented Oct 15, 2024

@npaszty does the answer satisfy your needs?

@npaszty
Copy link
Contributor Author

npaszty commented Oct 29, 2024

yes. thanks. a forgotten encoding element. ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants