Reactive function to read rtf in rshiny - shiny

I am new to R and RShiny. Am building an application to compare two rtf files where a user can choose the two files dynamically. Is there a reactive function that I can use to read an rtf file before I pass it on to renderDiffr? Here is one version of the code I generated but the issue I am having is for these two rtf files I pick under folder1 and folder2 should be passed to renderDiffr below. I am sure there is a simple solution that I am yet to figure out. Would appreciate your help.
library(diffr)
library(shiny)
ui <- fluidPage(
# Main title of the page
titlePanel(HTML("<center>Comparison of two files</center>")),
# Browse buttons to select files
sidebarLayout(position="left",
sidebarPanel(
#fileInput("selectfolder1","Select file from folder 1"),
#fileInput("selectfolder2","Select file from folder 2"),
# Submit button to perform the compare
actionButton("goButton", "Compare", class = "btn-success")
),
mainPanel(
verbatimTextOutput("folder1"),
verbatimTextOutput("folder2"),
diffrOutput("value")
)))
shinyServer(
server <- function(input, output, session){
re1<-reactive({
file1<-file.choose()
})
output$folder1<-renderText({
re1()
})
re2<-reactive({
file2<-file.choose()
})
output$folder2<-renderText({
re2()
})
re3<-reactive({
input$goButton
x<-diffr(folder1,folder2, before="Folder 1",after="Folder 2")
})
output$value<-renderDiffr({
re3()
})
}
)
shinyApp(ui, server)

According to this documentation you pass the result of diffr() to diffrOutput().
What I changed:
When you use a reactive function make sure that you return the result at the end of it. I use return() for clarity (though it's not necessary).
In diffr(folder1,folder2, ...) I used diffr(re1(), re2(), ...) for obvious reasons.
I also skipped the re3 reactive In this sample and used diffr() directly in renderDiffr. But that is merely to reduce complexity.
library(diffr)
library(shiny)
ui <- fluidPage(
# Main title of the page
titlePanel(HTML("<center>Comparison of two files</center>")),
# Browse buttons to select files
sidebarLayout(position="left",
sidebarPanel(
#fileInput("selectfolder1","Select file from folder 1"),
#fileInput("selectfolder2","Select file from folder 2"),
# Submit button to perform the compare
actionButton("goButton", "Compare", class = "btn-success")
),
mainPanel(
verbatimTextOutput("folder1"),
verbatimTextOutput("folder2"),
diffrOutput("FileDiff", width="600px", height="auto")
)))
shinyServer(
server <- function(input, output, session){
re1<-reactive({
file1<-file.choose()
file1
})
output$folder1<-renderText({
re1()
})
re2<-reactive({
file2<-file.choose()
file2
})
output$folder2<-renderText({
re2()
})
# re3<-reactive({
# input$goButton
# x<-diffr(folder1,folder2, before="Folder 1",after="Folder 2")
# return(x)
# })
output$FileDiff <- renderDiffr({
input$goButton
diffr(re1(), re2(), before="Folder 1", after="Folder 2")
})
}
)
shinyApp(ui, server)

Related

How to minimize a sidebarLayout in a Shiny App?

I am building a shiny app and I am using two sidebarLayouts. I’m looking for a way to minimize them. I have try put each sidebarLayout into a box.
Example code:
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
headerPanel("Here goes the heder"),
box(sidebarLayout(
sidebarPanel(textOutput("someinputs")),
mainPanel(textOutput("someoutputs"))),
width = 12,
title = "BB",
collapsible = T,
collapsed = F
)
)
server <- function(input, output) {
output$someinputs <- renderText({
"Here will go the inputs"
})
output$someoutputs <- renderText({
"Here will go the outputs"
})
}
shinyApp(ui, server)
Output:
When I press the collapsible button the Layout does not collapse. Why is this happening? What should I do? Is there other way to do this?
Because you didn't use shinydashboard. The box comes from shinydashboard package. You need to use shinydashboard::dashboardPage instead of fluidPage.
dashboardPage Loads required javascripts and CSS files to toggle the button.
library(shiny)
ui <- shinydashboard::dashboardPage(
shinydashboard::dashboardHeader(),
shinydashboard::dashboardSidebar(),
shinydashboard::dashboardBody(
headerPanel("Here goes the heder"),
shinydashboard::box(
width = 12,
title = "BB",
collapsible = TRUE,
collapsed = FALSE,
sidebarLayout(
sidebarPanel(textOutput("someinputs")),
mainPanel(textOutput("someoutputs")))
)
)
)
If you don't want to use dashboardPage, you can write your own scripts to control the button:
library(magrittr)
library(shiny)
ui <- fluidPage(
headerPanel("Here goes the heder"),
shinydashboard::box(
width = 12,
title = "BB",
collapsible = TRUE,
collapsed = FALSE,
sidebarLayout(
sidebarPanel(textOutput("someinputs")),
mainPanel(textOutput("someoutputs")))
)%>% {.$attribs[['id']] <- 'example-box'; .},
tags$head(tags$script(
"$(document).ready(function(){
$('#example-box button').attr({
'data-toggle':'collapse',
'data-target':'#example-box .box-body',
'aria-expanded':false
})
})"
))
)
I used a hack to assign an ID to the box %>% {.$attribs[['id']] <- 'example-box'; .}, and use some jquery to control the button. Be sure the ID in the script matches the ID you assign in UI, example-box in this case. In javascript, you add # for ID searching, so #example-box.
I wouldn't recommend you to use the second way. You can see in your UI, it's not really a box. It has no border and the button is not at the right place. If you use dashboardPage, you can see the difference.

