How to edit OpenStreetMap

WARNING: This vignette contain examples that can edit the data at OpenStreetMap.org. Please, create a user in the testing server and configure osmapiR to use it. You will be responsible for any edition!

library(osmapiR)
set_osmapi_connection(server = "testing") # set the testing server

Create some dummy OSM objects.

d <- data.frame(
  type = c("node", "node", "way", "relation"),
  id = -(1:4),
  lat = c(0, 1, NA, NA),
  lon = c(0, 1, NA, NA),
  name = c(NA, NA, "My way", "Our relation"),
  type.1 = c(NA, NA, NA, "Column clash!")
)
d$members <- list(
  NULL, NULL, -(1:2),
  matrix(
    c("node", "-1", "node", "-2", "way", "-3"),
    nrow = 3, ncol = 2, byrow = TRUE, dimnames = list(NULL, c("type", "ref"))
  )
)
obj <- osmapi_objects(d, tag_columns = c(name = "name", type = "type.1"))

Using OSMChange format and osm_diff_upload_changeset()

osmcha_crea <- osmchange_create(obj)
osmcha_crea

changeset_id <- osm_create_changeset(
  comment = "Add objects for testing editions with osmchange format.",
  hashtags = "#osmapiRvignette;#testing"
)
osmcha_diff <- osm_diff_upload_changeset(changeset_id = changeset_id, osmcha = osmcha_crea)

message("See changeset at:\n\t", paste0(get_osmapi_url(), "/changeset/", changeset_id))

Add a new node:

new_node <- data.frame(type = "node", id = -1, lat = 0, lon = 1)
new_node <- osmapi_objects(new_node)
osmcha_new_node <- osmchange_create(new_node)

Update the id of the created objects which we want to modify with the id assigned by the server:

mod_obj <- obj[3:4, ]
mod_obj$id <- osmcha_diff$new_id[match(mod_obj$id, osmcha_diff$old_id)]

mod_obj$members[[1]] <- osmcha_diff$new_id[match(mod_obj$members[[1]], osmcha_diff$old_id)]
mod_obj$members[[2]][, "ref"] <- osmcha_diff$new_id[match(mod_obj$members[[2]][, "ref"], osmcha_diff$old_id)]

Add the new node to the way and the relation

mod_obj$members[[1]] <- c(mod_obj$members[[1]], new_node$id)
mod_obj$members[[2]] <- rbind(mod_obj$members[[2]], as.character(new_node[, c("type", "id")]))
mod_obj <- osmapi_objects(mod_obj)

osmcha_mod <- osmchange_modify(mod_obj, tag_keys = FALSE, members = TRUE)

Unite modification and new node changes and commit changes

# Just for the rbind of `osmcha_create` and `osmcha_modify` which have different columns:
osmcha_new_node <- osmapi_objects(osmcha_new_node)
osmcha_new_node[, setdiff(names(osmcha_mod), names(osmcha_new_node))] <- NA

osmcha_2 <- rbind(osmcha_new_node, osmcha_mod)

osmcha_diff2 <- osm_diff_upload_changeset(changeset_id = changeset_id, osmcha = osmcha_2)

Even if it’s a testing server, better to leave it clean. Let’s remove the created objects and close the changeset:

osmcha_del <- unique(rbind(osmcha_diff[, c("type", "new_id")], osmcha_diff2[, c("type", "new_id")]))
names(osmcha_del) <- c("type", "id")
osmcha_del <- osmchange_delete(osmcha_del)
osmcha_del

osmcha_diff_del <- osm_diff_upload_changeset(changeset_id = changeset_id, osmcha = osmcha_del)
osmcha_diff_del

osm_close_changeset(changeset_id)

Using osmapi patterns

To avoid performance issues when uploading multiple objects, the use of transactions with [osm_diff_upload_changeset()] as in the former example is highly recommended.

changeset_id <- osm_create_changeset(
  comment = "Add objects for testing editions with osmapi.",
  hashtags = "#osmapiRvignette;#testing"
)

new_id <- character(nrow(obj))

# create nodes
for (i in 1:2) {
  obj$id[i] <- osm_create_object(obj[i, ], changeset_id = changeset_id)
}

# create way
obj$members[[3]] <- obj$id[1:2] # update id of the newly created nodes
obj$id[3] <- osm_create_object(obj[3, ], changeset_id = changeset_id)

# create relation
obj$members[[4]][, "ref"] <- obj$id[1:3] # update id of the newly created objects
obj$id[4] <- osm_create_object(obj[4, ], changeset_id = changeset_id)

message("See changeset at:\n\t", paste0(get_osmapi_url(), "/changeset/", changeset_id))

Update object:

upd_obj <- osm_get_objects(osm_type = obj$type[4], osm_id = obj$id[4])
new_tags <- upd_obj$tags[[1]]
new_tags$value[2] <- "test"
new_tags <- rbind(new_tags, data.frame(key = "name:ca", value = "La nostra relació"))
upd_obj$tags[[1]] <- new_tags

osm_update_object(upd_obj, changeset_id = changeset_id)

Delete everything and close the changeset:

obj$version <- "1"
obj$version[4] <- "2" # updated object
for (i in rev(seq_len(nrow(obj)))) { # reverse order to avoid error (Node xxx is still used by ways yyy.)
  osm_delete_object(obj[i, ], changeset_id = changeset_id)
}

osm_close_changeset(changeset_id)