Here is a minimum example. I am trying to modularize an existing app to separate different analysis problems. Each problem is intended to have a sidebar panel for inputs and a main panel for outputs. I am having two problems with setting up the siderbar panel for inputs. I will have two buttons that are exchanged after the first is selected. This action is in the module server code that requires reading in the selected analysis (tab label in the navbar) and then acting on the value read. I get errors for this problem: Warning: Error in ==: comparison (1) is possible only for atomic and list types
44: [/appsdata/home/wk211a/Projects/vrat4/minexample.R#61]
1: runApp
The second problem is that I cannot get the simple renderText message to display in the first tab.
Here is the code:
##### Test Example
##### Setup VRAT App
ContCurrentSideBarPanelUI <- function(id){
ns <- NS(id)
tagList(
tabsetPanel(
id = "sbpcontin",
tabPanel(
"Setup",
value = "setup_Cont_Curr",
textOutput(ns("result"))
),
tabPanel(
"Verification",
value = "verify_Cont_Curr"
),
tabPanel(
"Process",
value = "process_Cont_Curr"
),
tabPanel(
"Design",
value = "req_Cont_Curr"
),
tabPanel(
"Risk Analysis",
value = "risk_Cont_Curr",
),
tabPanel(
"Guardbanding",
value = "gb_Cont_Curr"
),
tabPanel(
"Sampling",
value = "sample_Cont_Curr"
),
tabPanel(
"Decon",
value = "decon_Cont_Curr"
)
)
)
}
ContCurrentSideBarPanelServer <- function(id,appTabs,Maincount){
moduleServer(
id,
function(input,output,session){
observe({
output$result <- renderText({
paste0("Here I am ", 63)
})
})
observe({
if (appTabs == "cont_Data" ) {
showElement(id = "goButton")
hideElement(id = "goButton3")
}
})
x <- 93
return(x)
}
)
}
VRATui <- shinyUI(
### Start Navbar Page
navbarPage(
title = "Test Tool",
selected = "Introduction",
fluid=TRUE,
### Start App Tab panel
tabsetPanel(id = "appTabs",
type = "pills",
### Start the tab panel for the Data Screen
tabPanel(
value = "cont_Data",
title = "Continuous Data",
### Start the Continuous sidebar layout
sidebarLayout(
### Start the Continuous sidebar panel
sidebarPanel(
id = "cndsp",
width = 3,
style = "overflow-y:scroll; max-height: 80vh",
h4("Analysis of Current Data"),
hr(style="border-color: darkblue;"),
conditionalPanel(
condition = "input.appTabs == 'cont_Data' && input.Maincont == 'currentCont'",
### Submit setup for analysis
actionButton(inputId = "goButton", label = "Start Current Analysis", width = '100%'),
actionButton(inputId = "goButton3", label = "Update Current Analysis", width = '100%'),
### Sidebar Panel Tabs
ContCurrentSideBarPanelUI("ContCurrentSideBarPanel")
),
### End Continuous Data Analysis sidebar panel
),
mainPanel()
### End the sidebar layout
),
### End the Data tab panel
)
)
### End the app tabPanelSet
)
### End the navbarPage
)
VRATserver <- shinyServer(function(input, output, session) {
test <- ContCurrentSideBarPanelServer(id = "ContCurrentSideBarPanel",
reactive(input$appTabs),
Maincount = reactive(input$Maincount))
})
shinyApp(
ui = VRATui,
server = VRATserver
)
It turned out to be easy. I was not passing the outer parameter as reactive correctly. It should be reactive({...}) not reactive(...). Once corrected, then the module responded to appTabs() correctly and the if statement completed without error. When this worked, the text was correctly entered into the sidebar tab.
Related
I created an actionButton RUN demo data as a demonstration of an app and I am wondering how to reset it all so that the user can start his input for user's data sets. I looked around the reset button but still can't get it through.
rm(list=ls())
library(tidyverse)
library(shiny)
# Define UI ----
ui <- fluidPage(
tabsetPanel(
#tabPanel-Input
tabPanel("Input", fluid = TRUE,
# tab title ----
titlePanel("Upload data"),
# sidebar layout with input and output tables ----
sidebarLayout(
# sidebar panel for inputs ----
sidebarPanel(
#show ct demo
actionButton("runexample", "RUN demo data"),
# input1: Select a file ----
fileInput("file1", "Count matrix File (.xlsx)",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
#input2: select a file ----
fileInput("file2", "Manifest File (.xlsx)",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
#select column name
selectInput("design", "Column name for analysis", " "),
#select ref group
uiOutput("level0"),
#select study group
uiOutput("level1"),
#action run
actionButton("runbutton", "Run"),
#comment message
p("Click to perform differential gene expression analysis between the selected groups"),
#README link
uiOutput("README"),
#issue report
uiOutput("issue")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("matrix"),
tableOutput("pdat")
)
)
),
#tabPanel-Results
tabPanel("Results", fluid = TRUE,
# App title ----
titlePanel("Download results"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("results", "Choose a dataset:",
choices = c("Results", "Normalized matrix")),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
),
#tabPanel-Plots
tabPanel("Plots", fluid = TRUE,
fluidRow(
column(width = 8,
plotOutput("plot1", height = 800,
# Equivalent to: click = clickOpts(id = "plot_click")
click = "plot1_click",
brush = brushOpts(
id = "plot1_brush"
)
)
),
column(width = 4,
h4("Brushed points"),
verbatimTextOutput("brush_info")
)
)
)
)
)
# Define Server ----
server <- function(input, output, session) {
#tabPanel-Input
###demo data
####count
set.seed(123)
ctdemo<- t(rmultinom(1000, size = 50, prob = c(rep(0.4, 4), rep(0.6, 4))))
####manifest
pdemo<-data.frame(Samples=paste0("Sample", 1:8),
Treatment=rep(c("DrugA", "DrugB"), each=4))
###display demo count matrix
observeEvent(input$runexample, {
output$matrix <- renderTable({
head(ctdemo, 10)
})
output$pdat <- renderTable({
head(pdemo, 10)
})
observe({
updateSelectInput(session, "design", choices="Treatment")
})
output$level0 <- renderUI({
selectInput("ref0", "Reference group", "DrugA")
})
output$level1 <- renderUI({
selectInput("ref1", "Study group", "DrugB")
})
})
}
shinyApp(ui, server)
Actually you've made most of the job (I don't copy-paste the full code, it is quite long and the solution is short).
First, create the button "Reset" in the ui part with actionButton("reset", "Reset"), (I placed it just after the button runexample).
Then, put almost of the code of the server part in an observeEvent that is triggered with reset (place this chunk of code at the end of the server part):
observeEvent(input$reset, {
output$matrix <- renderTable(NULL)
output$pdat <- renderTable(NULL)
observe({
updateSelectInput(session, "design")
})
output$level0 <- renderUI(NULL)
output$level1 <- renderUI(NULL)
})
That's it !
This is a reproducible example. I'm trying to understand using the conditionalpanel function under shiny.
How do I tweak the code in a manner such that when I check both checkboxes, the plot and image will be rendered together? (with the plot on the top and image at the bottom on main panel)
library(shiny)
ui = fluidPage(
titlePanel("Plot or Example?"),
sidebarLayout(
sidebarPanel(
checkboxGroupInput("my_choices", "Example or Plot",choices = c("Plot", "Example"), selected = 1),width=2),
mainPanel(
conditionalPanel(
condition = "input.my_choices == 'Plot'",
plotOutput('my_test1')
),
conditionalPanel(
condition = "input.my_choices == 'Example'",
uiOutput("my_test2")
)
)
)
)
server = function(input, output) {
output$my_test1 <- renderPlot({plot(runif(100))})
output$my_test2 <- renderUI({
images <- c("http://www.i2symbol.com/images/abc-123/o/white_smiling_face_u263A_icon_256x256.png")
tags$img(src= images)
})
}
There are several things to do.
First, your selected argument of checkboxGroupInput should match one of the choices. Here I changed it to "Plot".
Second, I used "input.my_choices.includes('Example') && input.my_choices.includes('Plot')" as the condition when both are selected.
Third, Shiny doesn't allow the same output to be used more than once. To get around that, I made duplicates of the outputs in the server code, and referenced the duplicated names in the conditional Panel for the condition both boxes are checked.
library(shiny)
ui = fluidPage(
titlePanel("Plot or Example?"),
sidebarLayout(
sidebarPanel(
checkboxGroupInput("my_choices", "Example or Plot",choices = c("Plot", "Example"), selected = "Plot"),width=2),
mainPanel(
conditionalPanel(
condition = "input.my_choices == 'Plot'",
plotOutput("my_test1")
),
conditionalPanel(
condition = "input.my_choices == 'Example'",
uiOutput("my_test2")
),
conditionalPanel(
condition = "input.my_choices.includes('Example') && input.my_choices.includes('Plot')",
plotOutput("my_test1a"),
uiOutput("my_test2a")
)
)
)
)
server = function(input, output) {
output$my_test1 <- output$my_test1a <- renderPlot({plot(runif(100))})
output$my_test2 <- output$my_test2a <- renderUI({
images <- c("http://www.i2symbol.com/images/abc-123/o/white_smiling_face_u263A_icon_256x256.png")
tags$img(src= images)
})
}
shinyApp(ui, server)
This is my first Shiny App, as part of my Coursera Data Science Specialisation. I am trying to create a Tab for documentation but the output of the main tab displays in both, the MainApp tab and the Documentation.
I want no output in the "Documentation" tab
Any help? Thanks!
This is the ui.R code:
shinyUI(
pageWithSidebar(
headerPanel (" Six Sigma Control Charts"),
tabsetPanel(
tabPanel("MainApp",
sidebarPanel(
h5 ("Control Charts are six sigma tools that track process statistics over time to detect the presence of special causes of variation. There are different types of charts according to the data type that you are analysing."),
selectInput("DataType", "Please select Data Type",
choices = c("Continuous", "Attribute")),
conditionalPanel(condition = "input.DataType == 'Continuous'",
selectInput("Groups", "Data collected in groups?",
choices = c("Yes", "No"))),
conditionalPanel(condition = "input.DataType == 'Attribute'",
selectInput("Counting", "What are you counting?",
choices = c("Defective items", "Defects per unit"))),
conditionalPanel(condition = "input.Groups == 'Yes' & input.DataType == 'Continuous' ",
textInput ("SubgroupSize", "Enter sub group size",1 ) )
) ),
tabPanel("Documentation",
h5 ("This Shiny App helps you to familiarise with Six Sigma Control Charts."),
h5 ("The different types of graphs are produced according to the type of data that you want to analyse"),
h5 ("Make a choice according to the data type to explore the various Six Sigma graphs")
)
),
mainPanel (
plotOutput ("ControlChart"),
textOutput("Explanation"),
br(100),
br()
)
)
)
It is not possible with the pageWithSidebar function. This function is deprecated anyway. Try to wrap a fluidPage in a navbarPage:
# Define UI
ui <- navbarPage("App Title",
tabPanel("Plot",
fluidPage(
sidebarLayout(
# Sidebar with a slider input
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 0,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
),
tabPanel("Summary",
tags$br("Some text"))
)
# Server logic
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$obs))
})
}
# Complete app with UI and server components
shinyApp(ui, server)
I need my Shiny module to hide/show a div outside of the namespace. I tried passing the div id to the module server function and using shinyjs to show/hide it but that is not working. I'm not getting an error, it just doesn't show/hide the div.
I know the Shiny module documentation says modules cannot access outputs outside the namespace. The docs do, though, give a way for the module to access inputs outside the namespace using reactives.
Does anyone know if there is a way for a Shiny module to access an output outside the namespace?
Here is what I'm trying to do:
### ui.R ###
header <- dashboardHeader(
title = a(href = 'http://google.com')
)
dashboardPage(
skin = 'black',
header,
dashboardSidebar(
sidebarMenu( id='tabs',
menuItem('Edit Existing Client', tabName = 'client-info')
)),
dashboardBody(
useShinyjs(),
fluidRow(
tabItems(
tabItem(tabName = "client-info",
div(selectClientModuleUI("clientinfons")),
div(id='editclientinfo', uiOutput('editclientstuff'))
)
)
)
)
)
### server.R ###
shinyServer(function(session,input, output) {
output$editclientstuff <- renderUI({
div(
fluidRow(
column(6,
textInput('editname', "Display name", value ='Testing name')
),
column(6,
numericInput('editastart','Start', value ='3')
)
)
)
})
callModule(selectClientModule, 'clientinfons', 'editclientinfo')
shinyjs::hide(id='editclientstuff')
})
### in global.R ###
selectClientModuleUI <- function(id){
ns <- NS(id)
clientlist = c(0, 1, 2)
names(clientlist) = c('Choose client', 'Fred', 'Kim')
div(
selectInput(ns('selectclient'), 'Select client to edit', choices = clientlist, selected = NULL, multiple = FALSE)
)
}
selectClientModule <- function(input, output, session, divtoshow = ''){
observeEvent(input$selectclient, {
if (!is.null(input$selectclient) && input$selectclient > 0){
print(paste0("showing ", divtoshow))
shinyjs::show(divtoshow)
}
})
}
That is possible by giving the value as a reactive (not as the value of the reactive) to the module. You can change the reactive Value in the module and return the reactive from the Module to the app (note, return the reactive itself, not its value). The following app switches the 'divtoshow' in the main app from inside the module. If nothing is selected, it's hidden, otherwise it's shown (note, I adjusted you code a little so it's working as a stand-alone app):
library(shinydashboard)
library(shinyjs)
# Module
selectClientModuleUI <- function(id){
ns <- NS(id)
clientlist = c(0, 1, 2)
names(clientlist) = c('Choose client', 'Fred', 'Kim')
div(
selectInput(ns('selectclient'), 'Select client to edit', choices = clientlist, selected = NULL, multiple = FALSE)
)
}
selectClientModule <- function(input, output, session, divtoshow){
observeEvent(input$selectclient, {
if (input$selectclient > 0){
print(paste0("showing editclientinfo"))
divtoshow("editclientinfo") # set the div to show to "editclientinfo", this will be visible outside the module
}else{
divtoshow("") # set the div to show to "", if nothing was chosen
}
})
# return the div to show as reactive to the main app
return(divtoshow)
}
# Main App
ui <- shinyUI(
dashboardPage(
skin = 'black',
dashboardHeader(
title = a(href = 'http://google.com')
),
dashboardSidebar(
sidebarMenu( id='tabs',
menuItem('Edit Existing Client', tabName = 'client-info')
)),
dashboardBody(
useShinyjs(),
fluidRow(
tabItems(
tabItem(tabName = "client-info",
div(selectClientModuleUI("clientinfons")),
div(id='editclientinfo', uiOutput('editclientstuff'))
)
)
)
)
))
server <- shinyServer(function(session,input, output) {
output$editclientstuff <- renderUI({
div(
fluidRow(
column(6,
textInput('editname', "Display name", value ='Testing name')
),
column(6,
numericInput('editastart','Start', value ='3')
)
)
)
})
# store the div to show in a reactive
divtoshow <- reactiveVal('')
# divtoshow can be changed in side this module, so it's a return value
divtoshow <- callModule(selectClientModule, 'clientinfons', divtoshow)
# observe the value of divtoshow and toggle the corresponding div
observeEvent(divtoshow(), {
if(divtoshow() == "editclientinfo"){
shinyjs::show("editclientinfo")
}else{
shinyjs::hide("editclientinfo")
}
})
})
shinyApp(ui, server)
I am having a following problem:
I want a sidebar change when I switch between tabItem(s).
dashboardPage(
dasboardHeader(title = ""),
dashboardSidebar(
sidebarMenu(
menuItem("1", tabName = "1"),
menuItem("2", tabName = "2")
),
#I want this to be displayed when menuItem "1" is clicked
tabsetPanel(
tabPanel("t1", val="t1",
.... some inputs),
tabPanel("t2", val="t2",
.... some inputs)
),
# This to be displayed when menuItem "2" is clicked
selectInput("s1", label="Select"....),
selectInput("s2", label="Select2"...)
)
dashboardBody(
tabItem(tabName="1",
.......
),
tabItem(tabName="2",
........
)
)
)
I have the dashboardBody changing when switching between the tabs but don't know how to change the dashboardSidebar values. Tried this inside the dashboardSidebar:
conditionalPanel(
condition="tabName='1'",
#displaying first version of DashboardSidebar
),
conditionalPanel(
condition="tabName='2'",
#displaying second version of DashboardSidebar
)
But it didn't work for me.
Any ideas?
Thank you for your help.
First of all, you have to add sidebarMenu an ID which will be used for a Shiny input value, and it will report which tab is selected.
After that, add uiOutput to dashboardSidebar function.
uiOutput is going to receive, depending on a selected tab, either tabsetPanel or two selectInputs.
Finally, within renderUI, which you define on the server side, you just need to create conditional statements. That's the easy part.
The tricky part is that you have to wrap selectInputs into a list - otherwise only the second widget would be sent to the UI. Even more tricky part is that you have to specify the ID of tabsetPanel when you want to send it to the UI via renderUI. (That's very tricky because normally you don't have to specify its ID!)
Full example:
library(shiny)
library(shinydashboard)
rm(ui)
rm(server)
ui <- dashboardPage(
dashboardHeader(title = ""),
dashboardSidebar(
# added ID which will be used for a Shiny input value,
# and it will report which tab is selected.
sidebarMenu(id = "tab",
menuItem("1", tabName = "1"),
menuItem("2", tabName = "2")
),
uiOutput("out1")
),
dashboardBody(
tabItem(tabName = "1"),
tabItem(tabName = "2")
)
)
server <- function(input, output) {
output$out1 <- renderUI({
if (input$tab == "1") {
dyn_ui <- tabsetPanel(id = "tabset_id", selected = "t1",
tabPanel("t1", value = "t1"),
tabPanel("t2", value = "t2"))
}
if (input$tab == "2") {
dyn_ui <- list(selectInput("s1", label = "Select", choices = letters[1:3]),
selectInput("s2", label = "Select2", choices = letters[4:6]))
}
return(dyn_ui)
})
}
shinyApp(ui, server)