shinyapps.io does not draw plots - r

I built a simple app using FactorMineR package to do MCA analysis and clustering depending on selected variables.
The app works fine on my local device, however it does not show any plots (either base plots and ggplots) on shinyapps.io server. I checked the packages and locally and remotley they are the same. I also checked if the MCA() function from FactoMineR pcg even works by extracking some results and rendering them as a table what gave positive results. So there is only the problem with plots drawing. I have been trying to solve it for two days but nothing helps so I am asking you for any advice.
Here is how it looks locally:
Here is the link to the app: https://mikolajm.shinyapps.io/MCA_test/
And a reproducible example
library(shiny)
library(FactoMineR)
library(cluster)
library(ggplot2)
data(tea)
ui <- fluidPage(
# Application title
titlePanel("MCA"),
textOutput("packages"),br(),
tableOutput("table"),br(),
fluidRow(
column(4, checkboxGroupInput("Variables", "Select variables:",
names(tea), selected=c("breakfast", "tea.time"))),
column(4, plotOutput("plot")), column(4, plotOutput("plot1"))),
fluidRow(column(12, plotOutput("dendro", height = "700px", width="1200px"))
)
)
server <- function(input, output) {
## packages checking
output$packages <- renderText({.packages()})
tea_selected <- reactive({
tea[, input$Variables]
})
## table with some results from MCA() fun
output$table <- renderTable({
tea.mca <- MCA(tea_selected(), ncp=9)
tea.mca$eig[1:5,]
})
## mca1
output$plot <- renderPlot({
library(FactoMineR)
par(mfrow=c(2,2))
tea.mca <- MCA(tea_selected(), ncp=9)
})
## mca with ggplot
output$plot1 <- renderPlot({
tea.mca <- MCA(tea_selected(), ncp=9)
tea_vars_df <- data.frame(tea.mca$var$eta2, Variable =names(tea_selected()))
library(ggplot2)
pp <- ggplot(data=tea_vars_df, aes(x=Dim.1, y=Dim.2, label=Variable))+
geom_hline(yintercept = 0, colour = "gray70") +
geom_vline(xintercept = 0, colour = "gray70") +
geom_point()+
geom_text() +
ggtitle("MCA plot of variables ")+
theme_bw()
pp
})
### dendro
output$dendro <- renderPlot({
library(FactoMineR)
library(cluster)
tea.mca <- MCA(tea_selected(), ncp=9)
classif <- agnes(tea.mca$ind$coord,method="ward")
plot(classif,main="Dendrogram",ask=F,which.plots=2)
})
}
# Run the application
shinyApp(ui = ui, server = server)

EDIT: You can see plots obviously, but
ORIGINAL
I could not see plots in your shiny app when I ran your code.
After some digging, my guess is only that:
You use a lot of functions that come with the FactoMineR package. For instance, you use the function MCA in output$plot1 code block. Type MCA in your R command line, and it should print the function. You can see MCA does a lot of stuff and eventually calls plot.MCA. Now type plot.MCA in your R command line. You can see that plot.MCA has a lot of plot commands, and I'm pretty sure this executes all the plotting when you call MCA. I think your problem is that plot in the function plot.MCA is sent to the graphic device, and these plots are not saved, ie they are not return() to the parent environment. This is only speculation.

Related

how to fix 'Error: variable lengths differ (found for 'input$s')' in R Shiny

I'm trying to make a simple shiny ap for creating kaplan-meier survival curves that are stratified by selection the user makes. When I code the KM calculation statically (with the column name thorTr) it works but the calculation and plot is static. When I replace with input$s I get ERROR:variable lengths differ (found for 'input$s')
I've tried looking at other code which use as.formula and paste, but I don't understand and couldn't get to work. But I am a new R and Shiny user so maybe I didn't get it right. Here is a similar shiny ap but I want to use survminer and the ggsurvplot for plotting
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
#load data
data(GBSG2, package = "TH.data")
#Define UI for application that plots stratified km curves
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("horTh","menostat","tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the km plot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
#calc KM estimate with a hard coded variables - the following line works but obviously is not reactive
#km <- survfit(Surv(time,cens) ~ horTh,data=GBSG2)
#replaced hard coded horTh selection with the respnse from the selection and I get an error
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
#plot km
ggsurvplot(km)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I expect to have a plot that updates the stratification variable with the users selection
Try using surv_fit() instead of survfit().
surv_fit() is a helper from survminer which does different scoping compared to survival:survit(), which is what you seem to need, as Byron suggests.
My snippet looks like:
output$plot <- renderPlot({
formula_text <- paste0("Surv(OS, OS_CENSOR) ~ ", input$covariate)
## for ggsurvplot, use survminer::surv_fit instead of survival:survfit
fit <- surv_fit(as.formula(formula_text), data=os_df)
ggsurvplot(fit = fit, data=os_df)
})
Two things:
The formula in the call to survfit() needs to be defined explicitly. The object being passed to survfit() in the original code uses a character value on the right hand side of the function. This throws an error, which we can address by translating the entire pasted value into a formula, i.e., as.formula(paste('Surv(time,cens) ~',input$s))
The formula needs to be defined in the call to ggsurvplot() to avoid scoping issues. This is a little more technical and has to do with the way that ggsurvplot() is programmed. Basically, ggsurvplot() can't access a formula that is defined outside of its own call.
Try replacing
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
ggsurvplot(km)
with
ggsurvplot(survfit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2))
Hi finally got this to work combinigng both solutions. I don't understand the fix but at least it now works the way I wanted it to :)
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
data(GBSG2, package = "TH.data")
# Define UI for application that plots features of movies
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("Hormone Therapy" = "horTh",
"Menopausal Status" = "menostat",
"Tumor Grade" = "tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the scatterplot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
## calc survival curve and plot
kmdata <- surv_fit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2)
ggsurvplot(kmdata)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)

