Skip to content
New issue

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

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

Already on GitHub? # to your account

#219 add facet_scales to plot aesthetics menu #227

Merged
merged 7 commits into from
Jul 21, 2023

Conversation

m7pr
Copy link
Contributor

@m7pr m7pr commented Jul 19, 2023

Closes #219

With this PR I extended Plot Aesthetic Settings foldable UI with an option to pass scales parameter to ggplot2::facet_wrap. This also required a change in insightsengineering/goshawk#201

library(dplyr)

# original ARM value = dose value
arm_mapping <- list(
  "A: Drug X" = "150mg QD",
  "B: Placebo" = "Placebo",
  "C: Combination" = "Combination"
)
set.seed(1)
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),
    ANRLO = 30,
    ANRHI = 75
  ) %>%
  dplyr::rowwise() %>%
  dplyr::group_by(PARAMCD) %>%
  dplyr::mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                                  paste("<", round(runif(1, min = 25, max = 30))), LBSTRESC
  )) %>%
  dplyr::mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                                  paste(">", round(runif(1, min = 70, max = 75))), LBSTRESC
  )) %>%
  ungroup()
attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
attr(ADLB[["ACTARM"]], "label") <- var_labels[["ACTARM"]]
attr(ADLB[["ANRLO"]], "label") <- "Analysis Normal Range Lower Limit"
attr(ADLB[["ANRHI"]], "label") <- "Analysis Normal Range Upper Limit"

# add LLOQ and ULOQ variables
ALB_LOQS <- goshawk:::h_identify_loq_values(ADLB)
ADLB <- dplyr::left_join(ADLB, ALB_LOQS, by = "PARAM")

