ggsurvplot_facet возвращает: «Ошибка в grDevices :: col2rgb (color, TRUE): неверное имя цвета» при использовании внутри функции - PullRequest
1 голос
/ 16 апреля 2019

Я пытаюсь построить кривые выживания для нескольких переменных, фасетируемых переменной пола с помощью функции ggsurvplot_facet (). Когда я применяю свой код к одной модели, она работает нормально. Однако, когда я пытаюсь использовать один и тот же код в функции или в цикле for, он не может построить все кривые выживания, которые должны быть построены, и возвращает ошибку. Я бы выполнил это построение в самой ggsurvplot_facet (), если бы он разрешал в качестве входных данных список элементов переохлаждения, точно так же, как это делает ggsurvplot (), но ggsurvplot_facet () допускает только один элемент выживания за раз.

Я запускаю свой код в RStudio на MacBook Pro 2018 года с Mac OS High Sierra.

Рассмотрим следующий набор данных: http://s000.tinyupload.com/index.php?file_id=01704535336107726906

Содержит наблюдения для нескольких посещений для 100 субъектов и 4 различных переменных. Две из переменных (variable1 и variable2) могут иметь два разных значения (0 или 1), а две другие переменные (variable3 и variable4) могут иметь три разных значения (0, 1 или 2).

Я начал работать с теми, которые могут иметь два разных значения, и я написал следующий код:

# Load libraries
require(mgcv)
require(msm)
library(dplyr)
library(grDevices)
library(survival)
library(survminer)


# Set working directory
dirname<-dirname(rstudioapi::getSourceEditorContext()$path)
setwd(dirname)


load("ggsurvplot_facet_error.rda")


fit_test <- survfit(
  Surv(follow_up, as.numeric(status)) ~ (sex + variable1), data = data)

plot_test <- ggsurvplot_facet(fit_test,
                                     data = data,
                                     pval = TRUE,
                                     conf.int = TRUE,
                                     surv.median.line = "hv", # Specify median survival
                                     break.time.by = 1,
                                     facet.by = "sex",
                                     ggtheme = theme_bw(), # Change ggplot2 theme
                                     palette = "aaas",
                                     legend = "bottom",
                                     xlab = "Time (years)",
                                     ylab = "Death probability",
                                     panel.labs = list(sex_recoded=c("Male", "Female")),
                                     legend.labs = c("A", "B")
) 

plot_test

Этот код прекрасно работает и генерирует следующий сюжет:

enter image description here

Однако, когда я пытаюсь преобразовать этот код в функцию или цикл FOR, чтобы он применял один и тот же код к variable1 и variable2, я всегда получаю сообщение об ошибке с частью color / palette этапа построения.

# Variables_with_2_categories:  variable1 and variable2
two <- c("variable1", "variable2")

## TEST #1: USING A FUNCTION

fit_plot_function <- function(x) {

# FIT part of the function
  two.i <- two[i]

fit_temp <- survfit(Surv(as.numeric(follow_up), as.numeric(status)) ~ 
                        sex + eval(as.name(paste0(two.i))), data = data)

# PLOT part of the function
  plot_temp <- ggsurvplot_facet(fit_temp,
                                data = data,
                                pval = TRUE,
                                conf.int = TRUE,
                                surv.median.line = "hv", # Specify median survival
                                break.time.by = 1,
                                facet.by = "sex",
                                ggtheme = theme_bw(), # Change ggplot2 theme
                                palette = "aaas",
                                legend = "bottom",
                                xlab = "Time (years)",
                                ylab = "Death probability",
                                panel.labs = list(sex_recoded=c("Male", "Female")),
                                legend.labs = rep(c("A", "B"),2)
  ) 
}


fit_plot_function(two)
# Warning message:
#  Now, to change color palette, use the argument palette= 
#  'eval(as.name(paste0(two.i)))' instead of color = 'eval(as.name(paste0(two.i)))' 

print(plot_temp)

# Error in grDevices::col2rgb(colour, TRUE) : 
#  invalid color name 'eval(as.name(paste0(two.i)))'

Похоже, когда он оценивает имена переменных, которые были проанализированы с вектором, он не распознает имена переменных. С циклом FOR это происходит точно так же:

## TEST #2: USING A FOR LOOP

n.two <- length(two)

for(i in 1:n.two) {
  two.i <- two[i]

  fit_temp <- survfit(Surv(as.numeric(follow_up), as.numeric(status)) ~ 
                        (sex + eval(as.name(paste0(two.i)))), data = data)



  plot_temp <- ggsurvplot_facet(fit_temp,
                                data = data,
                                pval = TRUE,
                                conf.int = TRUE,
                                surv.median.line = "hv", # Specify median survival
                                break.time.by = 1,
                                facet.by = "sex",
                                ggtheme = theme_bw(), # Change ggplot2 theme
                                palette = "aaas",
                                legend = "bottom",
                                xlab = "Time (years)",
                                ylab = "Death probability",
                                panel.labs = list(sex_recoded=c("Male", "Female")),
                                legend.labs = rep(c("A", "B"),2)
    ) 
}

print(plot_temp)

# ERROR: Now, to change color palette, use the argument palette= 'eval(as.name(paste0(two.i)))' 
# instead of color = 'eval(as.name(paste0(two.i)))

В качестве дополнительного комментария было бы здорово, если бы я мог применять один и тот же код к переменным, которые имеют оба, два или три разных значения одновременно, вместо того, чтобы применять разные функции для каждого из них.

