How to share dataframes from an observeEvent module to another - r

I need to share more than one dataframe within an observeEvent block with other observeEvent blocks. The reason is because the data is built only after a button is pressed.
I found the following two questions very resourceful, but not quite close to the structure of my app ...
How to return a variable from a module to the server in an R Shiny app?
How to access dataframe from another observeEvent?
I tried to wrap the button observeEvent within a module, but then the app does not work. I cannot figure out how to change my code into modules to make it work.
Here is a minimal example.
library(shiny)
library(shinydashboard)
library(DT)
header1 <- dashboardHeader(
title = "My App"
)
sidebar1 <- dashboardSidebar(
sidebarMenu(id = "sbmenu",
menuItemOutput("menuitems01"),
menuItemOutput("menuitems02")
) #sidebarMenu
) #dashboardSidebar
body1 <- dashboardBody(
tabItems(
uiOutput("tabitems01")
) #tabItems
) #dashboardBody
ui <- dashboardPage(header1, sidebar1, body1)
server <- function(input, output, session) {
# render menu
output$menuitems01 <- renderMenu({
menuItem("Main", tabName = "main", icon = icon("key"))
})
# render tabitems
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
observeEvent(input$btn1, {
dfresult02 <- data.frame(c(1, 2), c(3, 4)) # e.g. read some data from db
dfresult05 <- data.frame(c(5, 6), c(7, 8)) # e.g. read some data from db
rResult02 <- reactive({dfresult02}) # NEED TO MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
rResult05 <- reactive({dfresult05}) # NEED TO MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
output$menuitems02 <- renderMenu({
menuItem("MyData", tabName = "mydata", icon = icon("th"))
}) #renderMenu
updateTabItems(session, "sbmenu", "mydata")
print("button1 pressed")
}) #observeEvent(input$btn1)
observeEvent(input$sbmenu, {
# IF I UNCOMMENT THE NEXT FOUR LINES, THE TABLES ARE DISPLAYED
#dfresult02 <- data.frame(c(1, 2), c(3, 4))
#rResult02 <- reactive({dfresult02})
#dfresult05 <- data.frame(c(1, 2), c(3, 4))
#rResult05 <- reactive({dfresult05})
if(input$sbmenu == "mydata")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "mydata",
h2("My Data"),
DT::dataTableOutput('tbl02'),
DT::dataTableOutput('tbl05')
) #tabItem
}) #renderUI
output$tbl02 <- DT::renderDataTable({rResult02()}) # NEED DATA FROM OTHER MODULE HERE
output$tbl05 <- DT::renderDataTable({rResult05()}) # NEED DATA FROM OTHER MODULE HERE
} #if(input$sbmenu == "mydata")
if(input$sbmenu == "main")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
} #if(input$sbmenu == "main")
}) #observeEvent(input$sbmenu)
} #server
shinyApp(ui = ui, server = server)

Using the very useful comment above, I ended up with this code, that works perfectly! Thank you so much!!! (note the use of reactiveValues)
library(shiny)
library(shinydashboard)
library(DT)
header1 <- dashboardHeader(
title = "My App"
)
sidebar1 <- dashboardSidebar(
sidebarMenu(id = "sbmenu",
menuItemOutput("menuitems01"),
menuItemOutput("menuitems02")
) #sidebarMenu
) #dashboardSidebar
body1 <- dashboardBody(
tabItems(
uiOutput("tabitems01")
) #tabItems
) #dashboardBody
ui <- dashboardPage(header1, sidebar1, body1)
server <- function(input, output, session) {
# DECLARE REACTIVEVALUES FUNCTION HERE
rResult <- reactiveValues(df02 = 0, df05 = 0)
# render menu
output$menuitems01 <- renderMenu({
menuItem("Main", tabName = "main", icon = icon("key"))
})
# render tabitems
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
observeEvent(input$btn1, {
dfresult02 <- data.frame(c(1, 2), c(3, 4)) # e.g. read some data from db
dfresult05 <- data.frame(c(5, 6), c(7, 8)) # e.g. read some data from db
rResult$df02 <- dfresult02 # MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
rResult$df05 <- dfresult05 # MAKE THIS DATA AVAILABLE TO OTHER MODULE(S)
output$menuitems02 <- renderMenu({
menuItem("MyData", tabName = "mydata", icon = icon("th"))
}) #renderMenu
updateTabItems(session, "sbmenu", "mydata")
print("button1 pressed")
}) #observeEvent(input$btn1)
observeEvent(input$sbmenu, {
if(input$sbmenu == "mydata")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "mydata",
h2("My Data"),
DT::dataTableOutput('tbl02'),
DT::dataTableOutput('tbl05')
) #tabItem
}) #renderUI
output$tbl02 <- DT::renderDataTable(rResult$df02) # GET DATA FROM OTHER MODULE(S) HERE
output$tbl05 <- DT::renderDataTable(rResult$df05) # GET DATA FROM OTHER MODULE(S) HERE
} #if(input$sbmenu == "mydata")
if(input$sbmenu == "main")
{
output$tabitems01 <- renderUI({
tabItem(tabName = "main",
h2("Main"),
actionButton(inputId = "btn1", label = "Button1")
) #tabItem
}) #renderUI
} #if(input$sbmenu == "main")
}) #observeEvent(input$sbmenu)
} #server
shinyApp(ui = ui, server = server)

