The code below is adapted from https://gist.github.com/wch/4211337 and perfectly illustrates my challenges. I have two main issues:
I cannot get the interactive tables to download; and
I can't figure out how to make the table print with a page length, for example that shows 25 rows and lets you toggle to the next page.
Here is the code:
server.r
data_sets <- c("mtcars", "morley", "rock")
shinyServer(function(input, output) {
# Drop-down selection box for which data set
output$choose_dataset <- renderUI({
selectInput("dataset", "Data set", as.list(data_sets))
})
# Check boxes
output$choose_columns <- renderUI({
# If missing input, return to avoid error later in function
if(is.null(input$dataset))
return()
# Get the data set with the appropriate name
dat <- get(input$dataset)
colnames <- names(dat)
# Create the checkboxes and select them all by default
checkboxGroupInput("columns", "Choose columns",
choices = colnames,
selected = colnames)
})
# Output the data
output$data_table <- renderTable({
# If missing input, return to avoid error later in function
if(is.null(input$dataset))
return()
# Get the data set
dat <- get(input$dataset)
# Make sure columns are correct for data set (when data set changes, the
# columns will initially be for the previous data set)
if (is.null(input$columns) || !(input$columns %in% names(dat)))
return()
# Keep the selected columns
dat <- dat[, input$columns, drop = FALSE]
# Return
dat
})
output$downloadData <- downloadHandler(
filename = function() {
('test.csv')
},
content = function(con) {
write.table(dat, row.names = FALSE, col.names=T, sep=",",con)
},
contentType="csv"
)
})
ui.r
shinyUI(pageWithSidebar(
headerPanel(""),
sidebarPanel(
uiOutput("choose_dataset"),
uiOutput("choose_columns"),
downloadButton("downloadData", style = "color: white;background-color: #303030")
),
mainPanel(
tableOutput("data_table")
)
))
I am getting an error code in the downloadHandler that says it doesn't recognize dat. I have tried wrapping the elements in reactive({}), but that didn't work either.
I have tried several things to get the table to show with a page length, but nothing I am doing is working, so I don't have any code for that presented here.
Thanks for any help!
Just do the data wrangling outside. Try this
server <- shinyServer(function(input, output) {
# Drop-down selection box for which data set
output$choose_dataset <- renderUI({
selectInput("dataset", "Data set", as.list(data_sets))
})
# Check boxes
output$choose_columns <- renderUI({
# If missing input, return to avoid error later in function
if(is.null(input$dataset))
return()
# Get the data set with the appropriate name
dat <- get(input$dataset)
colnames <- names(dat)
# Create the checkboxes and select them all by default
checkboxGroupInput("columns", "Choose columns",
choices = colnames,
selected = colnames)
})
dat <- reactive({
# If missing input, return to avoid error later in function
if(is.null(input$dataset))
return()
# Get the data set
dat <- get(input$dataset)
# Make sure columns are correct for data set (when data set changes, the
# columns will initially be for the previous data set)
if (is.null(input$columns) || !(input$columns %in% names(dat)))
return()
# Keep the selected columns
dat <- dat[, input$columns, drop = FALSE]
# Return
dat
})
# Output the data
output$data_table <- renderTable({
dat()
})
output$downloadData <- downloadHandler(
filename = function() {
('test.csv')
},
content = function(con) {
write.table(dat(), row.names = FALSE, col.names=T, sep=",",con)
},
contentType="csv"
)
})
Related
I am trying to take the speed variable from the "car" data set which I am uploading to the application. Basically Under select speed: I would like to have all the numbers appearing in the dataset$speed. Under selecInput, the choices should depend upond the data set I am uploading using fileInput. How can I complete this task. For now I have added the choices as 1,2,3. In theory there should be all values of the speed variable of cars data set.
library(shiny)
library(datasets)
##the file I am uploading
data(cars)
dataset=write.csv(cars, "dataset.csv")
ui=fluidPage(
actionButton("upload", "Upload File"),
bsModal("uploadFile", " ", "upload",
sidebarLayout(
sidebarPanel(
fileInput("file","Choose file to upload")
),
mainPanel(
tableOutput("contents")
)
)
),
sidebarLayout(
sidebarPanel(
column(3, selectInput("selectElement", "Select speed:", c(1,2,3),multiple =
T, selectize = F)
)
),
mainPanel(
)
)
)
server=function(input,output,session){
output$contents <- renderTable({
inFile <- input$file
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath)
})
}
shinyApp(ui,server)
My apologies in advance for a somewhat incomplete response: see below.
First of all, an answer to your query:
If you have a dataset like cars, to identify the "speed" labels you can do:
labls <- unique(cars$speed)
...
selectInput("selectElement", "Select speed:", labls, multiple =
T, selectize = F)
I was hoping to post a complete example, but the current logic (maybe because of the limited code posted?) does not seems right: how can the app a) leave to the user to select which file to use; and at the same time b) already filter for speed?
Of course it is possible that you plan to display datasets that have all a column called "speed", then it would make sense :)
Additionally, but this was not part of your question, you appear to use modal dialogues through the package shinyBS.
Since version 0.14 of shiny (around October 2016) shiny has a very good modal function and personally I think it would be better to use the native function instead.
I thougth to post a simple example derived from your code (but with the selectInput for speed commented out because, as mentioned, it does not appear right in the context of the example posted).
library(shiny)
library(datasets)
data(cars)
dataset = write.csv(cars, "dataset.csv")
labls <- unique(cars$speed) # I left this in the code
ui=fluidPage(
sidebarLayout(
sidebarPanel(
actionButton("upload", "Upload File")
),
mainPanel(tableOutput("contents") )
))
server=function(input,output,session){
# Show modal when button is clicked.
observeEvent(input$upload, {
showModal(dataModal())
})
dataModal <- function(failed = FALSE) {
modalDialog(
fileInput('inputId', label=NULL, multiple = FALSE, accept = NULL, width = NULL, buttonLabel = "Browse...", placeholder = "No file selected")
# , selectInput("selectElement", "Select speed:", labls, multiple =
# T, selectize = F)
)
}
output$contents <- renderTable({
if (length(input$inputId )== 0) return(NULL)
inFile <- input$inputId
# if (is.null(input$selectElement )) return(NULL)
input$inputId
})
}
shinyApp(ui,server)
Here is an existing example
library(shiny)
runExample("06_tabsets")
And you will see you can choose distribution type in radiobutton and there are three tabs "Plot", "Summary", and "Table".
My question is how can I add a selectInput under the sliderInput(number of observations) with two values. The default one is "NULL", the second one is "1". Once users select "1", the previous three tabs would disappear. Instead, a new tab would show whatever it content is.
This is the modified "06_tabsets". A select input is added and the UI is generated depending of the selection. The only difference is that is not using NULL, but two options. I could make it run with NULL. Let me know if this helps.
ui.R
library(shiny)
# Define UI for random distribution application
shinyUI(fluidPage(
# Application title
titlePanel("Tabsets"),
# Sidebar with controls to select the random distribution type
# and number of observations to generate. Note the use of the
# br() element to introduce extra vertical spacing
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000),
selectInput("contentSelect", "Select content to dislay:", choices = c("1", "2"), selected = 1)
),
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
uiOutput("content")
)
)
))
server.R
library(shiny)
# Define server logic for random distribution application
shinyServer(function(input, output) {
# Reactive expression to generate the requested distribution.
# This is called whenever the inputs change. The output
# functions defined below then all use the value computed from
# this expression
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(data(),
main=paste('r', dist, '(', n, ')', sep=''))
})
# Generate a summary of the data
output$summary <- renderPrint({
summary(data())
})
# Generate an HTML table view of the data
output$table <- renderTable({
data.frame(x=data())
})
output$textA <- renderText({
paste(input$contentSelect, " A")
})
observeEvent(input$contentSelect, {
if (input$contentSelect == "1") {
output$content <- renderUI({
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
})
} else {
output$content <- renderUI({
tabsetPanel(type = "tabs",
tabPanel("A", textOutput("textA"))
)
})
}
})
})
How can I get the list of choices in a SelectInpute?
ui.R
selectInput(inputId = "select_gender",
label = "Gender",
choices = c("Male","Female"),
width = 150
)
server.R
# Something like...
genders <- input$select_gender["choices"]
# So that the gender would be:
> genders
[1] Male Female
From the scoping rules of Shiny:
Objects defined in global.R are similar to those defined in app.R outside of the server function definition, with one important difference: they are also visible to the code in the ui object. This is because they are loaded into the global environment of the R session; all R code in a Shiny app is run in the global environment or a child of it.
However, this doesn't mean that objects defined in the app.R can't be used on both the UI and Server side, they just belong to a different environment.
For example:
library("shiny")
library("pryr")
# or in global.R
genders <- c("Male", "Female")
gen_env <- where("genders")
par_env <- parent.env(gen_env)
ui <- fluidPage(
selectInput("shiny_gender", "Select Gender", choices = genders),
verbatimTextOutput("selected_gender_index"),
p("The `genders` object belongs to the environment:"),
verbatimTextOutput("gen_env_print"),
p("Which is the child of the environment:"),
verbatimTextOutput("par_env_print")
)
server <- function(input, output) {
output$selected_gender_index <- renderPrint({
# use the 'genders' vector on the server side as well
which(genders %in% input$shiny_gender)
})
output$gen_env_print <- renderPrint(gen_env)
output$par_env_print <- renderPrint(par_env)
}
shinyApp(ui = ui, server = server)
I've looked for get choices of selectinput but without recompute the choices. For example if the datas come from database, or file or other source.
And I didn't get answer. (I get this question but not the solution for me).
Here is ma solution which also could set the selectinput from the server:
set the choices list in a reactive function
build the selectinput in the server side (with the choices list reactive function)
set and get the selectinput in the server side
Here is the code
options(encoding = "UTF-8")
library("shiny")
library("pryr")
ui <- fluidPage(
uiOutput("shiny_gender.UI"),
verbatimTextOutput("selected_gender_index"),
p("The `genders` object belongs to the environment:"),
verbatimTextOutput("gen_env_print"),
p("Which is the child of the environment:"),
verbatimTextOutput("par_env_print"),
p(""),
textInput("set_input_txt","Set the car in letter (for example `Datsun 710`)",
#" Set the Select Input Male / Female ",
""),
actionButton("submit","submit")
)
server <- function(input, output, session) {
observeEvent(
c(input$submit),
{
if (input$submit>0) {
updateSelectInput(session, "shiny_gender",
# server = TRUE, if updateSelectizeInput
choices =shiny_gender.list(),
selected = input$set_input_txt
)
}
}
)
shiny_gender.list <- reactive ({
#c("Male", "Female")
rownames(mtcars)
})
output$shiny_gender.UI <- renderUI({
selectInput( "shiny_gender",
label="Select car",#"Select Gender",
choices =shiny_gender.list()
)
})
output$selected_gender_index <- renderPrint({
which(shiny_gender.list() %in% input$shiny_gender)
})
output$gen_env_print <- renderPrint(where("shiny_gender.list"))
output$par_env_print <- renderPrint(parent.env( where("shiny_gender.list")))
}
shinyApp(ui = ui, server = server)
I want to provide inputselect "choices" in dependency of uploaded files (fileInput). In the example below I want as.list(mydata[1, 1:5]) as values for inputselect choices. Later on the subsetting values will be dynamic and is not showed here.
I tried several approaches suggested in the forum (reactive, observe, reactiveValue and their combination) without much success.
My script runs partially, however I need a page refresh to the get the "choices" uploaded and reload the file again.
server.R
shinyServer(function(input, output, session) {
output$contents <- renderDataTable({
inFile <<- input$SoftRecom
if (is.null(inFile))
return(NULL)
filedatapath <<- reactive({inFile$datapath})
mydata <<- read.csv(filedatapath(), header = TRUE, sep = ',')
mydata
})
mychoices <<- reactive({
mydata
print(mydata)
})
output$vg <- renderUI({
selectInput("vg", label = p("goal", style = "color:#FFA500"),
mychoices()[1,1:5], selected = 1)
})
output$vp <- renderUI({
selectInput("procedure", label = p("procedure", style = "color:#FFA500"),
choices = c("proecudures"), selected = 1)
})
output$vm <- renderUI({
selectInput("procedure", label = p("procedure", style = "color:#FFA500"),
choices = c("ChIP-seq"), selected = 1)
})
})
ui.R
shinyUI(fluidPage(theme = "bootstrap.css",
titlePanel("simple software recommendation sytem"),
sidebarLayout(
sidebarPanel(
fileInput('SoftRecom', 'choose dataset'),
uiOutput("vg"), # variable goal
uiOutput("vp"), # variable procedure
uiOutput("vm") # variable method
),
mainPanel(
dataTableOutput('contents')
)
)
))
I have seen many examples and answers in the forum, that are very close (or even match) my question. Sorry for being so obtuse. If someone could point me to the problem, I would be very thankful.
Jay
Eventually I found the solution by myself. Don't get confused by the different server code in my question and the answer. Just look at the relationship between
uiOutput('pipelinestep') and
output$pconst <<- renderUI({selectizeInput(
'pconst', 'construct software workflow', choices = as.character(mysoft[mysoft$goal==mypipefilter, 3]),
multiple = TRUE, options = list(maxItems = 1))}
UI.R
I had to insert: uiOutput("pipelinestep") see line 8
shinyUI(fluidPage(theme = "bootstrap.css",
titlePanel( h2("simple software recommendation system", style = "color:#FFA500")),
sidebarLayout(position = "left",
sidebarPanel(width =3,
# chose standard pipeline
selectInput("selectpipe", "select standard pipeline:", choices = pipechoices),
# software details
*uiOutput("pipelinestep")*, # software per pipeline step,
# construct software workflow based on selected pipeline step
uiOutput("pconst")
))))
server.R
see from line 5 to 7. "Choices" gets new values assigned as soon a change is detected. Please see documentation here: http://shiny.rstudio.com/articles/dynamic-ui.html
pipelinestepsoftInput <<- reactive({
mypipefilter <- input$pipelinestep
softperpipe <<- mysoft[mysoft$goal==mypipefilter ,c(1,3,5:7), drop = FALSE]
## provides software choices related to the pipeline step
output$pconst <<- renderUI({selectizeInput(
'pconst', 'construct software workflow', choices = as.character(mysoft[mysoft$goal==mypipefilter, 3]),
multiple = TRUE, options = list(maxItems = 1))})
## input for outputDataTable
softperpipe
})
I'm currently designing a Shiny app that outputs a table. I would like to highlight the cells in a particular column (e.g., make the cells blue). I've tried using the HighlightRows function from the shinyBS package, but that doesn't seem to work.
Here is a portion of my server script making up the table:
output$text1 <- renderTable({
tab1 <- as.data.frame(matrix(c(rrround(input$patha,3),PowerF()$tta,input$nxn,rrround(currentInput()$patha,3),rrround(rxyval()$rxy,3),rrround(rxyval()$rxy_p,3),rround(PowerF()$tra,3),
rrround(input$pathp,3),PowerF()$ttp,input$nxn,rrround(currentInput()$pathp,3),rrround(rxyval()$rxyp,3),rrround(rxyval()$rxyp_p,3),rround(PowerF()$trp,3))
,ncol=7, byrow=TRUE))
rownames(tab1) <- c('Actor', 'Partner')
colnames(tab1) <- c('Size', 'Power', 'N','Beta','r','partial r','ncp')
tab1.align = "r"
highlightRows(session, id='tab1', class = "info", column="Power", regex = ".")
print(tab1, type="html")
})
Any help would be greatly appreciated.
Thanks!
You can modify your datatable using tags$script. below is an example of highlighting 3 columns (1), (5) and (9) of a sample datatable. I had a small problem with a similar issue, you can view that How to change Datatable row background colour based on the condition in a column, Rshiny
rm(list = ls())
library(shiny)
options(digits.secs=3)
test_table <- cbind(rep(as.character(Sys.time()),10),rep('a',10),rep('b',10),rep('b',10),rep('c',10),rep('c',10),rep('d',10),rep('d',10),rep('e',10),rep('e',10))
colnames(test_table) <- c("Time","Test","T3","T4","T5","T6","T7","T8","T9","T10")
ui =navbarPage(inverse=TRUE,title = "Coloring datatables",
tabPanel("Logs",icon = icon("bell"),
mainPanel(htmlOutput("logs"))),
tabPanel("Extra 2",icon = icon("bell")),
tabPanel("Extra 3",icon = icon("bell")),
tags$style(type="text/css", "#logs td:nth-child(1) {text-align:center;background-color:red;color: white;text-align:center}"),
tags$style(type="text/css", "#logs td:nth-child(5) {text-align:center;background-color:blue;color: white;text-align:center}"),
tags$style(type="text/css", "#logs td:nth-child(9) {text-align:center;background-color:green;color: white;text-align:center}")
)
server <- (function(input, output, session) {
my_test_table <- reactive({
other_data <- rbind(c(as.character(Sys.time()),(sample(c("Pass","Aggr","Bad"))[1]),round(c(rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1)),2)),
(c(as.character(Sys.time()),(sample(c("Pass","Aggr","Bad"))[1]),round(c(rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1),rnorm(1)),2))))
test_table <<- rbind(apply(other_data, 2, rev),test_table)
as.data.frame(test_table)
})
output$logs <- renderTable({my_test_table()},include.rownames=FALSE)
})
runApp(list(ui = ui, server = server))