Downloadhandler error .shp file

Good morning community,
When I use the following code I have the following output error report.
the argument "content" is not specified and does not have a default value

library(shiny)
library(rgdal)

shape_map<-rasterToPolygons(raster_map)

downloadButton(outputId = "download_shape",
               label = "Download shape")

output$download_shape<-downloadHandler({
  
  filename = function() {paste0("shapefile_download.shp")}
  
  content = function(file) {(writeOGR(obj = shape_map,
                                      dsn="C:/~",
                                      layer = "zone"))}
})

Someone has a solution to this problem?

1 Like

i think there are two problems.
most important is you arent using the downloadhandler function in the expected way, whereby you pass your filename and content options in as params to its function call.

output$download_shape<-downloadHandler(
  filename = function() {paste0("shapefile_download.shp")}   ,#comma seperates the params
  content = function(file) {(writeOGR(obj = shape_map,
                                      dsn="C:/~",
                                      layer = "zone"))}
)

a second smalller problem is that the content function doesnt use the file parameter at all, and shouldnt the writeOGR take notice of diferrent filenames passed to it with the file param ?

1 Like

can you succesfully read in the file with rgdal::readOGR() ?
I dont know what Qgis is im afraid, I work a lot with shiny (so I know about downloadhandlers) but not shapefiles as my work doesnt involve maps.

I tried to open it with rgdal and it said "Cannot open layer". :grimacing:
i don't know how to do and i searched in google and many people said to create a zip file put it inside and then download that zip file

I think the first step is to confirm you can read and writeOGR shapefiles just in a plain R script aside from the shiny and downloadhandler stuff.

Hi,
I think the problem is that a shape file is not a single file, it is a set of 4+ files. What works for me is:

output$downloadShape <- downloadHandler(
    filename = "myShapeFiles.zip",
    content = function(file) {
      owd <- setwd(tempdir())
      on.exit(setwd(owd))
      tmpdir <- paste0(tempdir(), "/MyDir")
      setwd(tmpdir)
        ### This is a custom function that prepares the data and uses 
        ### writeOGR() to produce the .shp
        downloadSpatial(myObject, 
                        CRS = input$CRS, 
                        dsn = tmpdir)
       ### I scan the path where only the .shp and associated files 
      ### should be and zip them 
       zip(file, files=list.files(path = tmpdir))
    },
    contentType = "application/zip"
  )

cheers

Alejandro

2 Likes

Hi @aleruete
Many thanks to reply.

I will try to fit your code into my shinyapp and i will try later because my session is busy right now.
i will let you know when i tried and the results.

Really thanks again and cheers to you too.

hi @aleruete,
I apologize for the delay in my reply.

I tried your code and didn't work and report me the follow output console:

Warning in proj4string(x) :
  CRS object has comment, which is lost in output
Warning: Error in setwd: I can't change the working directory
  [No stack trace available]

Do you have any suggestions?

thanks in advance

It is very difficult to know the cause of the error without being hands on your code. But, is that error on your local computer or deployed on a server?
Notice that "myDir" must exist at the moment of running the code.

Hi everyone,
I finally found the solution to the problem.
thanks to @Paula-Moraga, who created the spatialepiapp (https://github.com/Paula-Moraga/SpatialEpiApp).
I was able to understand which is the best way to import a shapefile into a shinyapp

This is the code.
Cheers

library(shiny)
library(rgdal)
library(mapview)

# 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),
            fileInput("filemap", "", accept=c('.shp','.dbf','.sbn','.sbx','.shx',".prj"), multiple=TRUE)
        ),

        # Show a plot of the generated distribution
        mainPanel(
           plotOutput("distPlot"),
           mapviewOutput("mapview")
        )
    )
)

# 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({
        shpdf <- input$filemap
        if(is.null(shpdf)){
            return()
        }
        previouswd <- getwd()
        uploaddirectory <- dirname(shpdf$datapath[1])
        setwd(uploaddirectory)
        for(i in 1:nrow(shpdf)){
            file.rename(shpdf$datapath[i], shpdf$name[i])
        }
        setwd(previouswd)
        
        map <- readOGR(paste(uploaddirectory, shpdf$name[grep(pattern="*.shp$", shpdf$name)], sep="/"))#,  delete_null_obj=TRUE)
        map <- spTransform(map, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))
        
        output$mapview<-renderMapview({
            mapview(map)
        })
    })
    
}

# Run the application 
shinyApp(ui = ui, server = server)


1 Like

Cool, thank you for sharing @fiorepalombina. I just see that the renderer

is within an observer. As far as I know that is not recommended as it could break the reactivity in the app. Else, works great as it is. I will take a deeper look at that "mapview" seems convinient.
Cheers,

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

Thanks in advance for the help.

There's still something wrong. When i am using the following code.

shape_map<-rasterToPolygons(raster_map)

downloadButton(outputId = "download_shape",
               label = "Download shape")

output$download_shape<-downloadHandler(
  
  filename = function() {paste0("shapefile_download.shp")},
  
  content = function(file) {(writeOGR(obj = shape_map,
                                      dsn="C:/~",
                                      layer = "zone"))}
)

the console output is giving me this error
Warning: Error in writeOGR: layer exists, use a new layer name
[No stack trace available]

as for your question, I honestly don't quite understand what you're asking. sorry.
I still want to tell you that I've always been able to use the downloadHandler for raster and png but for shapefiles I've only just started to approach it now

what default filename would you wish the fle to have ?
I assume its this - "shapefile_download.shp"
but the writeOGR wont see that, because you dont mention file when you call writeOGR

1 Like

I dont have any shapefile so I cant play around with it ..
your shape_map object ? is it small/simple enough to be dput() ?

yes I wish it is shapefile_download.shp.
but if this is the problem for downloading the shapefile I can also go avoid setting such a name.
The only thing I would like is that the user can also download the shapefile of the shinyapp processing result in any directory he will want to

https://agronomofiorentini.shinyapps.io/smart_farming_web_app/

Can you suggest me the solution for this challange?

Yes i wish to have the shapefile named "shapefile_download.shp" and this shape_map object is about 100 kb

The follow code created a ESRI shapefile directly on my desktop, but here the problem is that when i am trying to open this file on Qgis report me "invalid data source"

shape_map<-rasterToPolygons(raster_map)

downloadButton(outputId = "download_shape",
               label = "Download shape")

output$download_shape<-downloadHandler(
  
  filename = function() {paste0("shape_map.shp")},
  
  content = function(file) {(writeOGR(obj = shape_map,
                                      dsn = file,
                                      layer = "zone",
                                      driver = "ESRI Shapefile"))}
)