Is there a way to edit feature atributes in leaflet viewer panel?

I'm trying to create an interactive map that allows the user to edit the atributes of a selected polygon in the viewer panel. Is there a way to do so?

I found this answered question that matches exactly my task, but can't be applied to R.

The following code reproduces my problem:

library(rgdal)
library(leaflet)

#Download the shapefiles
download.file("http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip" ,destfile="world_shape_file.zip")
system("unzip world_shape_file.zip")

#Read the data
world_spdf=readOGR( dsn= getwd() , layer="TM_WORLD_BORDERS_SIMPL-0.3")

#Create the objective vector with random values
world_spdf$year <- factor(sample(c(NA,2020,2021,2022),nrow(world_spdf), replace = TRUE))

#Labels to be shown when mouseover
labels=paste("Country: ", world_spdf@data$NAME,"<br/>", "Year: ", world_spdf$year, sep="") %>%
lapply(htmltools::HTML)

#Color legend
pal <- colorFactor(palette = c('yellow','green','blue'),
                        levels = levels(world_spdf$year))

#Show map
leaflet(world_spdf) %>% 
addTiles()  %>% 
setView( lat=10, lng=0 , zoom=2) %>%
addPolygons(fillColor=~pal(year),stroke=FALSE,
                   highlightOptions = highlightOptions(weight=5,fillOpacity = 0.3,bringToFront = TRUE),
                   label=labels)%>%
       addLegend(pal=pal,values=levels(world_spdf$year),
                 title = "Travel year", position = "bottomright" )

What I want to do, is allow the user to edit the value in world_spdf$year that corresponds to the selected feature in the map.

Actually, i'm using the following code to change the value manually:

     change_to_na <- c('COUNTRY NAME')#Vector of countries whose $year will be set to NA 
     change_to_2020 <- c('COUNTRY NAME')#Vector of countries whose $year will be set to 2020
     change_to_2021 <- c('COUNTRY NAME')#Vector of countries whose $year will be set to 2021
     change_to_2022 <- c('COUNTRY NAME')#Vector of countries whose $year will be set to 2022

     world_spdf$year[which(world_spdf$NAME%in%change_to_na)] <- NA
     world_spdf$year[which(world_spdf$NAME%in%change_to_2020)] <- 2020
     world_spdf$year[which(world_spdf$NAME%in%change_to_2021)] <- 2021
     world_spdf$year[which(world_spdf$NAME%in%change_to_2022)] <- 2022

Using this code, I only need to fill the vectors with the country names, matching the names given in world_spdf$NAME. Now i'm looking forward to make things easier, without lines of code. Any help will be appreciated.

In what context are you facing the issue? In shiny it should be relatively straightforward (provided your leaflet is not too huge) by declaring the underlying data frame reactive and having the renderLeaflet recreated on each change.

Note that there is also leafletProxy expression, which may or may not be more appropriate to your use case - it serves to modify, but not recreate, an existing leaflet object.

In a static html setting I do not think such editing is doable.

I'm trying to create an interactive map that allows the user to edit the atributes of a selected polygon in the viewer panel. Is there a way to do so?

Sounds like a job for the mapedit package (built on top of leaflet) -- mapedit - updates in 0.2.0

In what context are you facing the issue? In shiny it should be relatively straightforward (provided your leaflet is not too huge) by declaring the underlying data frame reactive and having the renderLeaflet recreated on each change.

Note that there is also leafletProxy expression, which may or may not be more appropriate to your use case - it serves to modify, but not recreate, an existing leaflet object.

In a static html setting I do not think such editing is doable.

Thanks for your reply. I realized that shiny can solve the issue, but i'm new to this package and the better I can do is a simple choropleth. The objective in my project is to make the polygon atribute change when i click on it. So it means that i don't need to edit the atribute, but the atribute should "jump" to the next level when i click in the polygon. Actually, i have 4 levels c(NA, 2020, 2021,2022).

Example: If i click on a country (polygon) whose the value of the atribute "year" is 2020, it should jump to 2021. If the value is 2021, on the next click it should jump to 2022, and if the value is 2022, on the next click it should jump to NA.

Sounds like a job for the mapedit package (built on top of leaflet ) -- https://www.r-spatial.org/r/2017/06/09/mapedit_0-2-0.html

I tryied to use mapedit, but the edit features funcionality is not implemented yet.
Thanks for your reply.

Ahh, now I think I understand; and yea, this functionality is sufficiently specific that I you'll want to leverage shiny to implement the reactive logic. Here's a fairly naive implementation that redraws the map from scratch everytime you click a polygon. A more sophisticated approach could leverage leafletProxy() to only update the color of the clicked polygon:

library(rgdal)
library(leaflet)
library(shiny)

#Download the shapefiles
download.file("http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip" ,destfile="world_shape_file.zip")
system("unzip world_shape_file.zip")
#
##Read the data
world_spdf=readOGR( dsn= getwd() , layer="TM_WORLD_BORDERS_SIMPL-0.3")

#Create the objective vector with random values
world_spdf$year <- sample(c(NA,2020,2021,2022), nrow(world_spdf), replace = TRUE)


ui <- fluidPage(
  leafletOutput("map")
)

server <- function(input, output, session) {
  
  output$map <- renderLeaflet({
    
    # get the name (id) of the clicked polygon
    cntry <- input$map_shape_click$id
    cntry_idx <- world_spdf@data$NAME %in% cntry
    # update the year column
    if (any(cntry_idx)) {
      world_spdf$year[cntry_idx] <- world_spdf$year[cntry_idx] + 1 
      world_spdf$year[world_spdf$year > 2022] <- NA
      world_spdf <<- world_spdf
    }
    
    #Labels to be shown when mouseover
    labels <- paste("Country: ", world_spdf@data$NAME,"<br/>", "Year: ", world_spdf$year, sep="")
    
    #Color legend
    pal <- colorFactor(palette = c('yellow','green','blue'), levels = na.omit(unique(world_spdf$year)))
    
    #Show map
    leaflet(world_spdf) %>% 
      addTiles()  %>% 
      setView(lat=10, lng=0, zoom=2) %>%
      addPolygons(
        fillColor = ~pal(year),
        layerId = ~NAME,
        label = lapply(labels, htmltools::HTML),
        stroke=FALSE, 
        highlightOptions = highlightOptions(weight = 5, fillOpacity = 0.3, bringToFront = TRUE)
      ) %>%
      addLegend(
        pal = pal,
        values = ~na.omit(unique(year)),
        title = "Travel year", 
        position = "bottomright" 
      )
  })
  
}

shinyApp(ui, server)

Great! That's a solution! Thank you so much!
But considering that i have a larger shapefile and a huge amount of polygons, this approach should take a lot of time to load everytime i click on a feature, right? I adopted your suggestion and tried to implement the leafletProxy() approach but seems like i need to learn more. Can you please give me some hint or show me how can I update only the clicked polygon in the map?

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