0

I am trying to make a shiny app where you can select different miRNA in my input then plot the survival curve using ggsurvplot. There is something wrong with the functions within fitSurv, but I am not sure where I am doing it wrong.

library(dplyr) 
require(survminer)
library(tidyverse)
require(reshape2)
library(shiny)
library(tidyr)
require(survival)

example data:

 df.miRNA.cpm <-     structure(list(`86` = c(5.57979757386892, 17.0240095264258, 4.28380151026145, 
13.0457611762755, 12.5531123449841), `175` = c(5.21619202802748, 
15.2849097474841, 2.46719979911461, 10.879496005461, 9.66416497290915
), `217` = c(5.42796072966512, 17.1413407297933, 5.15230233060323, 
12.2646127361351, 12.1031024927547), `394` = c(-1.1390337316217, 
15.1021660424984, 4.63168157763046, 11.1299079134792, 9.55572588729967
), `444` = c(5.06134249676025, 14.5442494311861, -0.399445049232868, 
7.45775961504073, 9.92629675808998)), row.names = c("hsa_let_7a_3p", 
"hsa_let_7a_5p", "hsa_let_7b_3p", "hsa_let_7b_5p", "hsa_let_7c_5p"
), class = "data.frame")

df.miRNA.cpm$miRNA <- rownames(df.miRNA.cpm)


  ss.survival.shiny.miRNA.miRNA <-   structure(list(ID = c("86", "175", "217", "394", "444"), TimeDiff = c(71.0416666666667, 
601.958333333333, 1130, 1393, 117.041666666667), Status = c(1L, 
1L, 0L, 0L, 1L)), row.names = c(NA, 5L), class = "data.frame")

Joint the two example data frames:

 data_prep.miRNA <- df.miRNA.cpm %>% 
tidyr::pivot_longer(-miRNA, names_to = "ID") %>% 
left_join(ss.survival.shiny.miRNA.miRNA)

Example of the joined data:

 > data_prep.miRNA
# A tibble: 153,033 x 5
   miRNA         ID     value TimeDiff Status
   <chr>         <chr>  <dbl>    <dbl>  <int>
 1 hsa_let_7a_3p 86     5.58      71.0      1
 2 hsa_let_7a_3p 175    5.22     602.       1
 3 hsa_let_7a_3p 217    5.43    1130        0
 4 hsa_let_7a_3p 394   -1.14    1393        0
 5 hsa_let_7a_3p 444    5.06     117.       1
 6 hsa_let_7a_3p 618    4.37    1508        0
 7 hsa_let_7a_3p 640    2.46    1409        0
 8 hsa_let_7a_3p 829    0.435    919.       0
 9 hsa_let_7a_3p 851   -1.36     976.       0
10 hsa_let_7a_3p 998    3.87    1196.       0
# … with 153,023 more rows

For a selected MicroRNA this works:

fitSurv <- survfit(Surv(data$TimeDiff, data$Status) ~ paste(cut(value   , quantile(value   , probs = c(0, 0.8)), include.lowest=T)), data = data_prep.miRNA[grep("hsa_let_7a_3p",data_prep.miRNA$miRNA),])

Shiny:

ui.miRNA <- fluidPage(
  selectInput("MicroRNA", "miRNA", choices = unique(data_prep.miRNA$miRNA)),

  plotOutput("myplot"))

server <- function(input, output, session) {
  
  data_selected <- reactive({
    filter(data_prep.miRNA, miRNA %in% input$MicroRNA)
  })
  
  output$myplot <- renderPlot({
    fitSurv <- survfit(Surv("TimeDiff", "Status") ~ paste(cut("value"   , quantile("value"   , probs = c(0, 0.8)), include.lowest=T)), data = data_selected)
    ggsurvplot(fitSurv ,title="", xlab="Time (Yrs)", ylab="Survival prbability",
               font.main = 8,
               font.x =  8,
               font.y = 8,
               font.tickslab = 8,
               font.legend=8,
               pval.size = 3,
               pval.coord = c(1000,1),
               size=0.4,
               legend = "right",
               censor.size=2,
               break.time.by = 365,
               pval =T,#"p=0.003",#"p=0.41",
               #xscale=365,
               #palette = c("#E7B800", "#2E9FDF"),
               #ggtheme = theme_bw(),
               risk.table = F,
               xscale=365.25,
               xlim=c(0,7*365))
    
    
  })
}

