Shiny - Editing rhandsontable tables with multiple input and output elements - r

I've been working with this post as a starting point.
Update handsontable by editing table and/or eventReactive
Very helpful, but I'm trying to extend it to specify the number of values in the table, then update a plot based on the table values after editing.
Here's what I have so far.
library(shiny)
library(rhandsontable)
library(colorSpec)
ui <- fluidPage(
numericInput("x", "number of values", 2),
rHandsontableOutput('table'),
textOutput('result'),
plotOutput('plot'),
actionButton("recalc", "generate new random vals and calculate")
)
server <- function(input,output,session)({
values <- reactiveValues(data=as.data.frame(runif(input$x)))
observe({
input$recalc
values$data <- as.data.frame(runif(input$x))
})
observe({
if(!is.null(input$table))
values$data <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
rhandsontable(values$data)
})
output$result <- renderText({
sum(values$data)
})
output$plot <- reactivePlot({
barplot(values$data)
})
})
shinyApp(ui = ui, server = server)
I get an error on the reactiveValues line because I'm trying to use input$x. The previous post had a hard coded value of 2.

I think you were almost there. You can, however, not use an input for creating a reactive value. But this is anyways not eneded and you can initiate it with a NULL.
library(shiny)
library(rhandsontable)
ui <- fluidPage(
numericInput("x", "number of values", 2),
rHandsontableOutput('table'),
textOutput('result'),
plotOutput('plot'),
actionButton("recalc", "generate new random vals and calculate")
)
server <- function(input,output,session)({
values <- reactiveValues(data = NULL) ## assign it with NULL
## button press resets now the data frame
observeEvent(input$recalc, {
values$data$x <- 0
})
## changes in numericInput sets all (!) new values
observe({
req(input$x)
values$data <- data.frame(x = runif(input$x))
})
observe({
if(!is.null(input$table))
values$data <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
req(values$data)
rhandsontable(values$data)
})
output$result <- renderText({
req(values$data)
sum(values$data)
})
output$plot <- renderPlot({
req(values$data)
barplot(values$data$x)
})
})
shinyApp(ui = ui, server = server)

You can use reactive() instead of reactiveValues to do this:
library(shiny)
library(rhandsontable)
library(colorSpec)
ui <- fluidPage(
numericInput("x", "number of values", 2),
rHandsontableOutput('table'),
textOutput('result')
)
server <- function(input,output,session)({
values <- reactive({
foo <- as.data.frame(runif(input$x))
colnames(foo) <- c("Col1")
return(foo)
})
output$table <- renderRHandsontable({
rhandsontable(values())
})
output$result <- renderText({
sum(values())
})
})
shinyApp(ui = ui, server = server)

Related

updating table in Shiny

I've got a table that will initialize, but will not update. I use a few inputs, which then get called by a function to calculate the outputs. They will initialize with the correct values, but when I click the actionButton, nothing happens.
output$view<-renderTable({
tabSvol<-isolate(
data.frame(
S=c(
func1(input$in1),
func2(input$in2),
func3(input$in1,input$2)
)
)
)
tabSvol
})
Here's a MRE that allows you to add rows to a reactive table.
library(shiny)
library(tidyverse)
ui <- fluidPage(
numericInput("a", "A: ", value=NA),
selectInput("b", "B:", choices=c("X", "Y", "Z")),
actionButton("add", "Add row"),
tableOutput("table")
)
server <- function(input, output) {
rv <- reactiveValues(table=tibble(A=numeric(0), B=character(0)))
output$table <- renderTable({
rv$table
})
observeEvent(input$add, {
rv$table <- rv$table %>% add_row(A=input$a, B=input$b)
})
}
shinyApp(ui = ui, server = server)

In R shiny, How to create action button to transpose matrix if the view want to switch it?