app <- teal::init(
  data = teal.data::cdisc_data(
    teal.data::cdisc_dataset("ADSL", ADSL, code = "ADSL <- goshawk::rADSL"),
    teal.data::cdisc_dataset(
      "ADLB",
      ADLB,
      code = "set.seed(1)
              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),
                  ANRLO = 30,
                  ANRHI = 75) %>%
                  dplyr::rowwise() %>%
                  dplyr::group_by(PARAMCD) %>%
                  dplyr::mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                  paste('<', round(runif(1, min = 25, max = 30))), LBSTRESC)) %>%
                  dplyr::mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                  paste( '>', round(runif(1, min = 70, max = 75))), LBSTRESC)) %>%
                  ungroup
               attr(ADLB[['ARM']], 'label') <- var_labels[['ARM']]
               attr(ADLB[['ACTARM']], 'label') <- var_labels[['ACTARM']]
               attr(ADLB[['ANRLO']], 'label') <- 'Analysis Normal Range Lower Limit'
               attr(ADLB[['ANRHI']], 'label') <- 'Analysis Normal Range Upper Limit'
               ALB_LOQS <- goshawk:::h_identify_loq_values(ADLB)
               ADLB <- left_join(ADLB, ALB_LOQS, by = 'PARAM')",
      vars = list(arm_mapping = arm_mapping)
    ),
    check = FALSE
  ),
  modules = teal::modules(
    teal.goshawk::tm_g_gh_spaghettiplot(
      label = "Spaghetti Plot",
      dataname = "ADLB",
      param_var = "PARAMCD",
      param = choices_selected(c("ALT", "CRP", "IGA"), "ALT"),
      idvar = "USUBJID",
      xaxis_var = choices_selected(c("Analysis Visit Code" = "AVISITCD"), "AVISITCD"),
      yaxis_var = choices_selected(c("AVAL", "CHG", "PCHG"), "AVAL"),
      filter_var = choices_selected(
        c("None" = "NONE", "Screening" = "BASE2", "Baseline" = "BASE"),
        "NONE"
      ),
      trt_group = choices_selected(c("ARM", "ACTARM"), "ARM"),
      color_comb = "#39ff14",
      man_color = c(
        "Combination" = "#000000",
        "Placebo" = "#fce300",
        "150mg QD" = "#5a2f5f"
      ),
      hline_arb = c(60, 50),
      hline_arb_color = c("grey", "red"),
      hline_arb_label = c("default A", "default B"),
      hline_vars = c("ANRHI", "ANRLO", "ULOQN", "LLOQN"),
      hline_vars_colors = c("pink", "brown", "purple", "black"),
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

image

@m7pr m7pr added the core label Jul 19, 2023
@m7pr m7pr requested a review from a team July 19, 2023 11:57
@chlebowa
Copy link
Contributor

I don't think it works:
image
facets set to "free"

There is a range slider that determines the Y axis scale - will that not preclude freeing the Y axis?

Also, I scales are not aesthetics, put the input somewhere else.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 19, 2023

badge

Code Coverage Summary

Filename                                 Stmts    Miss  Cover    Missing
-------------------------------------  -------  ------  -------  ---------
R/tm_g_gh_boxplot.R                        349     349  0.00%    216-632
R/tm_g_gh_correlationplot.R                552     552  0.00%    282-940
R/tm_g_gh_density_distribution_plot.R      274     274  0.00%    161-484
R/tm_g_gh_lineplot.R                       559     559  0.00%    184-837
R/tm_g_gh_scatterplot.R                    235     235  0.00%    167-453
R/tm_g_gh_spaghettiplot.R                  288     288  0.00%    230-584
R/toggleable_slider.R                      154     154  0.00%    82-253
R/utils-arbitrary_lines.r                  121     121  0.00%    19-172
R/utils-data_constraints.r                 186     186  0.00%    2-255
R/utils-keep_range_slider_updated.r         23      23  0.00%    8-38
R/utils-maptrt.r                             9       9  0.00%    25-37
R/utils-templ_ui.r                          48      48  0.00%    2-73
R/utils.R                                   17      17  0.00%    12-32
R/zzz.R                                      1       1  0.00%    2
TOTAL                                     2816    2816  0.00%

Diff against main

Filename                     Stmts    Miss  Cover
-------------------------  -------  ------  --------
R/tm_g_gh_spaghettiplot.R       +4      +4  +100.00%
TOTAL                           +4      +4  +100.00%

Results for commit: 011e81e

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@m7pr
Copy link
Contributor Author

m7pr commented Jul 19, 2023

@chlebowa thanks

Also, I scales are not aesthetics, put the input somewhere else.

☝️ scales are in the same place as facet_ncol which determines ncol in facet_wrap. Also the Y-axis zoom is listed under this aesthetics part. I think adding scales next to other AXIS and GRID manipulators under the same area in which they existed should be fine.

@chlebowa
Copy link
Contributor

@chlebowa thanks

Also, I scales are not aesthetics, put the input somewhere else.

point_up scales are in the same place as facet_ncol which determines ncol in facet_wrap. Also the Y-axis zoom is listed under this aesthetics part. I think adding scales next to other AXIS and GRID manipulators under the same area in which they existed should be fine.

Fair enough.

@m7pr
Copy link
Contributor Author

m7pr commented Jul 19, 2023

Thanks for checking the case with AVISITCD - it indeed doesn't remove SCR level where all PCHG are NAs.

library(ggplot2)
ADLB %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

Will double check that again

image

@m7pr
Copy link
Contributor Author

m7pr commented Jul 19, 2023

Hey @chlebowa check-out this example. Below I created 3 datasets

# removing missing levels from the plot with facet_scales
ADLB2 <- ADLB %>% 
  filter(!(ARM == 'Placebo' & AVISITCD == "SCR"))

ADLB3 <- ADLB %>%
  mutate(AVISITCD = case_when(
    ARM == 'Placebo' & AVISITCD  == "SCR" ~ NA_character_,
    TRUE ~ AVISITCD
  ))
  • ADLB - all rows
  • ADLB2 - some rows filtered, hence some combination of ARM and AVISITCD do not exist in the data (ARM=facet, AVISITCD=x)
  • ADLB3 - all rows, some combinations of ARM and AVISITCD do not exist in the data (ARM=facet, AVISITCD=x), but ARM exist for all datapoints, even though AVISITCD is NA

When I was testing this functionality, I actually tested situation of ADLB2 where combination of facet * x did not exist in the dataset and could be removed. Check below plots to see difference in PLACEBO panel. I think scales does the trick for ADLB2 - situation when combination of facet*x is missing from the dataset. And to get NAs removed from the plot IMHO one needs to apply filters in the filter panel to drop specific NAs from the data.

> table(ADLB$ARM, ADLB$AVISITCD, useNA = 'always')
             
               BL SCR W 1 W 2 W 3 W 4 W 5 <NA>
  Combination 396 396 396 396 396 396 396    0
  Placebo     402 402 402 402 402 402 402    0
  150mg QD    402 402 402 402 402 402 402    0
  <NA>          0   0   0   0   0   0   0    0
> table(ADLB2$ARM, ADLB2$AVISITCD, useNA = 'always')
             
               BL SCR W 1 W 2 W 3 W 4 W 5 <NA>
  Combination 396 396 396 396 396 396 396    0
  Placebo     402   0 402 402 402 402 402    0
  150mg QD    402 402 402 402 402 402 402    0
  <NA>          0   0   0   0   0   0   0    0
> table(ADLB3$ARM, ADLB3$AVISITCD, useNA = 'always')
             
               BL SCR W 1 W 2 W 3 W 4 W 5 <NA>
  Combination 396 396 396 396 396 396 396    0
  Placebo     402   0 402 402 402 402 402  402
  150mg QD    402 402 402 402 402 402 402    0
  <NA>          0   0   0   0   0   0   0    0

full code is below, here is just a bit of comments

library(ggplot2)
# FIRST PLOT
ADLB %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

# SECOND PLOT
ADLB2 %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

# THIRD PLOT
ADLB3 %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

First plot
image

Second plot
image

Third plot
image

FULL CODE

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 <- goshawk::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)) %>%
  mutate(ANRLO = .5, ANRHI = 1) %>%
  rowwise() %>%
  group_by(PARAMCD) %>%
  mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                           paste("<", round(runif(1, min = .5, max = .7))), LBSTRESC
  )) %>%
  mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
                           paste(">", round(runif(1, min = .9, max = 1.2))), LBSTRESC
  )) %>%
  ungroup()
attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
attr(ADLB[["ANRLO"]], "label") <- "Analysis Normal Range Lower Limit"
attr(ADLB[["ANRHI"]], "label") <- "Analysis Normal Range Upper Limit"

# add LLOQ and ULOQ variables
ADLB_LOQS <- goshawk:::h_identify_loq_values(ADLB)
ADLB <- left_join(ADLB, ADLB_LOQS, by = "PARAM")


# removing missing levels from the plot with facet_scales
ADLB2 <- ADLB %>% 
  filter(!(ARM == 'Placebo' & AVISITCD == "SCR"))

ADLB3 <- ADLB %>%
  mutate(AVISITCD = case_when(
    ARM == 'Placebo' & AVISITCD  == "SCR" ~ NA_character_,
    TRUE ~ AVISITCD
  ))

table(ADLB$ARM, ADLB$AVISITCD, useNA = 'always')
table(ADLB2$ARM, ADLB2$AVISITCD, useNA = 'always')
table(ADLB3$ARM, ADLB3$AVISITCD, useNA = 'always')

library(ggplot2)
ADLB %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

ADLB2 %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

ADLB3 %>%
  select(AVISITCD, PCHG, ARM) %>%
  ggplot(aes(x = AVISITCD, y = PCHG, col = ARM)) +
  geom_point()+
  facet_wrap(~ARM, scales = 'free_x')

@m7pr
Copy link
Contributor Author

m7pr commented Jul 19, 2023

I remember about this

There is a range slider that determines the Y axis scale - will that not preclude freeing the Y axis?

Will reply in the next comment

@m7pr
Copy link
Contributor Author

m7pr commented Jul 19, 2023

I should also remember about insightsengineering/goshawk#201 (comment)

@chlebowa
Copy link
Contributor

I should also remember about insightsengineering/goshawk#201 (comment)

I got ahead of myself about the validator. The input is independent of data nad there will always be a valid value, so input validation will not be necessary. Sorry about that. Now, match.arg on the other hand, should be there in my opinion.

@m7pr
Copy link
Contributor Author

m7pr commented Jul 20, 2023

@chlebowa

There is a range slider that determines the Y axis scale - will that not preclude freeing the Y axis?

So yeah, coord_cartesian that sets Y axis is applied after facet_wrap. In a regular plot in goshawk::g_spaghettiplot ylim is set to NAs by default so it has no implication when facet_scales are used. On the other hand in teal.goshawk::tm_g_gh_spaghettiplot this is set by the module before the shiny app starts, hence it overwrites facet_scales for free_y. I guess, we can remove this option from UI and leave only - fixed and free_x for facet_scales