shinyApp(ui.miRNA, server)
user2300940
  • 2,355
  • 1
  • 22
  • 35
  • shiny: cannot coerce class ‘c("reactiveExpr", "reactive", "function")’ to a data.frame – user2300940 Jul 09 '20 at 10:47
  • try `data = data_selected()`. With this, the reactive function evaluates to the actual data.frame – starja Jul 09 '20 at 10:49
  • Warning: Error in as.data.frame.default: cannot coerce class ‘c("reactiveExpr", "reactive", "function")’ to a data.frame – user2300940 Jul 09 '20 at 10:52
  • Have you left out `as.data.frame`? You shouldn't need it – starja Jul 09 '20 at 10:53
  • yes, did not change much. I think the error is how I call the "MicroRNA" and "TimeDiff", "Status" – user2300940 Jul 09 '20 at 10:56
  • ok. Without example data it is difficult to further help – starja Jul 09 '20 at 11:03
  • @Roman Good suggestion. After doing that the error changed to: 'data' argument is of the wrong type – user2300940 Jul 09 '20 at 11:08
  • @Roman Please see updated with example data – user2300940 Jul 09 '20 at 11:16
  • @user2300940 using your updated data I still get an error here: `fitSurv <- survfit(Surv("TimeDiff", "Status") ~ paste(cut("MicroRNA" , quantile("MicroRNA" , probs = c(0, 0.8)), include.lowest=T),na.rm=F), data = dplyr::filter(data_prep.miRNA, miRNA == "hsa_let_7a_3p"))` – Roman Jul 09 '20 at 11:23
  • Yes, I also get this now: Error in Surv("TimeDiff", "Status") : Time variable is not numeric – user2300940 Jul 09 '20 at 11:32
  • 1
    and what is this `paste(cut("MicroRNA" , quantile("MicroRNA" , probs = c(0, 0.8)), include.lowest=T))`? The "MicroRNA" should be "value", right? – Roman Jul 09 '20 at 11:38
  • Yes, that is true. It is the value for each specific MicroRNa that I divide into two quantiles. However, changing that did not solve it. Still get this: Warning: Error in terms.formula: 'data' argument is of the wrong type – user2300940 Jul 09 '20 at 11:52
  • @Roman do you have any further suggestions what causes the problems? – user2300940 Jul 09 '20 at 12:15
  • What is your latest attempt for the `survfit` statement ? The one without this strange `paste(cut(...` ? – Stéphane Laurent Jul 09 '20 at 13:29
  • I have to do the paste cut to obtain two quantiles. Please see updated example on how it works for one specific miRNA – user2300940 Jul 09 '20 at 13:33
  • `survfit(Surv(TimeDiff, Status) ~ value, data = data_prep.miRNA)` works, but I don't understand what you want to do with `cut`. The right member of the formula must be a numeric variable (like `value`), no ? – Stéphane Laurent Jul 09 '20 at 13:38
  • If you do It like you suggest you get very many value-lines in the plot. I would like to divide value into two quantiles which results in two lines in the plot, for upper and lowe quantile of the value, respectively. – user2300940 Jul 09 '20 at 13:45
  • I think you want `probs = c(0, 0.8, 1)` otherwise there is only one category. For me this works: `survfit(Surv(TimeDiff, Status) ~ cut(value, quantile(value, probs = c(0,0.8,1)), include.lowest = TRUE), data = data_prep.miRNA)`, but I only use a subset of your data. This code doesn't work for you ? What is the error you get ? – Stéphane Laurent Jul 09 '20 at 13:54
  • awesome. seems to work for me as well. Please post it as an answer if you like – user2300940 Jul 09 '20 at 13:57
  • I noticed that the plot does not change when I choose different miRNA in the finished shiny app. It seems to plot only the first – user2300940 Jul 09 '20 at 14:11

1 Answers1

0

There are several mistakes in this statement:

fitSurv <- 
  survfit(Surv("TimeDiff", "Status") ~ paste(cut("value", quantile("value", probs = c(0, 0.8)), include.lowest=T)), 
          data = data_selected)

First, data_selected is a reactive conductor, not a dataframe. If you want the dataframe returned by this reactive conductor, you have to use parentheses: data_selected().

Next, you must not quote the variables: TimeDiff and not "TimeDiff", etc.

The paste command is useless.

Your cut produces only one category and the NA category. To get two intervals as categories, use probs = c(0, 0.8, 1) in quantile.

Finally it is not a good idea to use T for TRUE, because T can be set to any R object, while TRUE is a reserved work.

To conclude, here is the corrected code:

fitSurv <- 
  survfit(Surv(TimeDiff, Status) ~ cut(value, quantile(value, probs = c(0, 0.8, 1)), include.lowest=TRUE), 
          data = data_selected())
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225