I am building a shiny app for doing some network analyses. I want to calculate properties for the network using a function that is stored in global.R. However, I am not able to get the table output.
Here is the the part of my ui.R where I set the output for the table
# More ui.R above
mainPanel(
tabsetPanel(id = "conditionedPanels",
tabPanel("Network Properties",br(),value = 1,
actionButton('netproperty', label='Calculate Properties',class="btn btn-primary"),
h3(textOutput("Data Summary", container = span)),
tableOutput('prop_table')),
##... More ui.R code below
and here is my server.R:
shinyServer( function(input, output, session) {
## Get the properties
props <- reactive({
if (input$netproperty <= 0){
return(NULL)
}
result <- isolate({
input$netproperty
tryCatch ({
if(input$data_input_type=="example"){
if(input$datasets == "Network1"){
load("data/Network1.rda")
props <- graph_topology(g)
props
} else if (input$datasets == "Network2"){
load("data/Network1.rda")
props <- graph_topology(g)
props
} else if (input$datasets == "Network3"){
el <- read.delim("data/Network3.txt")
g <- graph.data.frame(el, directed = FALSE)
props <- graph_topology(g)
props
} else if (input$datasets == "Network4") {
el <- read.delim("data/Network4.txt")
g <- graph.data.frame(el, directed = FALSE)
props <- graph_topology(g)
props
}
} else if (input$data_input_type=="custom"){
if (is.null(input$dt_file))
return(NULL)
inFile <- input$dt_file
dataDT <- as.matrix(read.delim(inFile$datapah, sep="\t", header = FALSE, fill = TRUE))
g <- graph.data.frame(dataDT, directed = FALSE)
props <- graph_topology(g)
props
}
},
error = function(err) {
print(paste("Select Example or custom data set"))
})
})
result
})
## Output properties table
output$prop_table <- renderTable({
props()
})
}
When I press the button calculate properties, I get the error message always, telling me that I need to select example or custom data. I have tried with custom and example datasets, and the error remains. If I remove the tryCatch command in server.R I get the error of length equal zero. It seems that the function graph_topology in my global.R files is not working properly, but if I run it outside of the shiny app I get a matrix, that I thought it could be easily visualize with renderTable. I have also tried instead of using uiOutput in the ui.R using tableOutput but I have the same problem.
Related
I'm new to R shiny and I'm building a R shiny app that allows users to update values on a matrixInput. When that values are change the app update my datasets with the new information. I would like to have a button ("Reset Button") that allows to show the matrix with the values in their original form (ie with my original dataset when it opens for the first time in the app), but i would like to do that without close/open the app.
this is part of the code:
library(shiny)
library(shinyjs)
library(data.table)
ui:
shinyUI(pageWithSidebar(
headerPanel("title"),
sidebarPanel(conditionalPanel(condition="input.tabselected==1",
selectInput("equip_input", "Equip", choices=c("Total", equip_order)),
matrixInput("matrix_aux",
value = matrix_aux,
cols = list(names = TRUE)),
useShinyjs(),
actionButton("action_simulation", "Simulation"),
actionButton("reset_button","Reset")))))
And in the server i tried to "reload" my R environment, that's where i have the datasets without changes:
shinyServer(function(input,output, session)({
var_aux1 <- reactive({
table_input = as.matrix(input$matrix_aux)
var_aux1 = table_input[,2]
return (var_aux1)})
var_aux2 <- reactive({
table_input = as.matrix(input$matrix_aux)
var_aux2 = table_input[,3]
return (var_aux2) })
var_aux3 <- reactive({
table_input = as.matrix(input$matrix_aux)
var_aux3 = table_input[,4]
return (var_aux3)})
observeEvent(input$action_simulation, {
var_aux1 <- as.numeric(var_aux1())
var_aux2<- as.numeric(var_aux2())
var_aux3 <- as.numeric(var_aux3())
v1[(v1$Equip == as.character(input$equip_input),]$var1 <<- var_aux1
v1[(v1$Equip == as.character(input$equip_input),]$var2 <<- var_aux2
v1[(v1$Equip == as.character(input$equip_input),]$var3 <<- var_aux3
}
#this button doesn't do what i want
observeEvent(input$reset_button, {
rm(list=ls())
load("mydata") })}))
But it doesn't work. How can I do it??
Example:
When the user change the values in the matrix, the app updates my datasets with the new values:
observeEvent(input$action_simulation, {
v1[(v1$Equip == as.character(input$equip_input),]$var1 <<- var_aux1
v1[(v1$Equip == as.character(input$equip_input),]$var2 <<- var_aux2
v1[(v1$Equip == as.character(input$equip_input),]$var3 <<- var_aux3
}})
And I would like to have a option to make reset to the original values without changes
I would need some help with the missing code here:
selectInput("portfolio",
"Portfolio:",
c("p1","p2"))
## missing code:
## if input$portfolio == "p1" do a bunch of calculations and spit out the variable var (a tibble).
# variable var goes into a reactiveVal...
table <- reactiveVal()
table(var)
On the server you can, set table (not a great name, perhaps use something else, like my_table? to reactiveValues(), and then observe for changes in input$portfolio
table <- reactiveValues(var=NULL)
observeEvent(input$portfolio, {
if(input$portfolio == "p1") {
table$var = <- someFunction()
}
})
Here is a full example, using mtcars
library(shiny)
ui <- fluidPage(
selectInput("make","Make:", choices = rownames(mtcars)),
tableOutput("subtable")
)
server <- function(input, output, session) {
subtable <- reactiveValues(var=NULL)
observeEvent(input$make, {
subtable$var = dplyr::filter(cbind(makes,mtcars), makes == input$make)
})
output$subtable <- renderTable(subtable$var)
}
shinyApp(ui, server)
I'm trying to get a reactiveValue that is depending on a reactive. In the real code (this is a very simplified version), I load a dataset interactively. It changes when pushing the buttons (prevBtn/nextBtn). I need to know the number of rows in the dataset, using this to plot the datapoints with different colors.
The question: Why can't I use the reactive ro() in the reactiveValues function?
For understanding: Why is the error saying "You tried to do something that can only be done from inside a reactive expression or observer.", although ro() is used inside a reactive context.
The error is definitely due to vals(), I already checked the rest.
The code :
library(shiny)
datasets <- list(mtcars, iris, PlantGrowth)
ui <- fluidPage(
mainPanel(
titlePanel("Simplified example"),
tableOutput("cars"),
actionButton("prevBtn", icon = icon("arrow-left"), ""),
actionButton("nextBtn", icon = icon("arrow-right"), ""),
verbatimTextOutput("rows")
)
)
server <- function(input, output) {
output$cars <- renderTable({
head(dat())
})
dat <- reactive({
if (is.null(rv$nr)) {
d <- mtcars
}
else{
d <- datasets[[rv$nr]]
}
})
rv <- reactiveValues(nr = 1)
set_nr <- function(direction) {
rv$nr <- rv$nr + direction
}
observeEvent(input$nextBtn, {
set_nr(1)
})
observeEvent(input$prevBtn, {
set_nr(-1)
})
ro <- reactive({
nrow(dat())
})
output$rows <- renderPrint({
print(paste(as.character(ro()), "rows"))
})
vals <- reactiveValues(needThisForLater = 30 * ro())
}
shinyApp(ui = ui, server = server)
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
I think you want
vals <- reactiveValues(needThisForLater = reactive(30 * ro()))
Not everything in a reactiveValues list is assumed to be reactive. It's also a good place to store constant values. So since it's trying to evaluate the parameter you are passing at run time and you are not calling that line in a reactive environment, you get that error. So by just wrapping it in a call to reactive(), you provide a reactive environment for ro() to be called in.
I am trying to build a Shiny interface with:
a main selector, which decides:
which submenu (input) to show, which decides:
how many subsequent inputs to show
Here's a minimal reproducible example.
If "First" is chosen from the main selector, then a submenu with two possibilities [1,2] exist. These possibilities result in 1 or 2 subsequent inputs being built. So these possibilities:
If "Second" is chosen from the main selector, then a submenu with two possibilities [3,4] exist. These possibilities result in 3 or 4 subsequent inputs being built.
ui <- fluidPage(
radioButtons(inputId="main_selector",label=h5('Select menu'),
choices = list('First','Second'),selected='First'),
uiOutput("ui_selected")
)
server <- function(input, output, session) {
build_inputs <- function(choices){
output = tagList()
for(i in 1:choices){
output[[i]] = tagList()
output[[i]][[1]] = numericInput(inputId = paste0(i),
label = paste0(i),
value = i)
}
}
# Are these reactive elements necessary? Should they be in the renderUI below?
first_submenu <- reactive({
input$first_submenu
})
second_submenu <- reactive({
input$second_submenu
})
output$ui_selected <- renderUI({
if (input$main_selector == 'First'){
selectInput(inputId = "first_submenu", label="First submenu",
choices=list(1,2))
choices_1 <- first_submenu()
# Build a list of inputs dependent on the choice above
output <- build_inputs(choices_1)
} else if (input$main_selector == 'Second'){
selectInput(inputId = "second_submenu", label="Second submenu",
choices=list(3,4))
choices_2 <- second_submenu()
# Build a list of inputs dependent on the choice above
output <- build_inputs(choices_2)
# Return output as output$ui_selected element
output
})
}
shinyApp(ui, server)
The error I receive is Warning: Error in :: argument of length 0. I believe this is because you can't call the outcome of first_submenu from the renderUI element - but I don't know how to structure my code correctly.
I am not sure whether this is what you are after. The main problem was that your function build_inputs does not return anything. The second problem is that choices from selectInput are not numeric, so you need to convert them beforehand. And one other minor problem, related to the error you mention, is that the elements you want to render exist at the same time, so putting a condition on input$first_submenu will trigger errors (even if it is NULL for a couple of milliseconds), so it's (almost always) good practice to take care of possibly null inputs. The last thing I did was to add another uiOutput for the last layer of dynamic inputs. Hope this helps.
ui <- fluidPage(
radioButtons(inputId="main_selector",label=h5('Select menu'),
choices = list('First','Second'),selected='First'),
uiOutput("ui_selected"),
uiOutput("ui_numeric_inputs")
)
server <- function(input, output, session) {
build_inputs <- function(choices) {
output = tagList()
for(i in 1:choices){
output[[i]] = tagList()
output[[i]][[1]] = numericInput(inputId = paste0(i),
label = paste0(i),
value = i)
}
return(output)
}
output$ui_selected <- renderUI({
if (input$main_selector == 'First'){
selectInput(inputId = "first_submenu", label="First submenu",
choices=c(1,2))
} else if (input$main_selector == 'Second'){
selectInput(inputId = "second_submenu", label="Second submenu",
choices=list(3,4))
}
})
output$ui_numeric_inputs <- renderUI({
if (input$main_selector == 'First' &&
(!is.null(input$first_submenu))) {
build_inputs(as.numeric(input$first_submenu))
} else if (input$main_selector == 'Second' &&
(!is.null(input$second_submenu))){
build_inputs(as.numeric(input$second_submenu))
}
})
}
shinyApp(ui, server)
I am writing an shiny app in which contains an stochastic function generates four objects - one plot and three tables. However, I want to render each object in different tabs without being executing the function four times since this stochastic function will generates four different versions. I have been researched online and find a lot people recommend "reactive()" but I still don't quite understand how to apply it to my problem. How can I use those four objects on rendering with only one execution on the function?
My "server.R" structure basically looks like the below:
shinyServer(function(input, output) {
stochastic_function() {
...
plot1 <- ...
table1 <- ...
table2 <- ...
table3 <- ...
result <- list(plot, table1, table2, table3)
return(result)
}
output$plot <- renderPlot({
})
output$table1 <- renderTable({
})
output$table2 <- renderTable({
})
output$table3 <- renderTable({
})
...
So, I have tried something like below for the stochastic function:
model <- eventReactive(input$goButton, {
reactive(WG_Model(cdata = cdata(), # load data from outside env
sdata = sdata(), # load data from outside env
N = input$n,
end_date = input$end_date,
cpx_goal = input$cpx,
N_new = input$n2,
end_date_new = input$end_date2,
spend_range = input$s_range,
spend_incr = input$s_incr
)
)
})
The idea is to add an "GoButton" to initiate the function and then save all outputs in a reactive fun(). So I can render each output with:
output$plot <- renderPlot({
model$gplot
})
output$table <- renderTable({
model$table
})
# Render UI section
output$tb <- renderUI({
tabsetPanel(tabPanel("About Model", plotOutput("plot")),
tabPanel("About Model", tableOutput("table")))
})
However, I only got "Error: object of type 'closure' is not subsettable" in the UI output. Which part did I miss?
If your model() is a list and contains data for all tables and a plot, it should work as in my example.
In this app, after pressing a button, a random number and data for a table and a plot are generated. Then the number, data for table and a plot are returned as a list and rendered with appropriate render* functions.
This app illustrates that the model function won't be re-run after accessing it with model() in other reactive functions.
However, there is an odd thing...the plot is not always rendered. You sometimes have to click the button few times to get the plot. The table is working always.
library(shiny)
ui <- shinyUI(fluidPage(
br(),
actionButton("numb", "generate a random numbers"),
br(),
br(),
verbatimTextOutput("text"),
plotOutput("plot"),
tableOutput("table")
))
server <- shinyServer(function(input, output) {
model <- eventReactive(input$numb, {
# draw a random number and print it
random <- sample(1:100, 1)
print(paste0("The number is: ", random))
# generate data for a table and plot
data <- rnorm(10, mean = 100)
table <- matrix(data, ncol = 2)
# create a plot
Plot <- plot(1:length(data), data, pch = 16, xlab ="", ylab = "")
# return all object as a list
list(random = random, Plot = Plot, table = table)
})
output$text <- renderText({
# print the random number after accessing "model" with brackets.
# It doesn't re-run the function.
youget <- paste0("After using model()$random you get: ", model()$random,
". Compare it with a value in the console")
print(youget)
youget
})
output$plot <- renderPlot({
# render saved plot
model()$Plot
})
output$table <- renderTable({
model()$table
})
})
shinyApp(ui = ui, server = server)