@chlebowa
Copy link
Contributor

I guess, we can remove this option from UI and leave only - fixed and free_x for facet_scales

How about making it a checkbox?

@m7pr
Copy link
Contributor Author

m7pr commented Jul 20, 2023

@chlebowa oh yeah, now it makes sense if there is only 2 options now. Will update

@m7pr
Copy link
Contributor Author

m7pr commented Jul 20, 2023

@chlebowa I just pushed the change. We have a checkboxInput for freeing X scales
image
image

m7pr added a commit to insightsengineering/goshawk that referenced this pull request Jul 21, 2023
Fix for insightsengineering/teal.goshawk#219
and continued here
insightsengineering/teal.goshawk#227

# Data
```{R}
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 <- goshawk::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)) %>%
  mutate(ANRLO = .5, ANRHI = 1) %>%
  rowwise() %>%
  group_by(PARAMCD) %>%
  mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
    paste("<", round(runif(1, min = .5, max = .7))), LBSTRESC
  )) %>%
  mutate(LBSTRESC = ifelse(USUBJID %in% sample(USUBJID, 1, replace = TRUE),
    paste(">", round(runif(1, min = .9, max = 1.2))), LBSTRESC
  )) %>%
  ungroup()
attr(ADLB[["ARM"]], "label") <- var_labels[["ARM"]]
attr(ADLB[["ANRLO"]], "label") <- "Analysis Normal Range Lower Limit"
attr(ADLB[["ANRHI"]], "label") <- "Analysis Normal Range Upper Limit"

# add LLOQ and ULOQ variables
ADLB_LOQS <- goshawk:::h_identify_loq_values(ADLB)
ADLB <- left_join(ADLB, ADLB_LOQS, by = "PARAM")
```

# Show all scales - `facet_scales = 'fixed'`

```{R}
g_spaghettiplot(
  data = ADLB,
  subj_id = "USUBJID",
  biomarker_var = "PARAMCD",
  biomarker = "CRP",
  value_var = "AVAL",
  trt_group = "ARM",
  time = "RACE",
  color_manual = color_manual,
  color_comb = "#39ff14",
  alpha = .02,
  facet_scales = "fixed",
  rotate_xlab = FALSE,
  group_stats = "median",
  hline_arb = c(.5, .7, 1),
  hline_arb_color = c("blue", "red", "green"),
  hline_arb_label = c("Arb_Hori_line_A", "Arb_Hori_line_B", "Arb_Hori_line_C"),
  hline_vars = c("ANRHI", "ANRLO")
)
```

![image](https://github.com/insightsengineering/goshawk/assets/133694481/5f2bcbda-4996-4f29-8b3b-deb1bdd26c7f)

## Free scales for x - `facet_scales = 'free_x'`

```{R}
g_spaghettiplot(
  data = ADLB,
  subj_id = "USUBJID",
  biomarker_var = "PARAMCD",
  biomarker = "CRP",
  value_var = "AVAL",
  trt_group = "ARM",
  time = "RACE",
  color_manual = color_manual,
  color_comb = "#39ff14",
  alpha = .02,
  facet_scales = "free_x",
  rotate_xlab = FALSE,
  group_stats = "median",
  hline_arb = c(.5, .7, 1),
  hline_arb_color = c("blue", "red", "green"),
  hline_arb_label = c("Arb_Hori_line_A", "Arb_Hori_line_B", "Arb_Hori_line_C"),
  hline_vars = c("ANRHI", "ANRLO")
)
```


![image](https://github.com/insightsengineering/goshawk/assets/133694481/8b28e06f-b7c9-4192-9e1c-be39273834e5)

---------

Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com>
Co-authored-by: Aleksander Chlebowski <114988527+chlebowa@users.noreply.github.com>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com>
Copy link
Contributor

@chlebowa chlebowa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup 👌

@m7pr m7pr merged commit 4d87c82 into main Jul 21, 2023
@m7pr m7pr deleted the 219_scales_for_spaghettiplot@main branch July 21, 2023 14:24
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tm_g_gh_spaghettiplot will have all x ticks and labels
2 participants