Related

Shiny: Show Download Button Only If An Action Button Is Pressed

I have a reactive data frame df1(). A user can add their initials as text inputs such that the text is filled to rows as a new column name when the user clicks the Add button.
Everything works fine but I would like to add one more thing:
Make the download button download show only if the action button bttn1 is pressed. Currently download is shown regardless of pressing bttn1.
I can't understand why the following is not working:
observe({
if (is.null(input$bttn1)) {shinyjs::hide("download")}
else {shinyjs::show("download")}
})
The following is a fully working code:
##### ui
ui <- dashboardPage(
skin = "black",
#### Upper navigation bar
dashboardHeader(
title = "title",
titleWidth = 230
),
#### Side bar
dashboardSidebar(disable = T),
#### Body
dashboardBody(
shinyjs::useShinyjs(),
tabsetPanel(
tabPanel(
### tab1
tabName = "tab1",
h5("Tab 1"),
fluidRow(
reactableOutput("table1"),
textInput("textinput1", "Initials:"),
actionButton("bttn1", "Add", class = "btn-primary"),
reactableOutput("table2"),
uiOutput("ui_download")
) # fluidRow
), # tabPanel
#### tab2
tabPanel(
tabName = "tab2",
h5("Tab 2"),
fluidRow(
) # fluidRow
) # tabPanel
) # tabsetPanel
) # dashboardBody
) # dashboardPage
#### server
server <- function(input, output, session) {
## df1
# reactive
df1 <- reactive({
data.frame(
"id" = c("A", "A", "A", "A"),
"num1" = c(10, 11, 12, 13)
)
})
# renderReactable
output$table1 <- renderReactable({
reactable(df1(), borderless = F, defaultColDef = colDef(align = "center"))
})
## df2
## Text input
rv1 <- reactiveValues()
observe({
if (nrow(df1()) == 0) {shinyjs::hide("bttn1")}
else {shinyjs::show("bttn1")}
})
observe({
if (nrow(df1()) == 0) {shinyjs::hide("textinput1")}
else {shinyjs::show("textinput1")}
})
observeEvent(input$bttn1, {
rv1$values <- df1()
rv1$values$name <- input$textinput1
})
rv1_text <- reactive({
rv1$values
})
output$table2 <- renderReactable({
req(rv1_text())
reactable(rv1_text(), borderless = F, defaultColDef = colDef(align = "center"))
})
## downloadButton
# renderUI
output$ui_download <- renderUI({
# req(rv1_text())
downloadButton("download", "Download")
})
**# Why isn't this working?**
observe({
if (is.null(input$bttn1)) {shinyjs::hide("download")}
else {shinyjs::show("download")}
})
# Download csv
output$download <- downloadHandler(
filename = function() {
paste0('data', '.csv')
},
content = function(file) {
write.csv(rv1_text(), file, row.names = F)
}
)
}
shinyApp(ui, server)
I couldn't run your codes since you did not share the libraries you used in. But If I understand you correctly, conditionalPanel is very suitible for your purpose.
Here is a small shiny app that you can adapt it to your codes:
library(shiny)
ui <- fluidPage(
actionButton("call_download", "Show Download Button"),
conditionalPanel(condition = "input.call_download == 1",
downloadLink('downloadData', 'Download')
)
)
server <- function(input, output) {
output$downloadData <- downloadHandler(
filename = function() {
paste('data-', Sys.Date(), '.csv', sep='')
},
content = function(con) {
write.csv(mtcars, con)
} )
}
shinyApp(ui, server)