All plots output of xray's distributions in Shiny?

So the problem is that I am using xray package called to plot distributions from my data into Shiny dashboard.
Here is an example of the distributions function usage with my data:
ui <- fluidPage(
plotOutput("Distribute")
)
server <- function(input, output, session) {
#For Distribution
distribute <- reactive({
distrLongley=longley
distrLongley$testCategorical=c(rep('One',7), rep('Two', 9))
xray::distributions(distrLongley, charts = T)
})
output$Distribute <- renderPlot({
#distribute()
xray::distributions(longley, charts = T)
})
}
shinyApp(ui, server)
It shows from 3 to 4 distributions but actually it should show more distributions. When running in the console mode, I can see all the plots in plots screen. But when I run it in Shiny, it only shows few charts, which is not the desired output.
I don't know why the function shows all the plots when executing from the RStudio console, but not when executing in Shiny. Unlike in the RStudio plot viewer, there is not an option to move to next page option in Shiny.
The problem is that longley dataset contains 7 columns and xray package creates two 2 x 2 grids of graphs. And on the first graph it shows 4 graph and the second one it shows 3 graphs. The last graph overdraw the first one.
To cope with the problem you can temporarily save two graphs into two PNG file then load them into imageOutput. Please see the code below:
library(xray)
library(shiny)
ui <- fluidPage(
imageOutput("Distribute1"),
imageOutput("Distribute2")
)
server <- function(input, output, session) {
png("x%03d.png")
xray::distributions(longley, charts = T)
dev.off()
output$Distribute1 <- renderImage({
list(src = "x001.png")
}, deleteFile = FALSE)
output$Distribute2 <- renderImage({
list(src = "x002.png")
}, deleteFile = FALSE)
}
shinyApp(ui, server)
Output:

Removing the X,Y in nearPoints() Output

I want to use the functionality of nearPoints() to print out summary statistics for a specific point without printing the x, y associated with that point. I have been able to use this function printing the data frame and variations of the data frame. Is there anyway to suppress those columns
to customize the output? nearPoints comes from the latest version of shiny 0.12.1 but I believe may have been introduced a little earlier.
I know the documentation says this:
Note that these functions are only appropriate if the x and y variables are present in the data frame, without any transformation. If, for example, you have a plot where a the x position is calculated from a column of data, then these functions won’t work. In such a case, it may be useful to first calculate a new column and store it in the data frame.
but wanted to know if there was any kind of work around.
Here is the app that illustrates this problem, note that I'm using all of those libraries in my bigger app:
library(shiny)
library(ggplot2)
library(Cairo)
library(plyr)
library(dplyr)
library(shinydashboard)
library(grid)
library(gridExtra) # also loads grid
library(grDevices)
library(ggmap)
library(sqldf)
cars <- mtcars
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
dataTableOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
ggplot(cars, aes(x=cyl, y=carb)) + geom_point()
})
output$info <- renderDataTable({
summary_cars <- ddply(cars, .(gear, cyl, carb),
function(dd){as.data.frame(cbind(Mean_hp = mean(dd$hp),
Mean_wt = mean(dd$wt))
)
})
#This works-------------------------------------------------------
# nearPoints(summary_cars, input$plot_click, threshold = 10,
# addDist = TRUE)
#Removing the columns does not work ---------
nearPoints(select(summary_cars,-cyl,-carb), input$plot_click, threshold = 10,
addDist = F)
})
}
shinyApp(ui, server)

Create a number of renderPlot functions, based on the number of plots I have in a list of ggplots?

