0

The code below is generating a scatterplot from a shapefile file. It is generating normally (see the attached image). However, instead of inserting the file directory directly into the code, I would like to insert the file through a fileInput. I inserted the fileInput below, but I would like help to adjust my server. I believe it is necessary to adjust something related to the reactive.

Thank you so much!

library(shiny)
library(ggplot2)
library(shinythemes)
library(rdist)
library(geosphere)
library(rgdal)

function.cl<-function(df,k){
  
  shape<-readOGR(dsn="C:/Users/Jose Souza/Documents/Test",layer="Export_Output_3") 
  df<-shape@data
  
  #clusters
  coordinates<-df[c("Latitude","Longitude")]
  d<-as.dist(distm(coordinates[,2:1]))
  fit.average<-hclust(d,method="average") 
  clusters<-cutree(fit.average, k) 
  nclusters<-matrix(table(clusters))  
  df$cluster <- clusters 
  
  #all cluster data df1 and specific cluster df_spec_clust
  df1<-df[c("Latitude","Longitude")]
  df1$cluster<-as.factor(clusters)
    
  #Colors
  my_colors <- rainbow(length(df1$cluster))
  names(my_colors) <- df1$cluster
  
  #Scatter Plot for all clusters
  g <- ggplot(data = df1,  aes(x=Longitude, y=Latitude, color=cluster)) + 
    geom_point(aes(x=Longitude, y=Latitude), size = 4) +
    scale_color_manual("Legend", values = my_colors)
  plotGD <- g
  

  return(list(
    "Plot" = plotGD
  ))
}

ui <- bootstrapPage(
  navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
             "Cl", 
             tabPanel("Solution",
                      fileInput("shp", h3("Shapefile Import"), multiple = TRUE, accept = c('.shp', '.dbf','.sbn', '.sbx', '.shx', '.prj')),
                      sidebarLayout(
                        sidebarPanel(
                        
                          sliderInput("Slider", h5(""),
                                      min = 2, max = 4, value = 3),
                        ),
                        mainPanel(
                          tabsetPanel(      
                            tabPanel("Solution", plotOutput("ScatterPlot"))))
                        
                      ))))

server <- function(input, output, session) {
  
  Modelcl<-reactive({
    function.cl(df,input$Slider)
  })
  
  output$ScatterPlot <- renderPlot({
    Modelcl()[[1]]
  })
     
}

shinyApp(ui = ui, server = server)

enter image description here

Antonio
  • 1,091
  • 7
  • 24
  • What do you want to do in the server? Load selected files? – Waldi Jun 20 '20 at 21:09
  • Thanks for the answer. I would like to do the clustering after uploading the files via fileInput. Wouldn't you have to make a reactive in server for this fileInput? – Antonio Jun 20 '20 at 21:37
  • Why does function.cl have a df argument which you overwrite at the second line of the function? – Waldi Jun 20 '20 at 21:51

1 Answers1