Modularize reactiveUI with interdependent filters in shiny with {golem}

The following shiny app works well but has a problem: it displays errors or warnings because of the dynamic filtering.
library(shiny)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
titlePanel(
div(style="line-height: 100%",
align = 'center',
span("Awesome reprex"),
hr()
)
),
sidebarMenu(
menuItem("Home", tabName = "Home", icon = icon("fas fa-home")),
menuItem("Main section", tabName = "Main", icon = icon("far fa-chart-bar"))
)
),
dashboardBody(
tabItems(tabItem(tabName = "Home"),
tabItem(tabName = "Main",
fluidRow(
),
fluidRow(),
hr(),
fluidRow(style = 'background: white;',
div(
box(
title= "Much filters",
style = 'height:420px; background: gainsboro; margin-top: 5vw;',
width=3,
solidHeader = TRUE,
uiOutput("continent"),
uiOutput("country")
),
tabBox(
width = 9,
title = "Results",
id = "tabset1",
tabPanel(style = 'overflow-y:scroll;height:420px;',"Awesome results !",
style="zoom: 90%;",
DT::dataTableOutput("awesometable")
)
)
)
)
)
)
)
)
library(data.table)
library(shiny)
library(gapminder
server <- function(input, output, session) {
df <- gapminder::gapminder
output$continent = renderUI({
selectizeInput(inputId = "continent",
label = "Continent :",
choices = unique(df[,"continent"]),
selected = unique(df[,"continent"])[1])
})
# #
datasub <- reactive({
df[df$continent == input$continent,]
})
output$country = renderUI({
selectizeInput(inputId = "country",
label = "Country :",
choices = unique(datasub()[,"country"])
)
})
#
datasub2 <- reactive({
datasub()[datasub()$country == input$country, ]
})
output$awesometable <- DT::renderDataTable({
datasub2()
})
}
shinyApp(ui, server)
First part of the problem:
Errors started displaying once I included a filtering method I found here:
https://stackoverflow.com/a/51153769/12131069
After trying different methods, this is the one that works pretty close to what I am looking for.
However, once the app is loaded, this appears in the console:
Logical subscripts must match the size of the indexed input.
Input has size 392 but subscript datasub2()$country== input$country has size 0.
Second part of the problem:
The app is being developed with the {golem} package, which is really helpful when building scalable and maintainable shiny infrastructure. However, I don't get what I am expecting (and I get the errors). How can I solve that? How can I "modularize" the workaround I found to create interdependent filters?
I have been trying something like:
#' awesome_app_ui UI Function
#'
#' #description A shiny Module.
#'
#' #param id,input,output,session Internal parameters for {shiny}.
#'
#' #noRd
#'
#' #import DT
#' #import plotly
#' #import htmltools
#' #import shinydashboard
#' #importFrom reactable JS
#' #importFrom shiny NS tagList
mod_chiffres_cles_ts_ui <- function(id){
ns <- NS(id)
df <- gapminder::gapminder
tabBox(width = 9,title = "Results",d = "tabset1",
tabPanel(style = 'overflow-y:scroll;height:420px;',"Awesome results !",
style="zoom: 90%;",DT::dataTableOutput("awesometable"))
}
#' awesome_app Server Functions
#'
#' #noRd
mod_chiffres_cles_ts_server <- function(id){
moduleServer( id, function(input, output, session){
ns <- session$ns
df <- gapminder::gapminder
output$continent = renderUI({
selectizeInput(inputId = "continent",
label = "Continent :",
choices = unique(df[,"continent"]),
selected = unique(df[,"continent"])[1])
})
# #
datasub <- reactive({
df[df$continent == input$continent,]
})
output$country = renderUI({
selectizeInput(inputId = "country",
label = "Country :",
choices = unique(datasub()[,"country"])
)
})
#
datasub2 <- reactive({
datasub()[datasub()$country == input$country, ]
})
output$awesometable <- DT::renderDataTable({
datasub2()
})
}
Thanks!
Once you use req() appropriately, your program works fine.
library(shiny)
library(data.table)
library(shiny)
library(gapminder)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
titlePanel(
div(style="line-height: 100%",
align = 'center',
span("Awesome reprex"),
hr()
)
),
sidebarMenu(
menuItem("Home", tabName = "Home", icon = icon("fas fa-home")),
menuItem("Main section", tabName = "Main", icon = icon("far fa-chart-bar"))
)
),
dashboardBody(
tabItems(tabItem(tabName = "Home"),
tabItem(tabName = "Main",
fluidRow(
),
fluidRow(),
hr(),
fluidRow(style = 'background: white;',
div(
box(
title= "Much filters",
style = 'height:420px; background: gainsboro; margin-top: 5vw;',
width=3,
solidHeader = TRUE,
uiOutput("continent"),
uiOutput("country")
),
tabBox(
width = 9,
title = "Results",
id = "tabset1",
tabPanel(style = 'overflow-y:scroll;height:420px;',"Awesome results !",
style="zoom: 90%;",
DT::dataTableOutput("awesometable")
)
)
)
)
)
)
)
)
server <- function(input, output, session) {
df <- gapminder::gapminder
output$continent = renderUI({
selectizeInput(inputId = "continent",
label = "Continent :",
choices = unique(df[,"continent"]),
selected = unique(df[,"continent"])[1])
})
datasub <- reactive({
req(input$continent)
df[df$continent == input$continent,]
})
output$country = renderUI({
req(datasub())
selectizeInput(inputId = "country",
label = "Country :",
choices = unique(datasub()[,"country"])
)
})
datasub2 <- reactive({
req(datasub(),input$country)
datasub()[datasub()$country == input$country, ]
})
output$awesometable <- DT::renderDataTable({
req(datasub2())
datasub2()
})
}
shinyApp(ui, server)
You can also use modules as shown below. You may need to adjust where you want to place your selectInputs.
library(shiny)
library(data.table)
library(shiny)
library(gapminder)
moduleServer <- function(id, module) {
callModule(module, id)
}
mod_chiffres_cles_ts_ui <- function(id){
ns <- NS(id)
tagList(
box(
title= "Filter",
style = 'height:420px; background: gainsboro; margin-top: 3vw;',
#width=3,
solidHeader = TRUE,
uiOutput(ns("mycontinent"))
)
)
}
mod_chiffres_cles_ts_server <- function(id,dat,var){
moduleServer( id, function(input, output, session){
ns <- session$ns
df <- isolate(dat())
output$mycontinent = renderUI({
selectizeInput(inputId = ns("continent"),
label = paste(var, ":"),
choices = unique(df[,var]),
selected = unique(df[,var])[1])
})
#print(var)
return(reactive(input$continent))
})
}
mod_chiffres_cles_ds_server <- function(id,dat,var,value){
moduleServer( id, function(input, output, session){
df <- isolate(dat())
datasub <- reactive({
val = as.character(value())
df[df[[as.name(var)]] == val,]
})
#print(var)
return(reactive(as.data.frame(datasub())))
})
}
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
titlePanel(
div(style="line-height: 100%",
align = 'center',
span("Awesome reprex"),
hr()
)
),
sidebarMenu(
menuItem("Home", tabName = "Home", icon = icon("fas fa-home")),
menuItem("Main section", tabName = "Main", icon = icon("far fa-chart-bar"))
)
),
dashboardBody(
tabItems(tabItem(tabName = "Home"),
tabItem(tabName = "Main",
fluidRow(
column(6,mod_chiffres_cles_ts_ui("gap1"),
mod_chiffres_cles_ts_ui("gap2")
),
column(6,style = 'background: white;',
div(
tabBox(
width = 12,
title = "Results",
id = "tabset1",
tabPanel(style = 'overflow-y:scroll;height:560px;',"Awesome results !",
style="zoom: 90%;",
DTOutput("awesometable")
)
)
)
)
)
)
)
)
)
server <- function(input, output, session) {
dfa <- reactive(gapminder)
session$userData$settings <- reactiveValues(df1=NULL,df2=NULL)
rv <- reactiveValues()
var1 <- mod_chiffres_cles_ts_server("gap1",dfa,"continent")
observeEvent(var1(), {
data1 <- mod_chiffres_cles_ds_server("gap1",dfa,"continent", var1 )
session$userData$settings$df1 <- data1()
var21 <- mod_chiffres_cles_ts_server("gap2",data1,"country")
df21 <- mod_chiffres_cles_ds_server("gap2",data1,"country", var21 )
session$userData$settings$df2 <- df21()
print(var21)
})
df22 <- reactive(session$userData$settings$df1)
var22 <- mod_chiffres_cles_ts_server("gap2",df22,"country")
observeEvent(var22(), {
print(var22())
data2 <- mod_chiffres_cles_ds_server("gap2",df22,"country",var22)
session$userData$settings$df2 <- data2()
})
output$awesometable <- renderDT({
datatable(session$userData$settings$df2)
})
}
shinyApp(ui, server)