I created a matrix, and I want to input an action button to enable the user to control the view.
please use this dataset and here is the error message as after clicking "transpose" button nothing happens:
Here is the code
library(shiny)
library(DT)
ui <- basicPage(
h2("India cities"),
DT::dataTableOutput("mytable"),
actionButton("go", "Transpose"),
dataTableOutput("mytabletranspose")
)
server <- function(input, output,session)
{output$mytable = DT::renderDataTable({
indiacities
})
observeEvent(input$go, {
})
output$mytabletranspose<-renderDataTable({
t(mytable)
})
}
Unsure what is the expected output. One option is to have the transposed table show up when the button is clicked in a new data table. This is relatively straight forward.
If you want the transposed table to appear as a new data table,
library(shiny)
library(DT)
ui <- basicPage(
h2("India cities"),
DT::dataTableOutput("mytable"),
actionButton("go", "Transpose"),
dataTableOutput("mytabletranspose")
)
server <- function(input, output,session){
indiacities <- data.frame(city = c("Mumbai","Bangalore"),population = c(18,8.4),area_code = c("+91-22","+91-080"))
output$mytable <- DT::renderDataTable({
indiacities
})
output$mytabletranspose <- DT::renderDataTable({
req(input$go)
t(indiacities)
})
}
shinyApp(ui = ui,server = server)
If you want to transpose the same table we will need to edit the original table indiacities. Because observer and reactive execute functions in their own environment we need to use the global assignment operator <<-
library(shiny)
library(DT)
ui <- basicPage(
h2("India cities"),
DT::dataTableOutput("mytable"),
actionButton("go", "Transpose"),
)
server <- function(input, output,session){
indiacities <- data.frame(city = c("Mumbai","Bangalore"),population = c(18,8.4),area_code = c("+91-22","+91-080"))
data <- reactive({
if(length(input$go) == 0){
#Executed when the app is initializes
return(indiacities)
}else{
indiacities <<- t(indiacities)
}
})
output$mytable <- DT::renderDataTable({
req(data())
data()
})
}
shinyApp(ui = ui,server = server)

How to stop resetting a variable in R-Shiny?