Is there any way I can dynamically create a number of renderPlot functions, based on the number of plots I have in a list of ggplots?
I have a Shiny app where instead of having a stable UI, and instead of using renderUI, I am relying on a user-supplied config file to tell Shiny how many plots to show. The config file also supplies data and pretty much helps do most of the heavy lifting.
After much battling, I'm mostly there. With the handy-dandy config file, I can build the correct UI, and generate the correct number of ggplots. The ggplots live in a list, creatively named list_of_ggplots.
But now, I'm at a point where I have a list of ggplots, and I need to allow them to be plotted by using them like this:
output$plot1 <- renderPlot({
print(list_of_ggplots[[1]])
})
But now I have an existentialist crisis -- I can't do it like this, since the user-supplied config file tells me how many plots I have. I can no longer hard code the renderPlot call like is usually done in Shiny, since the number of these functions needed is defined in the config file.
Given my list of ggplots, I need some way to generate the renderPlot calls.
Has anyone done this or have any ideas? Much appreciated.
Here's my code:
SERVER.R:
library(shiny)
library(ggplot2)
# 3 simple plots of different colors -- used here instead of all the complicated stuff
# where someone uses the config file that specified 3 plots, with data, etc.
ggplot_names <- c("p1", "p2", "p3")
ggplot_colors <- c("red", "blue", "green")
list_of_ggplots <- list()
j = 1
for (i in ggplot_names){
i <- ggplot(data.frame(x = c(-3, 3)))
i <- i + aes(x)
i <- i + stat_function(fun = dnorm, colour=ggplot_colors[[j]])
list_of_ggplots[[j]] <- i
j <- j+ 1
}
## here's the problem -- the user specified 3 plots.
## I can't hardcode the following shinyServer functions!!!
## What if tomorrow, the user specifies 2 plots instead?
shinyServer(function(input, output) {
output$plot1 <- renderPlot({
print(list_of_ggplots[[1]])
})
output$plot2 <- renderPlot({
print(list_of_ggplots[[2]])
})
output$plot3 <- renderPlot({
print(list_of_ggplots[[3]])
})
})
UI.R
## this top part is actually sourced from the config file
## since Shiny needs to know how many tabPages to use,
## names for the tabs, etc
number_of_tabPages <- 3
tab_names <- c("", "Tab1", "Tab2", "Tab3")
tabs<-list()
tabs[[1]]=""
for (i in 2:(number_of_tabPages+1)){
tabs[[i]]=tabPanel(tab_names[i],plotOutput(paste0("plot",i-1)))}
## Here's the familiar UI part
shinyUI(fluidRow(
column(12,
"",
do.call(navbarPage,tabs)
)
)
)
You can use this solution (I modified only the shinyServer part of your scripts, so I don't list the repeating code here):
shinyServer(function(input, output) {
observe(
lapply(seq(3),function(i) output[[paste0("plot",i)]] <- renderPlot(list_of_ggplots[[i]]))
)
})
Of course, you can replace 3 by a variable.

Many error signs when running ggplot in render plot (shiny in general)

Took very basic shiny scripts and were able to play around the generic data sets. When I tried to put in my own and run ggplot, I've come across several errors. Most recent is what appears in my main panel of shiny app and console in Rstudio
...
"ggplot2 doesn't know how to deal with data of class reactive"
...
In general, I stripped down my ggplot to the most basic elements and still not sure from where ggplot is calling data while in shiny. I am guessing the reactive function, but honestly, I am lost.
Below are scripts
_____ui.R________
shinyUI(pageWithSidebar(
headerPanel('Mock Risk Scorecard'),
sidebarPanel(
selectInput('xcol', 'X Axis', names(RandomRiskCard)),
selectInput('ycol', 'Y Axis', names(RandomRiskCard),
selected=names(RandomRiskCard)[[2]]),
min = 1, max = 9),
mainPanel(
plotOutput('plot1')
)
)
)
_____server.R____
palette(c("#E41A1C", "#377EB8"))
shinyServer(function(input, output, session) {
# Combine the selected variables into a new data frame
selectedData <- reactive({
RandomRiskCard[, c(RandomRiskCard$xcol, RandomRiskCard$ycol)]
})
output$plot1 <- renderPlot({
p <- ggplot(selectedData, aes(x = RandomRiskCard$xcol, y = RandomRiskCard$ycol))
p <- p + geom_point()
})
})
I also loaded up my data and Run Shiny in different script windows as follow
install.packages("shiny")
library(shiny)
library(ggplot2)
runApp("U:/App-1")
as well as
RandomRiskCard = read.csv("U:/App-1/RandomRiskCard.csv")
I am eventually hoping to incorporate factor function and annotate with colors like I had done with my original ggplot. If it wasn't already obvious I am a newbie at this, but shiny has me completely twisted.
Reactive expressions should be called in the same way as parameter-less functions, with following parentheses: ggplot(selectedData(),...
xcol and ycol should be obtained via input:
p <- ggplot(selectedData(), aes(x = input$xcol, y = input$ycol)) in output$plot, and
RandomRiskCard[, c(input$xcol, input$ycol)] in selectedData

Resources