Большое спасибо за помощь,

С наилучшими пожеланиями,

Yatrosin

> sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.6

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] survminer_0.4.3.999 ggpubr_0.2          magrittr_1.5        ggplot2_3.1.1       survival_2.44-1.1  
[6] dplyr_0.8.0.1       msm_1.6.7           mgcv_1.8-27         nlme_3.1-137       

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.1        pillar_1.3.1      compiler_3.5.1    plyr_1.8.4        tools_3.5.1       digest_0.6.18    
 [7] tibble_2.1.1      gtable_0.3.0      lattice_0.20-38   pkgconfig_2.0.2   rlang_0.3.4       Matrix_1.2-17    
[13] ggsci_2.9         rstudioapi_0.10   cmprsk_2.2-7      yaml_2.2.0        mvtnorm_1.0-10    expm_0.999-4     
[19] xfun_0.6          gridExtra_2.3     knitr_1.22        withr_2.1.2       survMisc_0.5.5    generics_0.0.2   
[25] grid_3.5.1        tidyselect_0.2.5  data.table_1.12.2 glue_1.3.1        KMsurv_0.1-5      R6_2.4.0         
[31] km.ci_0.5-2       purrr_0.3.2       tidyr_0.8.3       scales_1.0.0      backports_1.1.4   splines_3.5.1    
[37] assertthat_0.2.1  xtable_1.8-3      colorspace_1.4-1  labeling_0.3      lazyeval_0.2.2    munsell_0.5.0    
[43] broom_0.5.2       crayon_1.3.4      zoo_1.8-5   

1 Ответ

0 голосов
/ 16 апреля 2019

Пришло время мурлыкать. То, что вы хотите, можно сделать с помощью purrr. Вы можете прочитать о создании ggplot2 purrr здесь и больше примеров здесь .

Прежде всего нам нужно преобразовать ваши данные в длинный формат с помощью tidyr::gather. Мы будем держать все в кадре данных, как это было, за исключением переменных 1,2,3,4. Они будут таять.

library(tidyr)
library(dplyr)
library(purrr)

data %>% 
  gather(num, variable, -sample_id,  -sex,
         -visit_number, -age_at_enrollment,
         -follow_up, -status) %>% 
  mutate(num2 = num) %>% # We'll need this column later for the titles
  as_tibble() -> long_data


# A tibble: 2,028 x 8
   sample_id   sex    visit_number age_at_enrollment follow_up status num       variable
   <fct>       <fct>  <fct>                    <dbl>     <dbl> <fct>  <chr>        <int>
 1 sample_0001 Female 1                         56.7     0     1      variable1        0
 2 sample_0001 Female 2                         57.7     0.920 1      variable1        0
 3 sample_0001 Female 3                         58.6     1.90  1      variable1        0
 4 sample_0001 Female 4                         59.7     2.97  2      variable1        0
 5 sample_0001 Female 5                         60.7     4.01  1      variable1        0
 6 sample_0001 Female 6                         61.7     4.99  1      variable1        0
 7 sample_0002 Female 1                         55.9     0     1      variable1        1
 8 sample_0002 Female 2                         56.9     1.04  1      variable1        1
 9 sample_0002 Female 3                         58.0     2.15  1      variable1        1
10 sample_0002 Female 4                         59.0     3.08  1      variable1        1
# ... with 2,018 more rows

Теперь нам нужно преобразовать наш длинный фрейм данных во вложенный фрейм данных и map! Будьте точны с ggsurvplot - эта функция не поддерживает tibbles, которые создаются во время nest().

long_data %>% 
  group_by(num) %>% 
  nest() %>% 
  mutate(
    # Run survfit() for every variable
    fit_f = map(data, ~survfit(Surv(follow_up, as.numeric(status)) ~ (sex + variable), data = .)),
    # Create survplot for every variable and survfit
    plots = map2(fit_f, data, ~ggsurvplot(.x,
                                          as.data.frame(.y), # Important! convert from tibble to data.frame 
                                          pval = TRUE,
                                          conf.int = TRUE,
                                          facet.by = "sex",
                                          surv.median.line = "hv", 
                                          break.time.by = 1,
                                          ggtheme = theme_bw(),
                                          palette = "aaas",
                                          xlab = "Time (years)",
                                          ylab = "Death probability") +
                   ggtitle(paste0("This is plot of ", .y$num2)) + # Add a title
                   theme(legend.position = "bottom"))) -> plots

Теперь вы можете вернуть свои участки, набрав:

plots$plots[[1]]
plots$plots[[2]]
plots$plots[[3]] 
plots$plots[[4]] # plotted below

enter image description here

И сохраните все свои графики, используя map2()

map2(paste0(unique(long_data$num), ".pdf"), plots$plots, ggsave)

UPDATE

К сожалению, я не могу понять, как изменить ярлыки легенды. Единственное решение, которое я могу предложить, это ниже. Помните, что plots$plots[[…]] является ggplot объектом, поэтому вы можете изменить все после. Например, чтобы изменить метки легенды, мне просто нужно добавить scale_fill_discrete и scale_color_discrete. То же самое можно сделать с заголовком, лабораториями, темой и т. Д.

library(ggsci) # to add aaas color palette

plots$plots[[3]] +
  labs(title = "Variable 3",
       subtitle = "You just have to be the best") +
  ggsci::scale_color_aaas(guide = F) +
  ggsci::scale_fill_aaas(label = LETTERS[1:3])

enter image description here

...