Operation Not Allowed Active Reactive Context - Subset in RShiny - r

I want to create a subset dataframe in shiny to output various filtered options in my ploy. In the UI, my variable PLAN_DIM_CK are my different choices, and each PLAN_DIM_CK number is the what I want to subset by. When I run the code, I get the error "Operation not allowed without an active reactive context (You tried to do something that can only be done inside a reactive expression or observer.)
Can anyone help me with where this issue lies?
# Filter by plan in UI
selectInput(inputId = "PlanID",
label = "Select a Plan",
choices = unique(vbc2$PLAN_DIM_CK)
In the server
#within server
subsetTest <- reactive ({
subset(vbc2, PLAN_DIM_CK == input$planID)})
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
output$distPlot <- renderPlot({
ggplot(data = subsetTest(), aes(x=y,y=x))

My best guess would be that you need to use observe. The x and y variables should be inside observe, something similar to this:
observe({
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
})
Using global variables like this is not a good option. I would suggest you put this x and y variables inside your renderPlot or create reactive variables from it.
Putting it inside the renderPlot could be something like this:
output$distPlot <- renderPlot({
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
ggplot(data = subsetTest(), aes(x=y,y=x))
)}
Using reactive you could do something like this:
subsetTest <- reactive ({
subset(vbc2, PLAN_DIM_CK == input$planID)})
y <- reactive({subsetTest()$RISK_ADJUSTED_HBR})
x <- reactive({subsetTest()$PANEL_SIZE})
output$distPlot <- renderPlot({
ggplot(data = subsetTest(), aes(x=y(),y=x()))
Also, it would be better that you provide a minimal reproducible example from next time so that it would be easy to help you.

Related

Structure Server Function in a Shiny App

I am struggling with my first shiny app and having problems to make it work due to, I think, I am missing out something in the server function.
I have a R script that has two variables (the two reactive values in shiny) that creates a plot (a histogram) and a csv file with two columns (time and mm).
library(ggplot2)
**Pdmm** <- 125 # numeric input in shiny
**IndiceTorrencial** <- 10 # slider between 8 and 12 in shiny
DuracionAgua <- 24
IntervaloMin <- 60
IntervaloTiempo <- IntervaloMin/60
Intervalos <- DuracionAgua/IntervaloTiempo
t <- seq(1,Intervalos,IntervaloTiempo)
DF <- data.frame(t)
DF$I <- (**Pdmm**/24)*(**IndiceTorrencial**)^(((28^0.1)-(DF$t^0.1))/((28^0.1)-1)) # equation where the reactive values are running
DF$Pacu <- DF$t*DF$I
DF$Pmm <- c(DF$Pacu[1], diff(DF$Pacu, lag = 1))
DF$mm <- c(DF$Pmm[23],DF$Pmm[21],DF$Pmm[19],DF$Pmm[17], DF$Pmm[15],DF$Pmm[13],DF$Pmm[11],DF$Pmm[9],DF$Pmm[7],DF$Pmm[5],DF$Pmm[3],DF$Pmm[1],DF$Pmm[2],DF$Pmm[4],DF$Pmm[6],DF$Pmm[8],DF$Pmm[10],DF$Pmm[12],DF$Pmm[14],DF$Pmm[16],DF$Pmm[18],DF$Pmm[20],DF$Pmm[22],DF$Pmm[24])
ggplot(DF,aes(x=t,y=mm)) + geom_bar(stat = "identity",fill = "dodgerblue",color = "black") + scale_x_continuous(name = "t(h)", breaks = seq(1,24,1)) + scale_y_continuous(name = "mm")
My shiny app has, in its UI, a slider, a numeric input and a plot. It works, I will have time to make something better.
ui <- basicPage(
sliderInput(inputId = "coefTo",
label = h3("Torrentiality Coefficient"),
value = 10, min = 8, max = 12),
numericInput(inputId = "PmmS",
label = h3("Areal Precipitation"),
value = 100),
imageOutput("plot")
)
The problem is in the server function. I think I am sure that I have to use a reactive function in order to execute the code and to yield the results (histogram and csv). Also, to plot the histogram, I have a renderPlot.
server <- function(input, output, session){
data <- reactive({
DuracionAgua <- 24
IntervaloMin <- 60
IntervaloTiempo <- IntervaloMin/60
Intervalos <- DuracionAgua/IntervaloTiempo
t <- seq(1,Intervalos,IntervaloTiempo)
DF <- data.frame(t)
DF$I <- (input$PmmS/24)*(input$coefTo)^(((28^0.1)-(DF$t^0.1))/((28^0.1)-1))
DF$Pacu <- DF$t*DF$I
DF$Pmm <- c(DF$Pacu[1], diff(DF$Pacu, lag = 1))
DF$mm <- c(DF$Pmm[23],DF$Pmm[21],DF$Pmm[19],DF$Pmm[17], DF$Pmm[15],DF$Pmm[13],DF$Pmm[11],DF$Pmm[9],DF$Pmm[7],DF$Pmm[5],DF$Pmm[3],DF$Pmm[1],DF$Pmm[2],DF$Pmm[4],DF$Pmm[6],DF$Pmm[8],DF$Pmm[10],DF$Pmm[12],DF$Pmm[14],DF$Pmm[16],DF$Pmm[18],DF$Pmm[20],DF$Pmm[22],DF$Pmm[24])
DFm <- DF$mm
return(DFm)
})
output$plot <- renderPlot({
ggplot(data(DFm),aes(x=t,y=mm)) + geom_bar(stat = "identity",fill = "dodgerblue",color = "black") + scale_x_continuous(name = "t(h)", breaks = seq(1,24,1)) + scale_y_continuous(name = "mm")
})
}
When I run this script, I get the shiny app I have the slider and the numeric input, but not the plot getting an error message saying Error: unused argument (DFm). DFm is not created, so I assume that I am placing bad the code from my original script inside the shiny app, but I cannot figure out how to do it.
I have tried several things to make the server works, but I think that the script never runs inside the shiny app. I tried to create two reactive functions, one per each reactive value. I tried to put all the code from my original script out of the shiny leaving just the reactive values inside the shiny code... I tried with observe function as well.
Another problem I have is that I am not sure about the renderPlot. I am aware that I have to call the reactive function, data, but as I am not sure if it is well made.
I think that my server function is a total disaster. I have looked for examples in the shiny gallery and in Google, but I do not see something similar to help me.
Could anyone give a tip in order to fix my server function?
Many thanks in advance.
Following the advice of our colleague, I could solve my problem by setting DF, the first data frame I created, in return() inside the reactive function. Another confusion was how to set the object from the reactive function inside the renderplot.

use function to plot in shiny

I use a function to plot in R, because this is pretty large code for the plot (hexagonals etc). For the sake of neat code I put this in a function.
It is about a SOM algorithm , that does not really matter for now, but I create the data I need, then I normally plot it with the following code:
mydata <- som_model$codes
var <- 1
title <- names(som_model$data)[var]
dataplot <- matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source('plotHexMap.R')
plotHexMap(dataplot,title,gridsize)
So now I want to do this in Shiny:
observe({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<-matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R")
output$plot1 <-renderPlot({plotHexMap(dataplot,title,gridsize)})
}
})
Ok so this does not work, but when I just write the plot to a global variable (with <<-) it does exist and I can see it in the plots, so by doing this:
observe({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<-matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R")
plot1 <<-renderPlot({plotHexMap(dataplot,title,gridsize)})
}
})
What am I missing here? what does shiny need that normal R environment does not to plot this from function?
would really appreciate any help with this! Thanks in advance,
Pieter
Instead of observe, try renderPlot in server:
output$myplot <- renderPlot({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<- matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R", local = TRUE) #assuming this file is actually local for you
plot1 <- plotHexMap(dataplot,title,gridsize)
}
else{return(NULL)}
})
And then plotOutput in the ui:
plotOutput('myplot')

R Shiny: Invalidate data periodically in reactive() yet not force DB call first time

I have a plot resulting from a DB query. I load data to refresh in the plot in the shiny app. To do this, I am using a combination of reactive() and invalidateLater(), but it is forcing a data load even the first time the plot is rendered. Is there any way to make the app use pre-fetched data for the plot, and invalidate/reactive cycle for background processing?
Sample code below (replace mtcars with some function that forces a long DB query):
library(shiny)
ui <- fluidPage(mainPanel(plotOutput('mpg')))
server <- function(input, output) {
output$mpg <- renderPlot({
p <- ggplot(mtcarsReactive(), aes(x = as.factor(cyl), y = mpg)) +
geom_boxplot()
print(p)
})
mtcarsReactive <- reactive({
invalidateLater(60000)
mtcars
})
}
shinyApp(ui = ui, server = server)
One way to do it is to rely on a global variable. You can define a global variable outside the ui/server functions (for example, firstRun <- 1). Then in your reactive
mtcarsReactive <- reactive({
invalidateLater(600)
if (first == 1) {
first <<- first + 1
return(mtcars)
} else {
return(diamonds)
}
})
Note the <<- assignment, which will assign the value to the global variable, instead of creating a new local variable (if you use normal <-).
I tested this under a newer version of Shiny than yours (because mine requires a session object in invalidateLater), but hopefully it works on your environment.

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