Folder selection in Shiny App (locally and on the server) to read the files and save results

I am trying to use the solution proposed here.
The difference is that I want the user to chose two folders, one to save the result of my code, and one that has all files.
Now the question is that how can I save files in the second folder (input$fileout). Is there a way to pass this path to a function that processes my input files? I think there will be a permission issue.
Edit: I'd like to use dataHandler inside my.analysis() function as I need to save multiple pngs, csv and some specific formatted files. What would be the best approach? My shinyApp does not print out anything, except that analysis is done, download the result.
Here's the updated ui.R
library(shiny)
library(shinythemes)
library(shinyWidgets)
shinyUI(tagList(fluidPage(theme = shinytheme("lumen"),
includeScript("./www/text.js"),
titlePanel("Test"),
fluidRow(
column(4,
tags$div(class="form-group shiny-
input-container",
tags$div(tags$label("Choose a
folder", class="btn btn-primary",
tags$input(id = "fileIn", webkitdirectory = TRUE, type = "file", style="display: none;", onchange="pressed()"))),
tags$label("No folder choosen", id = "noFile"),
tags$div(id="fileIn_progress", class="progress progress-striped active shiny-file-input-progress",
tags$div(class="progress-bar")
)
)),
verbatimTextOutput("tbl")
),
fluidRow(
column(8,
verbatimTextOutput("results"))
)
),
HTML("<script type='text/javascript' src='getFolders.js'>
</script>")
)
)
And my server.R
library(shiny)
library(ggplot2)
library(shinythemes)
library(shinyWidgets)
library(flowCore)
source("myanalysis.R")
options(shiny.maxRequestSize=50*1024^2)
shinyServer(function(input, output, session) {
observeEvent(input$go, {
df <- reactive({
print(input$fileIn)
# Below returns NULL, as it does not have any files in it yet.
print(input$fileout)
inFiles <- input$fileIn
if (is.null(inFiles))
return(NULL)
my.analysis(fs = tmp,output=input$fileout)
})
output$tbl <-renderPrint(
df()
)
output$results = renderPrint({input$mydata
})
})
})
Any help will be greatly appreciated.
Here are two options:
Option 1
It you only want to choose a folder in the sever side (that could be the local system if your app is running locally), you can use ShinyFiles.
Option 2
If your app is running in a server, then is not possible that you can write data to a local directory from your Shiny app. The solution in this case is to save the results in the server and later allow the user to download it using the downloadHandler function.

Let parent server of module know that something happened inside the module

I am building an app that presents a data table and which allows you to add data. The adding of data is build by means of a form. This form is written by a module. What I want to happen is that one may fill out the form, press an 'add' button and that the data inside the table is updated.
As an example, could you help me figure out how to complete the following piece of code:
library(shiny)
library(shinydashboard)
moduleInput <- function(id){
ns <- NS(id)
sidebarPanel(
actionButton(ns("action1"), label = "click")
)
}
module <- function(input, output, session){
observeEvent(input$action1, {
# Do stuff here,
# -> let the parent module or server know that something has happened
})
}
ui <- fluidPage(
verbatimTextOutput("module.pressed"),
moduleInput("first")
)
server <- function(input, output, session){
# print the currently open tab
output$module.pressed <- renderPrint({
#-> Write that we have pressed the button of the module
})
callModule(module,"first")
}
shinyApp(ui = ui, server = server)
All I thus want to do is find an easy way to present TRUE in the output field module.pressed when something happend inside the module.
Thanks!
Modules can pass reactive expression(s) to calling apps/modules by returning them in their server function. The documentation provides a few examples on how to set up interactions between modules and calling apps - https://shiny.rstudio.com/articles/modules.html
If a module needs to use a reactive expression, take the reactive expression as a function parameter. If a module wants to return reactive expressions to the calling app, then return a list of reactive expressions from the function.
library(shiny)
moduleInput <- function(id){
ns <- NS(id)
sidebarPanel(
actionButton(ns("action1"), label = "click")
)
}
module <- function(input, output, session){
action1 <- reactive(input$action1)
return(reactive(input$action1))
}
ui <- fluidPage(
verbatimTextOutput("module.pressed"),
moduleInput("first")
)
server <- function(input, output, session){
action1 <- callModule(module,"first")
output$module.pressed <- renderPrint({
print(action1())
})
}
shinyApp(ui = ui, server = server)

bsCollapsePanel within renderUI

I am using bsCollapse panels (from the shinyBS library) heavily in an app that I am working on. I'd like to be able to define a panel on the server-side as shown in the code. The code does not run and returns an error ERROR: argument is of length zero. The problem seems to be that bsCollapse won't accept a renderUI argument and requires bsCollapsePanel call to be in ui.R.
I've tried having bsCollapse() on the server-side, which works but is clunky as the individual panels then don't expand/collapse in the same way. I've also tried including outputOptions(output, "hipanel", suspendWhenHidden = FALSE), the idea being that my "hipanel" would be evaluated earlier, but this didn't work.
I think the key is that renderUI/uiOutput isn't returning the an object that's accepted by bsCollapsePanel (at least not at the right time), but I'm not sure what to do about it.
server.R
shinyServer(function(input, output){
output$hipanel<-renderUI({
bsCollapsePanel("hello",helpText("It's working!"))
})
})
ui.R
shinyUI(fluidPage(
mainPanel(
bsCollapse(
bsCollapsePanel("This panel works",helpText("OK")),
uiOutput("hipanel")
))))
It seems that bsCollapse needs a bsCollapsePanel so just add this in and then you can rnder whatever you want into the content:
library(shiny)
library(shinyBS)
ui <- shinyUI(fluidPage(
mainPanel(
bsCollapse(
bsCollapsePanel("This panel works",helpText("OK")),
bsCollapsePanel("hello",uiOutput("hipanel"))
)
)))
server <- shinyServer(function(input, output,session){
output$hipanel<- renderUI({
helpText("It's working!")
})
})
shinyApp(ui,server)
You can always dynamically create the whole thing
library(shiny)
library(shinyBS)
ui <- shinyUI(fluidPage(
mainPanel(
uiOutput("hipanel")
)))
server <- shinyServer(function(input, output,session){
output$hipanel<- renderUI({
bsCollapse(
bsCollapsePanel("This panel works",helpText("OK")),
bsCollapsePanel("hello",helpText("It's working!"))
)
})
})
shinyApp(ui,server)

How to catch dynamic tabPanel() id in Shiny app

It is possible to use a tabPanel id into a link ? I speak of id like #tab-6584-1 or #tab-6985-1 that shows when your cursor is over a tab in a Shiny app running in a browser :
Image of dynamic tabPanel() id example with Firefox
I would like to use this to put a top left link in a Shiny app to redirect on app "home" page.
From your question, I'm not sure, but it seems like you want to mimic navigation to "subpages" in your app. If that's the case, there's a way of doing that in Shiny by reading and writing the value of the hash string at the end of the app's URL (link to gist):
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
tags$a("Go to Panel 1", href = "#panel1"), br(),
tags$a("Go to Panel 2", href = "#panel2"), br(),
tags$a("Go to Panel 3", href = "#panel3")
),
mainPanel(
tabsetPanel(id = "tabs",
tabPanel("Panel 1", h1("Panel 1"), value = "#panel1"),
tabPanel("Panel 2", h1("Panel 2"), value = "#panel2"),
tabPanel("Panel 3", h1("Panel 3"), value = "#panel3")
)
)
)
)
server <- function(input, output, session) {
# When we change from one `tabPanel` to another, update the URL hash
observeEvent(input$tabs, {
# No work to be done if input$tabs and the hash are already the same
if (getUrlHash() == input$tabs) return()
# The 'push' argument is necessary so that the hash change event occurs and
# so that the other observer is triggered.
updateQueryString(
paste0(getQueryString(), input$tabs),
"push"
)
# Don't run the first time so as to not generate a circular dependency
# between the two observers
}, ignoreInit = TRUE)
# When the hash changes (due to clicking on the link in the sidebar or switching
# between the `tabPanel`s), switch tabs and update an input. Note that clicking
# another `tabPanel` already switches tabs.
observeEvent(getUrlHash(), {
hash <- getUrlHash()
# No work to be done if input$tabs and the hash are already the same
if (hash == input$tabs) return()
valid <- c("#panel1", "#panel2", "#panel3")
if (hash %in% valid) {
updateTabsetPanel(session, "tabs", hash)
}
})
}
shinyApp(ui, server)