How to set working directory with bookmarks the bookmark directory

bookmark

#1

I am using the following code on the server to perform bookmarks.

setBookmarkExclude(c("bookmark1"))
observeEvent(input$bookmark1, {
     session$doBookmark()
})
onRestore(function(state) {
    if(DEBUG)cat(file=stderr(), paste("getwd:", getwd() ," \n"))
})

Here, the debug message shows that I am working in the current working directory of the app, and not the bookmark folder.

(I tried this without closing the session and using the bookmark from Chrom, while there was another session open within RStudio (Run in Window).

I am running into a problem with the fileInput. The input variable from the bookmark directory (input.rds) stores the plain file name without directory information. Thus, I cannot load the file because I don't know the exact location.

Further info:
I am starting the app with:

shinyApp(ui, server, enableBookmarking = "server")

The ui function starts like this:

ui <- function(request) {
  dashboardPage(

where request is never used.

The server function, which contains some of the above code starts like this:

  server <- function(input, output, session) {

The whole app is a few thousand lines long, which I would like to spare you from :wink:

but can be accessed at: github.com/baj12/scShinyHub

I would assume that since the server is still running in RStudio and thus the result of getwd is explained. But then I don't understand how to use bookmarks and if it is possible to use the server side bookmarks without a commericial server license...

Could you please help me and let me where I might be missing something?

thx in advance.


#2

Hi,

I use bookmarks in a shiny app with several fileInput controls. When the app is restored from a bookmark the fileInputs automatically loads the files they point to, but not from the original location. When a file is uploaded using a fileInput a local copy is created, and this local copy is stored in the bookmark folder along with all the other data. Upon restore the file is loaded from the bookmark folder automatically. At least I don't have to do anything manually to re-load the file.

With that said, there's a bug in Shiny, so if you use more than one fileInput Shiny will load only one of the files in all the fileInput controls. You can review the bug and my solution to it on github/rstudio/shiny, issue #1921.

Cheers
Steen


#3

Hi,

is it possible that I have to use the shiny server (https://www.rstudio.com/products/shiny/download-server/). I am currently trying to work with the regular RStudio version (https://www.rstudio.com/products/rstudio/#Desktop), which is serving my shiny apps and workbooks well (so it is kind of a server).
I am currently trying to compile it for Mac and running into some issues, so it would be great if you could verify that my time spent is worth it.

Thx
Bernd


#4

Hi,

First, I apologize if you already know this, but I'm gonna describe it anyway just to make sure :slight_smile:

When you upload a file using a fileInput control you point to the file on the client computer, and Shiny will upload the file to the server and create a local copy in a tmp folder. In the fileInput event you get the path to this temp location in input$<name-of-fileInput-control>$datapath. When you then bookmark the Shiny app, Shiny will copy the file from the temp location to the bookmark folder, and change the datapath field of the fileInput control to point to the new location. When you restore your Shiny app from the bookmark, Shiny will again copy the file from the bookmark location to a new temp location and change the datapath field accordingly. So you really don't need to worry about the location of the uploaded file, it will all be taken care of by Shiny, and the datapath field of the fileInput control will always contain the correct location.

I don't run my Shiny apps directly from RStudio as it blocks the terminal, and I usually need the terminal during debugging. Instead, during development I launch the Shiny app in a separate process (running something like R -e 'shiny::runApp("~/<path-to-shiny-app>", host="0.0.0.0", port=4000. Then I can reach my Shiny app going to localhost:4000 in a browser). In production the app is hosted on a Shiny Server instance. But it doesn't really matter here, it just changes the location of temp folder and the bookmark folder, but since I don't really need to care about those locations (they are available from the datapath field) I think you should be fine on Mac. Just remember that if you run the Shiny app in a separate process you will need to reload the app when you have made changes - Shiny looks at the timestamp of app.R to determine whether a reload is necessary. If app.R didn't change Shiny won't reload your modifications. I usually just touch app.R to make sure.

Happy hunting!
Steen


#5

Hi Steen,
thanks for your elaborated and very appreciated answer. I am now following your suggestions, but am still not getting any further...
I am starting from the command line, have put the server and ui functions in separate r scripts and controlling this via app.R.

When I load a bookmarked state it seems that my input$file1 (where I store the filename, fileInput()) is still NULL when it is called.
I looked at input.rds in the respective bookmark folder and there the variable is set, though without the bookmark path in the file1 data.frame.
I am now wondering if the input.rds is not fully loaded when the respecitive function is called or that there is some kind of sync hickup...

Do you have any idea on how to further debug this?

Thx,

B

A bit more detail:

the reactive that uses the file name starts with

inputData = reactive({
  inFile <- input$file1
  cat(file = stderr(), "DEBUG:inputData1:", names(input), ":\n")
  cat(file = stderr(), "DEBUG:inputData2:", class(input$file1), ":\n")
  cat(file = stderr(), "DEBUG:inputData3:", input$file1, ":\n")

And the corresponding output look like this:

DEBUG:inputData1: bookmark1 cellKeep cellKeepOnly cellPatternRM cellSelectionComment cellSelectionMod-selectAll cellSelectionTSNEMod-selectAll cellsFiltersOut coEminExpr DEBUGSAVE dimension_x1 dimension_x3 dimension_x4 dimension_xVioiGrp dimension_y1 dimension_y3 dimension_y4 expclusters-dimension_x expclusters-dimension_y expclusters-showCells file1 gene_id gene_id_sch geneGrpVioIds genesKeep goCalc heatmap_geneids heatmap_geneids2 maxGenes mclustids minExpGenes minGenes minGenesGS noStats panelplotids selected-dimension_x selected-dimension_y selected-showCells selectIds sidebarCollapsed sidebarItemExpanded tsneDim tsnePerplexity tsneSeed tsneTheta :
DEBUG:inputData2: NULL :
DEBUG:inputData3: :

which confuses me because apparently the variables are know, but they are not set.


#6

Hi Bernd,

I haven't really used it the way you do. I use fileInput like this:

stash = reactiveValues()
stash$inputData = NULL

observeEvent(input$file1, {
   if (!is.null(input$file1)) {
    filename = input$file1$datapath
    stash$inputData = read.xlsx(filename, colNames=F, skipEmptyRows=F)
  }
})

## somewhere in ui:
     fileInput("file1", "File to upload", multiple=F, accept=c(".xlsx"))

Coming to think about it, when you load a bookmark all the ui controls will be initialized before the bookmarked content is loaded, so you will get an empty/NULL file1 before you get a file1 with content. Maybe that is what's causing you problems? Initialization of a Shiny app is somewhat a mess (IMHO), you really need to protect every reactive against null input values, and there's no telling in what order the controls will be initialized.

Cheers
Steen


#7

Too bad, I don't have any time any more...

I am starting to do stupid things, being rushed by trying to finish this before the vacation :wink:

Somehow I have the app working with the observeEvent and it is working in the normal way. The only thing is that after loading a bookmark the input$file1 is not updated. I copy/paste the that is presented to me in the chrome browser (e.g. http://127.0.0.1:4000/?state_id=206bbd3ef1f9f7f1) and then a lot of things happen, but the input$file1 is never observed. I check this with a cat directly after invocation.

The other oddity is that I somehow cannot "source" (i.e. source('file.R')) from within the server function to load/activate the observeEvent (neither with local=TRUE/FALSE). It somehow has to be inside the server function...

I will have to create a minimal example and expand again from there, but this will have to wait until end of August... Thanks so much for your help!