As the title says, I'm trying to get Shiny to display a SelectBox so I can dynamically select records from a SQL Server Table, and based on the selection of the CATEGORY, display everything in the table. The script below must be close. I am getting the SelectBox to work, but when I make a selection, nothing is displayed.
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data")
# plotOutput("plot_data")
)
),
server = shinyServer(function(input, output, session){
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <-
reactive({
req(input$showDrop)
ch <- odbcDriverConnect('driver={SQL Server};server=MyServer;database=Northwind;trusted_connection=true')
showList <- sqlExecute(ch,
"SELECT * FROM [NORTHWND].[dbo].[Customers] WHERE [CUSTOMERID] = ?",
data = list(AnalyteId = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <-
renderUI({
ch <- odbcDriverConnect('driver={SQL Server};server=MyServer;database=Northwind;trusted_connection=true')
showList <- sqlExecute(ch,
"SELECT DISTINCT AnalyteId From [NORTHWND].[dbo].[Customers] ORDER BY [CUSTOMERID]",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$AnalyteId)
})
# Display the data in a table
output$display_data <-
renderTable({
QueriedData()
})
# Display a plot
# output$plot_data <-
# renderPlot({
# plot(QueriedData()) # fill in the plot code you want to use.
# })
})
)
How can I get this working? Also, can you make the table dynamically selectable, or is that not an option?
It seems like you're missing some components. Some notes:
Your UI definition is invalid. Each argument to the UI should produce some kind of UI element. The lines where you define your connection and export the data from SQL Server will won't behave the way you are expecting them to here. You should either do these actions on the server, or you should define them globally.
You are retrieving data into your output$cumReturn slot, but you are using a renderPlot call to do it. This is somewhat disjoint. If you wish to render a plot, you should generate a plot. If you wish to show data, you should use renderTable (or something similar).
You also haven't displayed the cumReturn output slot anywhere in the UI, so the query is never actually being called.
Lastly, your query in output$cumReturn will fail when it goes to the server. I am guessing you mean to use input$showDrop in a WHERE statement, but your query has no such statement. This is not casting an error in the code above because you never try to render the cumReturn output, so the query is never being called.
Here's a variation on your code that should produce a table of data that fall within the category.
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data"),
plotOutput("plot_data")
)
),
server = shinyServer(function(input, output, session){
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <-
reactive({
req(input$showDrop)
ch <- odbcDriverConnect('...')
showList <- sqlExecute(ch,
"SELECT * FROM dbo.Analyte WHERE AnalyteId = ?",
data = list(AnalyteId = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <-
renderUI({
ch <- odbcDriverConnect('...')
showList <- sqlExecute(ch,
"SELECT DISTINCT AnalyteId FROM dbo.Analyte ORDER BY AnalyteId",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$AnalyteId)
})
# Display the data in a table
output$display_data <-
renderTable({
QueriedData()
})
# Display a plot
output$plot_data <-
renderPlot({
plot(QueriedData()) # fill in the plot code you want to use.
})
})
)
library(shiny)
library(RODBCext)
shinyApp(
ui =
shinyUI(
fluidPage(
uiOutput("select_category"),
tableOutput("display_data")
# plotOutput("plot_data")
)
),
# server needs the function; looks ok
server = shinyServer(function(input, output, session)
{
# A reactive object to get the query. This lets you use
# the data in multiple locations (plots, tables, etc) without
# having to perform the query in each output slot.
QueriedData <- reactive({
req(input$showDrop)
ch <- odbcDriverConnect("driver={SQL Server};server=SERVER;database=DB;trusted_connection=true")
showList <- sqlExecute(ch, "SELECT * FROM [DB].[dbo].[TABLE] WHERE Category = ?",
data = list(Category = input$showDrop),
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
showList
})
# The select input control. These can be managed dynamically
# from the server, and then the control send back to the UI
# using `renderUI`
output$select_category <- renderUI({
ch <- odbcDriverConnect("driver={SQL Server};server=SERVER;database=DB;trusted_connection=true")
showList <- sqlExecute(ch, "Select Distinct Category From [DB].[dbo].[TABLE] Order by Category",
fetch = TRUE,
stringsAsFactors = FALSE)
odbcClose(ch)
selectInput(inputId = "showDrop",
label = "Select Asset",
showList$Category)
})
# Display the data in a table
output$display_data <- renderTable({
QueriedData()
})
# Display a plot
# output$plot_data <-
# renderPlot({
# plot(QueriedData()) # fill in the plot code you want to use.
# })
})
)
Related
I am relatively new to R and currently, I am trying to build a simple Shiny app.
I believe that the input is good, however, my output does not seem to work properly.
My app should allow users to select the number of ingredients they want to use and the output should give all the names of the recipes with that specific number of ingredients.
How can I connect the input to the desired output?
ui <- fluidPage(
titlePanel("Foodify"),
#Input
selectInput("number_of_ingredients", "How many ingredients would you like to use?",
choices = c(dt.ingredients.and.directions.recipe$dt.number.of.ingredients), selected = 5, selectize = TRUE),
mainPanel(textOutput("ingredients")
))
server <- function(input, output){
ingredients.data <- reactive({as.data.frame(dt.ingredients.and.directions.recipe)})
recipes <- reactive(ingredients.data()[which(row.names(ingredients.data()) == input$number_of_ingredients),])
output$ingredients <- renderPrint({ingredients.data()$Recipe_name})
}
shinyApp(ui = ui, server = server)
I think you could simplify your app.
You had your recipe data as reactive - does it need to be? If you have your data already present in a data frame, you can filter that in either a separate reactive block or in your output.
Here is a brief example that simplifies things (filtering your data frame in the output). If your input changes (different number of recipes) the text output will automatically update.
Will this meet your needs?
dt.ingredients.and.directions.recipe <- data.frame(
dt.number.of.ingredients = c(1,2,3),
Recipe_name = c("First", "Second", "Third"),
stringsAsFactors = F
)
ui <- fluidPage(
titlePanel("Foodify"),
#Input
selectInput("number_of_ingredients", "How many ingredients would you like to use?",
choices = unique(dt.ingredients.and.directions.recipe$dt.number.of.ingredients),
selected = 1,
selectize = TRUE),
mainPanel(textOutput("ingredients")
)
)
server <- function(input, output){
output$ingredients <- renderPrint({
dt.ingredients.and.directions.recipe[dt.ingredients.and.directions.recipe$dt.number.of.ingredients == input$number_of_ingredients, "Recipe_name"]
})
}
shinyApp(ui = ui, server = server)
If you want to use a separate reactive block to filter you can also do the following:
server <- function(input, output){
recipes <- reactive({
dt.ingredients.and.directions.recipe[dt.ingredients.and.directions.recipe$dt.number.of.ingredients == input$number_of_ingredients,]
})
output$ingredients <- renderPrint({
recipes()$Recipe_name
})
}
Edit (3/1/20):
There is flexibility in how your recipe results can appear. Right now, this was using renderPrint which just captures any print output and converts it to a string.
There are a number of alternative ways to show your data. One way is to use renderTable instead (and in your ui replace with tableOutput instead of textOutput. Also would take a look at the DT package in shiny.
This will display the recipe results in a single column:
library(shiny)
dt.ingredients.and.directions.recipe <- data.frame(
dt.number.of.ingredients = c(7,2,7,8,6),
Recipe_name = c("Jam Toaster Tarts", "Oven-Dried Strawberries", "Fried Whole Fish", "Veggie Italian Hoagies", "Buttered Tomatoes with Ginger"),
stringsAsFactors = F
)
ui <- fluidPage(
titlePanel("Foodify"),
#Input
selectInput("number_of_ingredients", "How many ingredients would you like to use?",
choices = sort(unique(dt.ingredients.and.directions.recipe$dt.number.of.ingredients)),
selected = 1,
selectize = TRUE),
mainPanel(tableOutput("ingredients")
)
)
server <- function(input, output){
output$ingredients <- renderTable({
data.frame(Recipe = dt.ingredients.and.directions.recipe[dt.ingredients.and.directions.recipe$dt.number.of.ingredients == input$number_of_ingredients, "Recipe_name"])
})
}
shinyApp(ui = ui, server = server)
library(shiny)
library(mongolite)
ui <- fluidPage(
titlePanel("Mongodb Data"),
sidebarLayout(
sidebarPanel(
textInput("_id", "Document type:", "")
),
mainPanel(
dataTableOutput("mydata")
)
)
)
server <- function(input, output) {
mon <- mongo(collection = "collectionname", db = "db name", url = "mongodb://localhost:27017")
output$mydata <- renderDataTable({
doc_type <- paste0(doc_type= input$doc_id)
mon$find( query = '{"doc_type" : {"$in" : ["x", "y"]} }' , limit = 100)
})
}
}
Warning: The Error, 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.)
How to add a reactive query and retrieve data from a particular column from MongoDB collection? whenever I give text input value x or y it should show relevant documents from MongoDB database.
You need a query that changes according to user input. Try changing your server code to this. I'm considering there's a typo in your question and your actual input is this textInput("doc_id", "Document type:", "")
Server:
mon <- mongo(collection = "collectionname", db = "db name", url = "mongodb://localhost:27017")
# Create a reactive element. Changes when the user input changes
data.for.table <- reactive({
# Build a query that concatenates value of input$doc_id to other strings
query.foo <- paste0('{"doc_type" : {"', input$doc_id, '" : ["x", "y"]} }' )
# Retrieve data
mon$find(query = query.foo, limit = 100)
})
output$mydata <- renderDataTable({
data.for.table()
})
I am trying to dynamically populate the values of the selectInput from the data file uploaded by the user. The selectInput must contain only numeric columns.
Here is my code snippet for server.R
...
idx <- sapply(data.file, is.numeric)
numeric_columns <- data.file[, idx]
factor_columns <- data.file[, !idx]
updateSelectInput(session, "bar_x", "Select1", choices = names(numeric_columns))
updateSelectInput(session, "bar_y", "Select2", choices = names(factor_columns))
...
Corresponding ui.r
...
selectInput("bar_x", "Select1", choices = NULL),
selectInput("bar_y", "Select2", choices = NULL)
...
The code works fine as long as there are more than one values in any dropdown. However, it fails as soon as it encounters only one value to be displayed in the selectInput.
How can I handle this specific condition, given that the data is uploaded and it cannot be controlled if there is just one column as numeric?
It appears that in 2019, this issue still exists. The issue that I have seen is that when there is only one option in the dropdown, the name of the column is displayed instead of the one option.
This appears to only be a graphical problem, as querying the value for the selectInput element returns the correct underlying data.
I was unable to figure out why this problem exists, but an easy way around this bug is to simply change the name of the column so that it looks like the first element in the list.
library(shiny)
ui <- fluidPage(
selectInput("siExample",
label = "Example Choices",
choices = list("Loading...")),
)
server <- function(input, output, session) {
# load some choices into a single column data frame
sampleSet <- data.frame(Example = c("test value"))
# rename the set if there is only one value
if (length(sampleSet$Example) == 1) {
# This should only be done on a copy of your original data,
# you don't want to accidentally mutate your original data set
names(sampleSet) <- c(sampleSet$Example[1])
}
# populate the dropdown with the sampleSet
updateSelectInput(session,
"siExample",
choices = sampleSet)
}
shinyApp(ui = ui, server = server)
Info: Code was adapted by OP to make error reproducible.
To solve your issue use val2 <- val[,idx, drop = FALSE]
You dropped the column names by subsetting the data.frame().
To avoid this use drop = FALSE; see Keep column name when select one column from a data frame/matrix in R.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
# drj's changes START block 1
#selectInput('states', 'Select states', choices = c(1,2,4))
selectInput('states', 'Select states', choices = NULL)
# drj's changes END block 1
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
observe({
#drj's changes START block 2
#val <- c(1,2,3)
#names(val) <- c("a","b","c")
#updateSelectInput(session, 'states', 'Select states', choices = names(val[1]))
val <- as.data.frame(cbind(c("_1","_2","_3"), c(4, 4, 6)))
names(val) <- c("a","b")
val$b <- as.numeric(val$b)
idx <- sapply(val, is.numeric)
val2 <- val[,idx, drop = FALSE]
updateSelectInput(session, 'states', 'Select states', choices = names(val2))
#drj's changes END block 2
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm building a shiny app that queries an SQL database so the user can ggplot the data. I would like the user to be able to rename factors manually but am struggling to get going. Here is an example of what I want to do:
ui.R
library(markdown)
shinyUI(fluidPage(
titlePanel("Reactive factor label"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Input wafer ID:"), value = NULL),
actionButton("do", "Search wafer"),
textInput("text", label = h3("Factor name to change"), value = ""),
textInput("text", label = h3("New factor name"), value = ""),
actionButton("do2", "Change name")
),
mainPanel(
verbatimTextOutput("waf"),
verbatimTextOutput("que"),
verbatimTextOutput("pos"),
dataTableOutput(outputId="tstat")
)
)
)
)
server.R
# Create example data
Name <- factor(c("Happy", "New", "Year"))
Id <- 1:3
dd <- data.frame(Id, Name)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "dd", dd)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
sq = data.frame()
shinyServer(function(input, output){
# create data frame to store reactive data set from query
values <- reactiveValues()
values$df <- data.frame()
# Wait for user to search
d <- eventReactive(input$do, { input$wafer })
# Reactive SQL query
a <- reactive({ paste0("Select * from dd where Id=",d()) })
wq <- reactive({ query( a() ) })
# Check outputs
output$waf <- renderPrint(input$wafer)
output$que <- renderPrint({ a() })
output$pos <- renderPrint( wq()[1,1] )
# observe d() so that data is not added until user presses action button
observe({
if (!is.null(d())) {
sq <- reactive({ query( a() ) })
# add query to reactive data frame
values$df <- rbind(isolate(values$df), sq())
}
})
output$tstat <- renderDataTable({
data <- values$df
})
})
In static R I would normally use data table to rename factors i.e.:
DT <- data.table(df)
DT[Name=="Happy", Name:="Sad"]
But I'm not sure how to go about this with a reactiveValues i.e. values$df.
I have read this (R shiny: How to get an reactive data frame updated each time pressing an actionButton without creating a new reactive data frame?). This lead me to try this but it doesn't do anything (even no error):
observeEvent(input$do2, {
DT <- data.table(values$df)
DT[Name == input$text1, Name := input$text2]
values$df <- data.frame(values$df)
})
Perhaps there is a way around this..maybe there is a way to use an action button to "lock in" the data as a new data frame, which can then be used to rename?
Sorry for such a long winded question. My real app is much longer and more complex. I have tried to strip it down.
Your approach works but there are a few issues in your app.
In ui.R, both textInput have the same id, they need to be different so you can refer to them in the server.R. In the observeEvent you posted, you refer to input$text1 and input$text2 so you should change the id of the textInputs to text1 and text2.
In the observeEvent you posted, the last line should be values$df <- as.data.frame(DT), otherwise it does not change anything.
Using R shiny, I am developing a simple app that allows user to input data from a Rdata file. I want the app to load the data, show the names of numeric variables in a select input field, and after the user selected one of variables do some analysis. But I can not get it working. In the code provided I obtain two outputs: summary, which works fine, and the MEAN of the selected variable which I can not get work.
server.R
library(shiny)
library(shinydashboard)
library(data.table)
library(DT)
shinyServer(function(input, output) {
#### DATA LOAD
df <- reactive({
df <- input$datafile
if (is.null(df)) {
# User has not uploaded a file yet
return(NULL)
}
objectsLoaded <- load(input$datafile$name)
# the above returns a char vector with names of objects loaded
df <- eval(parse(text=objectsLoaded[1]))
# the above finds the first object and returns it
df<-data.table(df)
})
#### SELECTS
num <- reactive({
num <- sapply(df(),is.numeric)
num <- names(num)
})
output$var_num <- renderUI({
vector.num <- as.vector(num())
selectInput("var_num", "Select Variables :", as.list(vector.num), multiple = FALSE)
})
#### OUTPUTS
### SUMMARY
output$summary_num <-renderDataTable({
x<-t(sapply(df(), summary))
x<-as.data.frame(x)
x<-setDT(x, keep.rownames = TRUE)[]
colnames(x) <- c("Variable","Mínimo","1er Quartil", "Mediana", "Media", "3er Quartil","Máximo")
datatable(x)
})
### MEAN OF SELECTED VAR
output$test <-renderPrint ({
if(is.null(df()))
return()
dat<- df()
dat <- dat[,num(), drop = FALSE]
mean(dat[,input$var_num])
})
})
UI.R
dashboardPage(
dashboardHeader(title = "TITLE", titleWidth = 500),
dashboardSidebar(disable = TRUE), #---> fin SIDEBAR
dashboardBody(
fluidRow(
box(width=12, status = "primary",
tabsetPanel(
tabPanel("Test",
fileInput("datafile", label = h3("File input")),
uiOutput("var_num"),
br(),hr(),br(),
fluidRow(column(width=4, uiOutput("var_caracter"),textOutput("test"))),
br(),hr(),br(),
fluidRow(column(width=8, "Variables Numericas", dataTableOutput("summary_num")))
)
) # fin tabsetPanel
) # fin box
)# fin fluidRow
)# fin dashboardBody
)# fin dashboardPage
When I run the app everything goes fine (select input, summary, etc) except the calculation and printing of the MEAN of the selected variable. I guess for some reason the subsetted dataframe is empty, but I do not know why...
Any help will be great! Thanks in advance.
I get it working.
The solution was to define the dataset I used as.data.frame:
### MEAN OF SELECTED VAR
output$test <-renderPrint ({
if(is.null(df()))
return()
dat<- as.data.frame(df()) ## THIS IS THE CORRECTION
dat <- dat[,num(), drop = FALSE]
mean(dat[,input$var_num])
})
I do not really understand why... The reactive file df() was defined as data.table and dat shoul inherit that, but for some reason it was necesary an explicit definition as dataframe.