How to create a button that will create a pdf file of a table

I currently have a table being generated and I would like the user to be able to create a pdf file when they click the download button.
I am currently getting an error where when I click the download button I get an html file that downloads the entire page of the app. I thought that using pdf(file) would work but it ignores the function.
Here is currently what I have.
library(shiny)
library(xlsx)
library(shinyWidgets)
population <- read.xlsx("population.xlsx", 1)
fieldsMandatory <- c("selectedCountry")
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
appCSS <-
".mandatory_star {color: red;}"
ui <- fluidPage(
navbarPage(title = span("Spatial Tracking of COVID-19 using Mathematical Models", style = "color:#000000; font-weight:bold; font-size:15pt"),
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
div(
id = "dashboard",
pickerInput(
inputId = "selectedCountry",
labelMandatory ("Country"),
choices = population$Country,
multiple = FALSE,
options = pickerOptions(
actionsBox = TRUE,
title = "Please select a country")
),
sliderInput(inputId = "agg",
label = "Aggregation Factor",
min = 0, max = 50, step = 5, value = 10),
actionButton("go","Run Simulation"),
)
),
mainPanel(
tabsetPanel(
tabPanel("Input Summary", verbatimTextOutput("summary"),
tableOutput("table"),
downloadButton(outputId = "downloadSummary", label = "Save Summary"))
)
)
)
)
)
)
server <- function(input, output, session){
observeEvent(input$resetAll, {
shinyjs::reset("dashboard")
})
values <- reactiveValues()
values$df <- data.frame(Variable = character(), Value = character())
observeEvent(input$go, {
row1 <- data.frame(Variable = "Country", Value = input$selectedCountry)
row2 <- data.frame(Variable = "Aggregation Factor", Value = input$agg)
values$df <- rbind(row1, row2)
})
output$table <- renderTable(values$df)
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "go", condition = mandatoryFilled)
})
output$downloadSummary <- downloadHandler(
filename = function(file) {
paste('my-report.pdf', )
},
content = function(file) {
pdf(file)
}
)
}
shinyApp(ui,server)
Here's a minimal example:
library(shiny)
ui <- fluidPage(
downloadButton("savepdf", "Save pdf")
)
server <- function(input, output, session) {
output$savepdf <- downloadHandler(
filename = "test.pdf",
content = function(file) {
pdf(file)
plot(iris$Sepal.Length, iris$Sepal.Width)
dev.off()
}
)
}
shinyApp(ui, server)
Also see here.
Here is a minimal example with the package latexpdf. It will create the pdf table in the folder of the app.
library(shiny)
library(latexpdf)
dat <- head(iris, 5)
ui <- fluidPage(
br(),
actionButton("dwnld", "Create pdf"),
tableOutput("mytable")
)
server <- function(input, output, session){
output[["mytable"]] <- renderTable({
dat
})
observeEvent(input[["dwnld"]], {
as.pdf(dat)
})
}
shinyApp(ui, server)