1
  1. Add a new path argument to function.cl, remove df argument which is not used because assigned directly in the function
  2. Use `eventReactive' in the server :
  Modelcl <- eventReactive(input$shp,{
    req(input$shp)
    mydir <- tempdir()
    on.exit(unlink(mydir))
    print(paste("names:",input$shp$name))
    file.copy(input$shp$datapath,file.path(mydir, input$shp$name) )
    function.cl(input$Slider,mydir)
    
  })

The difficulty was that readOGR expects a path but fileInput returns files.

The workaround was to create a temporary directory to get a path (on the server), to copy the fileInput files into it and to give the path of this temporary directory to readOGRfor further processing.

This works with the example files you provided:

library(shiny)
library(ggplot2)
library(shinythemes)
library(rdist)
library(geosphere)
library(rgdal)

function.cl<-function(k,path,filename){
  print(dir(path))
  shape<-readOGR(dsn=path,layer=filename) 
  df<-shape@data
  
  #clusters
  coordinates<-df[c("Latitude","Longitude")]
  d<-as.dist(distm(coordinates[,2:1]))
  fit.average<-hclust(d,method="average") 
  clusters<-cutree(fit.average, k) 
  nclusters<-matrix(table(clusters))  
  df$cluster <- clusters 
  
  #all cluster data df1 and specific cluster df_spec_clust
  df1<-df[c("Latitude","Longitude")]
  df1$cluster<-as.factor(clusters)
  
  #Colors
  my_colors <- rainbow(length(df1$cluster))
  names(my_colors) <- df1$cluster
  
  #Scatter Plot for all clusters
  g <- ggplot(data = df1,  aes(x=Longitude, y=Latitude, color=cluster)) + 
    geom_point(aes(x=Longitude, y=Latitude), size = 4) +
    scale_color_manual("Legend", values = my_colors)
  plotGD <- g
  
  
  return(list(
    "Plot" = plotGD
  ))
}

ui <- bootstrapPage(
  navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
             "Cl", 
             tabPanel("Solution",
                      fileInput("shp", h3("Shapefile Import"), multiple = TRUE, accept = c('.shp', '.dbf','.sbn', '.sbx', '.shx', '.prj')),
                      sidebarLayout(
                        sidebarPanel(
                          
                          sliderInput("Slider", h5(""),
                                      min = 2, max = 4, value = 3),
                        ),
                        mainPanel(
                          tabsetPanel(      
                            tabPanel("Solution", plotOutput("ScatterPlot"))))
                        
                      ))))

server <- function(input, output, session) {
  
  # Modelcl<-reactive({
  #   function.cl(df,input$Slider,input$Filter1)
  # })
  Modelcl <- eventReactive(c(input$shp, input$Slider),{
    req(input$shp)
    tmpdir <- tempdir()
    on.exit(unlink(tmpdir))
    filename <- substr(input$shp$name[1],1,nchar(input$shp$name[1])-4)
    file.copy(input$shp$datapath,file.path(tmpdir,input$shp$name) )
    function.cl(input$Slider,tmpdir,filename)
    
  })
  
  output$ScatterPlot <- renderPlot({
    Modelcl()[[1]]
  })
  
  observeEvent(input$Slider, {
    abc <- req(Modelcl()$Data)
    updateSelectInput(session,'Filter1',
                      choices=sort(unique(abc$cluster)))
  }) 
  
}

shinyApp(ui = ui, server = server)

enter image description here

Waldi
  • 39,242
  • 6
  • 30
  • 78
  • Thanks for reply. I believe this is the way, but it still hasn't worked out. This code:```df <-shape @ data``` needs to be in the code, as it converts the shapefile into data.frame. If you can insert all the code with the changes you would make, I would appreciate it. – Antonio Jun 21 '20 at 01:14
  • Thanks Waldi for updating the answer. I'm still doing tests, but I haven't been able to yet. My brother, who is helping me too, inserted the shapefile file of this issue in his github (https://github.com/JovaniSouza/JovaniSouza5/blob/master/shapefile.rar). So, I believe it’s easier for you to simulate too, if you can .Thanks again. – Antonio Jun 21 '20 at 18:19
  • thanks for the files : which one(s) should readOGR open? – Waldi Jun 21 '20 at 18:36
  • Hello friend, all the files in the zip are part of 1 shapefile. A shapefile consists of between 6 and 8 files on average. In the formula, the dsn is the path where the shapefile is saved, and Export_Output_3 is the name of the shapefile. Therefore, the readOGR is not choosing just one specific file, but all the files that make up the shapefile. – Antonio Jun 21 '20 at 23:49
  • OK, got it, so you're not looking for a fileInput, but looking to find a path – Waldi Jun 22 '20 at 15:25
  • readOGR seems to expect a path, this is the example you give. Not sure you can directly transmit the result of fileInput to a function expecting a path. See my edit : I propose to copy the uploaded files in a temp dir which is then given to readOGR. Another important argument is input$Filter1: where is it defined? – Waldi Jun 22 '20 at 18:24
  • Thanks again for the answer Waldi. I am analyzing your code. Were you able to get it to work using the shapefile via fileInput? Regarding Filter 1, it was not important for what I wanted, I even apologize for having inserted it (I removed it in the code for this question). I'm looking at this website (https://www.paulamoraga.com/book-geospatial/sec-shinyexample.html), which used shapefile data via fileInput. But I still haven't succeeded for my example. = / – Antonio Jun 22 '20 at 19:58
  • Code wasn't yet working for me, but I didn't try to solve this yet because I didn't know what to do with filter1 : When you provide code examples in Stack Overflow, please try to reduce them to a Minimal Reproducible Example without unneeded parameters. I'm going to try to make this run with you new code. – Waldi Jun 22 '20 at 20:30
  • Yes, my sincere apologies. I was focused on fileInput that I forgot those details. Thank you Waldi. – Antonio Jun 22 '20 at 20:47
  • Code now running with explainations : give it a try! – Waldi Jun 22 '20 at 21:23
  • Fantastic, thank you very much, it appeared to me too. Just two things I would like to clarify: I found it strange that the Slider is no longer working after the scatterplot is generated in your code. The last question concerns the layer of this formula: ```shape <-readOGR (dsn = path, layer =" Export_Output_3 ")```. It is necessary to always be defined as the name of the shapefile, that is, whenever I insert another shapefile, will I need to update the code? Thanks again! – Antonio Jun 22 '20 at 21:47
  • @Jose, slider works for me, added automatic filename modification – Waldi Jun 22 '20 at 22:00
  • After you generate the scatterplot. I slide on the Slider, is the cluster automatically modified on the graph? In mine, it was static. – Antonio Jun 22 '20 at 22:20
  • No the cluster is not automatically modified because eventReactive depends only on input$shp. added c(input$shp, input$Slider) as trigger. Would be even better to separate this in 2 functions, one for file read, the other for slider management. But I'm going to quit here for now ;) – Waldi Jun 22 '20 at 22:27
  • Now it's working perfectly, Waldi, I don't even know how to thank you, you helped me a lot. I hope to return this favor someday. Really, thank you very much. – Antonio Jun 22 '20 at 22:31
  • Hi Waldi, do you have any suggestions for this issue: https://stackoverflow.com/questions/62567104/generate-scatterplot-both-by-shapefile-and-excel-in-shiny/62568117#62568117 – Antonio Jun 25 '20 at 19:44