We are running several shiny apps for educational purposes on shinyapps.io. In order to track the usage we tried the shinylogs package locally, which worked out fine. Now the goal is to upload the logfiles created by shinylogs on shinyapps.io to a WebDAV server.
The file upload itself can be achieved with the following code. Note, that I have not revealed my true credentials for security reasons. So this request won't actually work for you.
username <- "xxx"
password <- "yyy"
file <- upload_file("test.txt")
PUT("https://fernuni-hagen.sciebo.de/public.php/webdav/test.txt", authenticate(username, password), body = file)
As the next step I created a function out of it, which also works fine.
upload <- function(filename){
body <- upload_file(filename)
PUT(paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", filename), authenticate(username, password), body = body)
}
upload("test.txt")
Finally, I tried to combine this code with the track_usage command of shinylogs. According to the documentation the store_custom mode should be suitable. Not finding any working example on the web, I was unable to figure out the right syntax, though.
Instead of a single file specified upfront, the function should upload any new logfile to the WebDAV server. In order to clarify my requirements, I have created this simple demo app.
library(shiny)
library(shinylogs)
library(httr)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
fluidRow(
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins1",
"Number of bins:",
min = 1,
max = 50,
value = 30)),
mainPanel(
# Show a plot of the generated distribution
plotOutput("distPlot1")
))),
fluidRow(
# Sidebar with a slider input for number of bins (and action button)
sidebarLayout(
sidebarPanel(
sliderInput("bins2",
"Number of bins:",
min = 1,
max = 50,
value = 30),
actionButton("go", "Update Plot")),
mainPanel(
# Show a plot of the generated distribution
plotOutput("distPlot2")
)))
)
# Define server logic required to draw a histogram
server <- function(input, output) {
username <- "xxx"
password <- "yyy"
track_usage(storage_mode = store_custom(FUN = function(logs){
body <- upload_file(logs)
url <- paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", logs)
PUT(url, authenticate(username, password), body = body)
}))
output$distPlot1 <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins1 + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$distPlot2 <- renderPlot({
# generate bins based on input$bins from ui.R (only upon click)
input$go
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = isolate(input$bins2) + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
When I run this shiny app locally, there is no error message in the R console, but the files will never arrive on the WebDAV server. Any help to fix this issue would be much appreciated.
So this is my own solution.
# Configuration of logging directory
logsdir <- "~/logs"
# Create directory for log files, if not existent
if(!dir.exists(logsdir)) dir.create(logsdir)
# Usage tracking with JSON file being saved on Shiny and WebDAV Servers
track_usage(
storage_mode = store_custom(FUN = function(logs) {
jsondata <- toJSON(logs)
filename <- paste0("shinylogs_", session$token, ".json")
filepath <- paste0(logsdir, "/", filename)
write(jsondata, file = filepath)
body <- upload_file(filepath)
url <- paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", filename)
PUT(url, authenticate(username, password), body = body)
})
)
Related
So I have a shiny app. I want to create a new tab. And within that new tab I want to display the code in a specific R file that is located in a folder within the package.
Basic requirements is to display the R file as if it is a text file verbatim.
Enhance features would have it display text and color rendering as if reading it from RStudio or something.
You can do it by rendering the file contents as HTML inside <pre><code> tags...
Say your file is in www/random_fn.R:
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Home", sliderInput(inputId = "bins",label = "Bins", min = 0, max = 10, value = 3),
plotOutput("distPlot")),
tabPanel("R Code", uiOutput("show_code")
))
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$show_code <- renderUI({
raw_lines <- readLines("www/random_fn.R")
# insert line breaks for HTML
code_joined <- stringi::stri_join(raw_lines, collapse = "\n")
tagList(
tags$pre(
tags$code(
HTML(code_joined)
)
)
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Also you can use package shinyAce
Is it possible for multiple users of the same app to make changes to the same set of reactive values?
This question (handling multiple users simulaneously in an R Shiny app) suggests that multiple users in different sessions can make changes to the same value (by declaring it outside of server() and using <<- instead of <- ) But that is for just plain old values/variables. Is this possible for reactive values?
Ideally, I would like a change made by user A to be immediately reflected in some output viewed by user B.
Here's a minimal working example based on RStudio's default one-file Shiny app:
library(shiny)
slidervalue <- 30
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = slidervalue)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput('txt')
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
observe({
slidervalue <<- input$bins
})
reactive_slidervalue <- reactivePoll(100, session,
checkFunc = function() { slidervalue },
valueFunc = function() { slidervalue }
)
output$txt <- renderText(reactive_slidervalue())
observe({
updateSliderInput(session, 'bins', value = reactive_slidervalue())
})
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = reactive_slidervalue() + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
Basically, I am using a global variable (as you and and the post suggested), and then hooked it back into server by using the reactivePoll function to make the external dependency reactive.
Im creating shiny app. for calculating risk score where the user will upload input file and select the input such as ethnic groups, type of calculating score and diseases. After all of the input are selected and file is uploaded, my App. will be run when user click at action button and the output such as graph and dataframe will be shown
Im using observeEvent to control my App for triggering unnecessarily( mulitple handleExpr with one eventExpr), and this is my shorten version of code. Im sorry for my code that is not reproducible.
observeEvent(input$action,{
isolate(system2("bash_script/plink.sh",args = c(input$file$datapath,input$type,input$sum_stat,input$Disease,input$Ethnic,input$Ref)))
output$table_score <- renderDataTable({
percentile <- read.csv("../output/score_percentile.csv",header = T, sep = "\t")
}, selection = "single")
output$table_variant <- renderDataTable({
varaints_in_sample <- fread("../output/summary.csv", header = T, drop = 1)
})
#Plot Graph
output$plot <- renderPlot({
s <- input$table_score_cell_clicked
plot("../output/score_percentile_plot.csv",s,"analysis")
})
})
my problem is that when Im running app for the first time, everything is controllable. However, if I want to select new input. for example im changing input disease from heart disease to another disease. my App. will be triggered unnecessarily although I did NOT click at action button.
So, Is there any way to use observeEvent with one evenExpr for mulitple handleExpr
Thanks everyone for your help!
I think, this is simplified example of your problem. The solution is to put all your input$... inside isolate().
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
actionButton('action', 'Click')
),
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
req(input$action)
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = isolate(input$bins) + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
shinyApp(ui = ui, server = server)
I want to modularise my shiny app code, by moving parts of the code in separate files. I then include the content of the file with a call to the source function: source("./www/some_code.R", local = TRUE)
It works well except for an undesired effect: the word TRUE is added just below the insert.
Could you help me understand why this happen and how I can remove this undesired text?
For a reproducible example,
create app.R:
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
source("./www/slider.R", local = TRUE)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
and in the www folder the slider.R:
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
Just when I posted this, I saw a link to this which answer the question: displaying TRUE when shiny files are split into different folders
I thought that I did my research though... Should I delete the whole thread?
I generate and display a flextable in a Shiny app and want to place it in a PDF. The only available method is to convert the flextable object to a PNG then place the PNG in the PDF. For each PNG file I assign a filename including a date-time stamp to make it unique between sessions. This file name is saved in a reactiveValue.
When the user is finished and the session is closed, how can I delete the file? If I do not I will pile up extraneous files. I cannot use onSessionEnded() because the reactive values are all gone when the browser is closed. I cannot generalize using a pattern because other users have files with a similar name. I have to delete these PNG files specifically.
Any ideas?
onSessionEnded code that does not work:
observe({
session$onSessionEnded(function() {
unlink(c(values$fnameSummary))
unlink(c(values$fnameLike))
unlink(c(values$fnameRisk1))
})
})
This produces the following error:
Warning: Error in .getReactiveEnvironment()$currentContext: 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.)
Stack trace (innermost first):
33: .getReactiveEnvironment()$currentContext
32: .subset2(x, "impl")$get
31: $.reactivevalues
30: $
29: unlink
28: callback [C:\Users\jch1748\Documents\Projects\W2017010 - Combined Risk Tool\testing/server.R#2790]
1: runApp
maybe a working example will help?
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
tsts <- reactiveValues()
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
observe({
tsts$fname <- "AAA.txt"
write(input$bins, file=tsts$fname)
})
onSessionEnded(function() {
cat("Session Ended\n")
unlink(tsts$fname)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I had a similar problem where I wanted to dynamically serve images and pdf files for download in a shiny app. Therefore the files need to be placed within the www-directory which makes the use of tempdir impossible. Additionally, the created files needed to be deleted after the app stops. I solved the problem with the following code:
session$onSessionEnded(function() {
system(paste("rm -f", PathToFile))
})
No need to use reactiveValues. Please see:
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
fname <- "AAA.txt"
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
observe({
write(input$bins, file=fname)
})
session$onSessionEnded(function() {
cat("Session Ended\n")
unlink(fname)
})
}
# Run the application
shinyApp(ui = ui, server = server)