6

I just wanted to upload a shapefile and a raster in a RShiny app and then execute a script. What I have wrote is the following;

library(shiny)
library(raster)
library(rgdal)
ui=shinyUI(fluidPage(pageWithSidebar(
  headerPanel("Header1"),
  sidebarPanel(
   fileInput('layer', 'Choose Layer', multiple=FALSE, accept='tif'),
   fileInput('shapefile', 'Input Shapefile/AOI',accept=c('.shp','.dbf','.sbn','.sbx','.shx',".prj"), multiple=TRUE)

  mainPanel(
    plotOutput("mapPlot")
  )
)))


server = shinyServer(function(input,output){

  inFile <- reactive({input$layer})
  data <- brick(inFile())
  inFile2 <- reactive({input$shp})
  data2 <- readOGR(inFile2())

  output$mapPlot<-renderPlot({plot(data)
    plot(data2, add=T)})
})
shinyApp(ui = ui, server = server)

What I am getting is 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):

45: .getReactiveEnvironment()$currentContext 44: .dependents$register 43: inFile 42: brick 41: server [~/.active-rstudio-document#18] 5: 4: do.call 3: print.shiny.appobj 2: print 1: source

I have no idea what I did wrong and I can't find a source that explains how to solve this. Can anyone help me debug it or even help me understand what I did wrong?

3 Answers 3

7
+50

Your code has several structural problems with the reactives and so on, and some possible more fundamental problems with shapefile.

Here's a working version with some caveats that follow:

ui=shinyUI(fluidPage(pageWithSidebar(
  headerPanel("Header1"),
  sidebarPanel(
      fileInput('layer', 'Choose Layer', multiple=FALSE, accept='asc'),
      fileInput('shape', 'Choose gml', multiple=FALSE, accept="gml")

  ),
  mainPanel(
      plotOutput("mapPlot")
  )
)))


server = shinyServer(function(input,output){

    inFile <- reactive({
        raster::brick(input$layer$datapath)
    })

    inShp = reactive({
        readOGR(input$shape$datapath)
    })

    output$mapPlot<-renderPlot(
    {
        plot(inFile());
        plot(inShp(), add=TRUE)
    })
})

Note that everything in the server function is either in a "reactive" or a "renderer". That's what was causing your initial problem.

Secondly the file upload input returns a data frame with a datapath column which is where the file has been dropped. So in your code you would have been trying to read from input$layer which is a dataframe of upload data rather than input$layer$datapath which is the column with the file name you want.

Thirdly it is hard to make shapefiles work with shiny uploads. Shapefiles must have a .shp and a .shx component for readOGR to work, and possibly a .dbf and .prj component too. You can upload several files in a shiny upload widget (is that why you have multiple=T?) but the server renames them so that the data frame of input$shape contains the names 0.shp, 1.shx, 2.dbf and so on. It might be possibly to rename these back together, but most shapefile upload solutions require users to upload a ZIP file of everything which is then extracted by the server.

My solution above, and in order to show how the reactive stuff works which was your first problem, is to load a GML file instead of a shapefile. In my test code I did writeOGR(pts, "pts.gml","pts", driver="GML") just to get something I could upload to shiny and plot over a raster.

4
  • Since the day I uploaded my code I made a few changes, like fileInput('shapefile', 'Input Shapefile/AOI',accept=c('.shp','.dbf','.sbn','.sbx','.shx',".prj"), multiple=TRUE) (see changes) but nevertheless it was great getting help from that
    – Ka_Papa
    Mar 14, 2018 at 12:07
  • but nevertheless it was great getting help. I'll try using .gml. But after plotting my data, as I said, I would like to call a script using source() and then create plots based on the outputs of that R script. How can I do that?
    – Ka_Papa
    Mar 14, 2018 at 12:14
  • ^ That's very general and a big ask. I would put that in a separate question with what you have tried.
    – GISHuman
    Mar 14, 2018 at 13:01
  • I think you might be able to work with uploaded shapefile components by renaming the uploaded parts so they have a common name and the right extensions. But that's a whole other problem from what was causing your error message which was the placing of code outside reactives and renderers.
    – Spacedman
    Mar 14, 2018 at 16:52
3

For those searching for easy answers to this still: credit to Robin Cura for writing a script that lets you upload all necessary files using the multiple = TRUE argument available here, which seemingly takes care of all the issues mentioned in the other comments.

1

Given the conversation in the comments below the accepted answer I wanted to throw in a solution that won't require zipping files in order to load and plot shapefiles. This solution allows a user to select a point shapefile, execute a script (jitter xy coordinates), see the original and jittered on a plot, and export the new shapefile, all from within a (remedial) Shiny dashboard.

library(shiny)
library(shinydashboard)

ui <- dashboardPage(
  dashboardHeader( title = "Jitter XY UTM Points"),
  dashboardSidebar( title = "Select .shp to run 0.3-0.5 mile Jitter"),
  dashboardBody(
    box(plotOutput("plot1", height = 500))
  )
)

server <- function(input, output) {
  library(raster)

  output$plot1 <- renderPlot({
    shp <- shapefile(file.choose())
    plot(shp, col = "black")
    shp$x_offset <- sample(482:804, size =nrow(shp), replace = TRUE)
    shp$y_offset <- sample(482:804, size =nrow(shp), replace = TRUE)
    shp$calc_X_jitter <- shp$long_x + sample(c(-1,1), size=nrow(shp), replace = TRUE)*shp$x_offset
    shp$calc_Y_jitter <- shp$lat_y + sample(c(-1,1), size=nrow(shp), replace = TRUE)*shp$y_offset
    new <- data.frame(shp)
    library(maptools)
    library(rgdal)
    library(sp)
    coordinates(new) =~ calc_X_jitter+calc_Y_jitter
    proj4string(new) <- CRS("+init=epsg:26913")
    library(gdata)
    new <- rename.vars(new, from = c("coords.x1", "coords.x2"), to = c("jitter_x", "jitter_y"))
    raster::shapefile(new, "jittered_pts.shp", overwrite = TRUE)
    plot(new, add = TRUE, col = "red")
    print("complete")
  })
}

shinyApp(ui, server)
1
  • I believe that file.choose will only work on a local Shiny app because on a server it will access the server file system not the users
    – see24
    May 13 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.