I am working on an Interactive Shiny App. To display the next plot on a mouse click, I have to track the very previous value of a variable. But when I click on the plot All the variables reset. Can you please suggest me a way to stop a variable from resetting on every iteration.
For example:
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
actionButton("Reset", label="Reset Graph")
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server <- shinyServer(function(input, output, session) {
level <- "Value1"
observeEvent(input$Reset,{
output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
print(level)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
level <- "Value2"
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)
I have changed the level variable to "Value2". But on next iteration, it again turns to "Value1" due to the first line of code. Can you help me to remain it as "Value2"?
You can define it as a reactive value:
server <- shinyServer(function(input, output, session) {
level_init <- reactiveValues(level="Value1")
level_react <- reactive({
level_init$level <- "Value2"
})
print(isolate(level_init$level))
observeEvent(input$Reset,{
output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
level_react()
print(level_init$level)
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)

Get selected row value instead of number in shiny using DT

Small question here: I know I can access selected rows by input$dfname_rows_selected it gives back the numbers of rows selected, but how do I read the rows names, not numbers? In my case they are generated not in the order I use them later, therefore I need to get the values inside to make it work.
edit: added example
ui <- shinyUI(fluidPage(
DT::dataTableOutput("table"),
actionButton("btn", "press me")
))
server <- function(input, output) {
observeEvent(input$btn, {
print(input$table_rows_selected)
})
output$table <- DT::renderDataTable({
mtcars %>%
datatable(selection = "multiple")
})
}
shinyApp(ui = ui, server = server)
Something like this:
library(shiny)
library(DT)
ui <- basicPage(
mainPanel(DT::dataTableOutput('mytable')),
textOutput("selected")
)
server <- function(input, output,session) {
mydata <- reactive({mtcars})
output$mytable = DT::renderDataTable(
datatable(mydata())
)
selectedRow <- eventReactive(input$mytable_rows_selected,{
row.names(mtcars)[c(input$mytable_rows_selected)]
})
output$selected <- renderText({
selectedRow()
})
}
runApp(list(ui = ui, server = server))
I don't think you can. What you could do is write a reactive, where all modifications to your dataframe take place, before creating the datatable. An example:
library(shiny)
library(DT)
ui <- shinyUI(fluidPage(
DT::dataTableOutput("table"),
textOutput("selectedcar")
)
)
server <- function(input, output,session) {
# the reactive where we filter/sort/modify the data
reactive_df <- reactive({
mtcars[order(mtcars$cyl),]
})
# This datatable uses the reactive directly, so no more modifications
output$table <- DT::renderDataTable({
DT::datatable(reactive_df())
})
# now we can get the row/rowname as follows:
output$selectedcar <- renderText({
paste0(rownames(reactive_df())[input$table_rows_selected], collapse = ", ")
})
}
shinyApp(ui, server)
Hope this helps!

Storing reactive data in shiny from SQL

This is a follow up from this question:
Acessing SQL database using shiny with reactive query
I am trying to build a data frame from data fetched from an SQL database using a shiny app. Currently i am able to query the database and return one set of data. Now I would like to save that data to a data frame and then add more data from subsequent queries. Here is my code:
UI
library(markdown)
shinyUI(fluidPage(
titlePanel("Generic grapher"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Select wafer ID:"), value = NULL),
actionButton("do", "An action button")
),
mainPanel(
verbatimTextOutput("value"), verbatimTextOutput("que"), dataTableOutput(outputId="pos")
)
)
)
)
Server:
library(RMySQL)
library(DBI)
library(sqldf)
con = dbConnect(RMySQL::MySQL(), dbname="xx", username="pete", password="xx", host="xx", port=3306)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
shinyServer(function(input, output){
d <- eventReactive(input$do, { input$wafer })
output$value <- renderPrint({ d() })
a <- reactive({ paste("Select id from wafer where wafer_id=",d(), sep="") })
output$que <- renderPrint({ a() })
wq <- reactive({ query( a() ) })
output$pos <- renderDataTable({ wq() })
})
Now I am trying to use the information from these two answers to store the data from each search I do in a data frame:
Add values to a reactive table in shiny
What's the difference between Reactive Value and Reactive Expression?
New Server:
library(RMySQL)
library(DBI)
library(sqldf)
con = dbConnect(RMySQL::MySQL(), dbname="xx", username="pete", password="xx", host="xx", port=3306)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
shinyServer(function(input, output){
values <- reactiveValues()
values$df <- data.frame()
d <- eventReactive(input$do, { input$wafer })
output$value <- renderPrint({ d() })
a <- reactive({ paste("Select id from wafer where wafer_id=",d(), sep="") })
output$que <- renderPrint({ a() })
wq <- reactive({ query( a() ) })
values$df <- reactive({ rbind(values$df, wq() ) })
output$pos <- renderDataTable({ values$df })
})
However, when I do this the data table never renders within my app. I dont have an error message. Any ideas where Im going wrong? Any help appreciated!
I think changing
values$df <- reactive({ rbind(values$df, wq() ) })
in your new server.R to
observe({
values$df <- rbind(isolate(values$df), wq())
})
might fix your problem.
EDIT: Here's a working example using a local connection:
library(markdown)
library(RMySQL)
library(DBI)
library(sqldf)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "mtcars", mtcars)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
ui <- shinyUI(fluidPage(
titlePanel("Generic grapher"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Select number of cylinders:"),
value = NULL),
actionButton("do", "An action button")
),
mainPanel(
verbatimTextOutput("value"),
verbatimTextOutput("que"),
verbatimTextOutput("wq_print"),
dataTableOutput(outputId="pos")
)
)
)
)
server <- shinyServer(function(input, output){
values <- reactiveValues()
values$df <- data.frame()
d <- eventReactive(input$do, { input$wafer })
output$value <- renderPrint({ d() })
a <- reactive({ paste("SELECT * FROM mtcars WHERE cyl = ", d(), sep="") })
output$que <- renderPrint({ a() })
observe({
if (!is.null(d())) {
wq <- reactive({ query( a() ) })
output$wq_print <- renderPrint({ print(str(wq())) })
values$df <- rbind(isolate(values$df), wq())
}
})
output$pos <- renderDataTable({ values$df })
})
shinyApp(ui, server)
The relevant changes to your original code are the !is.null(d()) condition for handling the initial NULL value of d(), and using values$df <- rbind(isolate(values$df), wq()) inside an observer. Hope this helps with fixing your code!

Resources