How to refresh a shiny datatable with a button that runs a function

I have looked everywhere and cant seem to find help with what must be a common issue.
I have a datatable in a shiny app. I load data into it when it first appears. It consists of one column of text
I want the user be able to press a button that takes the data in the datatable and performs an action on it and then presents a datatable with the result of that function. The function (not shown) basically splits the single column up into several columns.
I cant seem to figure out how to run a function from a button that refreshes and shows the new datatable.
This is what I have so far:
server.R
library(shiny)
library(EndoMineR)
RV <- reactiveValues(data = PathDataFrameFinalColon)
server <- function(input, output) {
output$mytable = DT::renderDT({
RV$data
})
output2$mytable = DT::renderDT({
RV$data<-myCustomFunction(RV$data)
})
}
ui.R
library(shiny)
basicPage(
fluidPage(
DT::dataTableOutput("mytable")
))
basically how do I allow a button on the page to run a specific function that then updates the datatable?
You can use observeEvent() and ignoreInit = TRUE so that the initial dataframe is rendered without the function being applied.
server <- function(input, output) {
RV <- reactiveValues(data = PathDataFrameFinalColon)
output$mytable = DT::renderDT({
RV$data
})
observeEvent(input$my_button,{
RV$data<-myCustomFunction(RV$data)
},ignoreInit = TRUE)
}
ui <- basicPage(
fluidPage(
DT::dataTableOutput("mytable"),
actionButton("my_button",label = "Run Function")
))
I hope this helps you. Have fun;
library(shiny)
library(shinydashboard)
dat = data.frame(id = c("d","a","c","b"), a = c(1,2,3,4), b = c(6,7,8,9))
header <- dashboardHeader(
)
sidebar <- dashboardSidebar(
tags$head(tags$style(HTML('.content-wrapper { height: 1500px !important;}'))),
sidebarMenu (
menuItem("A", tabName = "d1"),
menuItem("B", tabName = "d2"),
menuItem("C", tabName = "d3")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "d1",
box(title = "AAA",
actionButton("refreshTab1_id", "Refresh Tab 1"),
actionButton("sortTable1_id", "Sort Table 1"),
DT::dataTableOutput("table_for_tab_1", width = "100%"))
),
tabItem(tabName = "d2",
box(title = "BBB",
actionButton("refreshTab2_id", "Refresh Tab 2"),
actionButton("sortTable2_id", "Sort Table 2"),
DT::dataTableOutput("table_for_tab_2", width = "100%"))
),
tabItem(tabName = "d3",
box(title = "CCC",
actionButton("refreshTab3_id", "Refresh Tab 3"),
actionButton("sortTable3_id", "Sort Table 3"),
DT::dataTableOutput("table_for_tab_3", width = "100%"))
)
)
)
# UI
ui <- dashboardPage(header, sidebar, body)
# Server
server <- function(input, output, session) {
observe({
if (input$sortTable1_id || input$sortTable2_id || input$sortTable3_id) {
dat_1 = dat %>% dplyr::arrange(id)
} else {
dat_1 = dat
}
output$table_for_tab_1 <- output$table_for_tab_2 <- output$table_for_tab_3 <- DT::renderDataTable({
DT::datatable(dat_1,
filter = 'bottom',
selection = "single",
colnames = c("Id", "A", "B"),
options = list(pageLength = 10,
autoWidth = TRUE#,
# columnDefs = list(list(targets = 9,
# visible = FALSE))
)
)
})
})
observe({
if (input$refreshTab1_id || input$refreshTab2_id || input$refreshTab3_id) {
session$reload()
}
})
}
# Shiny dashboard
shiny::shinyApp(ui, server)

How can i get a fixed plotOutput in Shiny

I am developing a Shiny app with a plot (plot1 in the code) that is reactive to a data table (rhandsontable) and it displays the item selected on the table.
The table is very large so you have to scroll down to see everything. But I want the plot to be always visible, so to be fixed in the layout while you scroll down the table.
There is anyway to do it? I have done a lot of research but any answer that can help me.
My UI code is that:
ui <- dashboardPage(
dashboardHeader(title = "IG Suppliers: Tim"),
dashboardSidebar(
sidebarMenu(
menuItem("Data Cleansing", tabName = "DataCleansing", icon = icon("dashboard")),
selectInput("supplier","Supplier:", choices = unique(dt_revision_tool$Supplier)),
#selectInput("supplier","Supplier:", choices = 'Phillips'),
selectInput("segment","Segment:", choices = unique(dt_revision_tool$Segment_Name), multiple = TRUE, selected = unique(dt_revision_tool$Segment_Name)[1]),
#selectInput("segment","Segment:", choices = sgm),
selectInput("alert","Alert", choices = unique(dt_revision_tool$Alert),selected = "Yes"),
#selectInput("alert","Alert", choices = c('Yes','No'),selected = "Yes"),
selectInput("dfu","DFU", choices = c("NULL",unique(dt_revision_tool$DFU)),selected = "NULL"),
tags$hr()
# h5("Save table",align="center"),
#
# div(class="col-sm-6",style="display:inline-block",
# actionButton("save", "Save"),style="float:center")
)
),
dashboardBody(
shinyjs::useShinyjs(),
#First Tab
tabItems(
tabItem(tabName= "DataCleansing",
fluidPage(theme="bootstrap.css",
fluidRow(
plotOutput('plot1')
),
fluidRow(
verbatimTextOutput('selected'),
rHandsontableOutput("hot")
)
)
)
# #Second Tab
# tabItem(tabName = "Forecast",
# h2('TBA')
# )
)
)
)
The server code is that:
server <- shinyServer(function(input, output) {
if (file.exists("DF.RData")==TRUE){
load("DF.RData")
}else{
load("DF1.RData")
}
rv <- reactiveValues(x=dt_revision_tool)
dt <- reactiveValues(y = DF)
observe({
output$hot <- renderRHandsontable({
view = data.table(update_view(rv$x,input$alert,input$segment,input$supplier,dt$y,input$dfu))
if (nrow(view)>0){
rhandsontable(view,
readOnly = FALSE, selectCallback = TRUE, contextMenu = FALSE) %>%
hot_col(c(1:12,14),type="autocomplete", readOnly = TRUE)
}
})
})
observe({
if (!is.null(input$hot)) {
aux = hot_to_r(input$hot)
aux = subset(aux, !is.na(Cleansing_Suggestion) | Accept_Cleansing,select=c('DFU','Week','Cleansing_Suggestion',
'Accept_Cleansing'))
names(aux) = c('DFU','Week','Cleansing_Suggestion_new','Accept_Cleansing_new')
dt$y = update_validations(dt$y,aux)
DF = dt$y
save(DF, file = 'DF.RData')
}
})
output$plot1 <- renderPlot({
view = data.table(update_view(rv$x,input$alert,input$segment,input$supplier,dt$y,input$dfu))
if (nrow(view)>0){
if (!is.null(( data.table(update_view(rv$x,input$alert,input$segment,input$supplier,dt$y,input$dfu)))[input$hot_select$select$r]$DFU)) {
s = make_plot2(rv$x,(data.table(update_view(rv$x,input$alert,input$segment,input$supplier,dt$y,input$dfu)))[input$hot_select$select$r]$DFU,(data.table(update_view(rv$x,input$alert,input$segment,input$supplier,dt$y,input$dfu)))[input$hot_select$select$r]$Article_Name)
print(s)
}
}
})
})
Any help or idea will be welcome!
Thanks!
Aida
Here is an example of using CSS position: fixed to do this. You can adjust the position top and margin-top according to your requirement.
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
tags$div(p("Example of fixed plot position"))
),
mainPanel(
plotOutput("plot"),
tableOutput("table"),
tags$head(tags$style(HTML("
#plot {
position: fixed;
top: 0px;
}
#table {
margin-top: 400px;
}
")))
)
)
))
server <- shinyServer(function(input, output, session) {
output$plot <- renderPlot({
plot(iris$Sepal.Length, iris$Sepal.Width)
})
output$table <- renderTable({
iris
})
})
shinyApp(ui = ui, server = server)

Resources