From 43aae3b498346de765ee1a1a1765f1f277197c78 Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Thu, 17 Mar 2022 22:58:24 +1100 Subject: [PATCH 1/3] simple rstudio addin for creating features in rstudio --- NAMESPACE | 1 + R/addin.R | 107 ++++++++++++++++++++++++++++++++++++++++ inst/rstudio/addins.dcf | 4 ++ man/mapeditAddin.Rd | 22 +++++++++ 4 files changed, 134 insertions(+) create mode 100644 R/addin.R create mode 100644 inst/rstudio/addins.dcf create mode 100644 man/mapeditAddin.Rd diff --git a/NAMESPACE b/NAMESPACE index a951c25..9f3b79d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -33,6 +33,7 @@ importFrom(DT,datatable) importFrom(DT,editData) importFrom(DT,renderDataTable) importFrom(DT,replaceData) +importFrom(dplyr,bind_rows) importFrom(leaflet,setView) importFrom(mapview,mapview) importFrom(miniUI,gadgetTitleBar) diff --git a/R/addin.R b/R/addin.R new file mode 100644 index 0000000..c9b2ab5 --- /dev/null +++ b/R/addin.R @@ -0,0 +1,107 @@ + + + +#' @title mapedit create features Addin +#' @description Create and save spatial objects within the Rstudio IDE. Objects +#' can then be saved to file types such as \code{.geojson} or \code{.shp}. +#' Objects are also output to the console and can be assigned to a variable +#' using `.Last.value`. If you wish to pass the output directly to a variable +#' simply call the addin function, ie. \code{new_sf <- mapeditAddin()}. +#' +#' An existing sf \code{data.frame} can also be passed either indirectly by +#' selecting text in RStudio with the name of the object, or directly by +#' passing the existing sf object to \code{new_sf <- mapeditAddin(existing_sf)}. +#' When passing an existing sf object you can only add and edit additional features, +#' the existing features cannot be changed. +#' +#' @param SF_OBJECT sf Simple feature collection +#' +#' @return sf object and/or saved to file +#' @importFrom miniUI miniPage miniContentPanel gadgetTitleBar miniButtonBlock +#' @import shiny +#' @importFrom shinyWidgets switchInput updateSwitchInput +#' @importFrom mapview mapview +#' @importFrom sf write_sf +#' @importFrom dplyr bind_rows +#' @importFrom leaflet setView +#' @importFrom rstudioapi getActiveDocumentContext +#' @export +#' +mapeditAddin <- function(SF_OBJECT = NULL) { + + ui <- miniPage( + gadgetTitleBar("Edit Map"), + miniContentPanel( + editModUI("editor"), + miniButtonBlock( + div(style="display: inline-block;padding-top:22px;padding-left:30px;width:200px;", + switchInput('savefile', 'Save', value = FALSE, onStatus = "success", offStatus = "danger")), + div(style="display: inline-block; width: 400px;", + textInput('filename', '', value = 'saved_geometry.geojson')), + div(style="display: inline-block;padding-top:18px;width: 400px;font-size: 10pt;color: #313844;", + 'The filename can include a path relative to working directory. ', + 'A different file type can be selected by changing the file extension.') + ) + ) + ) + + server <- function(input, output, session) { + + # get values from rstudio + ct <- getActiveDocumentContext() + + TEXT <- ct$selection[[1]]$text + OBJECTNAME <- ifelse(TEXT == '', 'geom', TEXT) + FILENAME <- ifelse(TEXT == '', 'saved_geometry.geojson', paste0(TEXT, '.geojson')) + + # test selected text an sf object (if not passed directly) + try({ + if (is.null(SF_OBJECT)) { + SF_OBJECT <- get(TEXT) + if (!('sf' %in% class(SF_OBJECT))) {SF_OBJECT <- NULL} + } + }, silent = TRUE) + + # update UI based on inputs + updateTextInput(session, 'filename', value = FILENAME) + if (FILENAME != 'saved_geometry.geojson') { + updateSwitchInput(session, 'savefile', value = TRUE) + } + + # load mapedit + if ('sf' %in% class(SF_OBJECT)) { + geo <- callModule(editMod, "editor", mapview(SF_OBJECT)@map) + } else { + geo <- callModule(editMod, "editor", setView(mapview()@map, 80, 0, 3)) + } + + observe({ + input$filename + OBJECTNAME <- tools::file_path_sans_ext(basename(input$filename)) + }) + + # return geometry to file and object in console + observeEvent(input$done, { + geom <- geo()$finished + + if (!is.null(geom) & !is.null(SF_OBJECT)) geom <- dplyr::bind_rows(SF_OBJECT, geom) + + if (!is.null(geom)) { + if (input$savefile) { + sf::write_sf(geom, input$filename, delete_layer = TRUE, delete_dsn = TRUE) + } + } + + stopApp({ + if (!is.null(geom)) { + geom + } + }) + }) + + } + + viewer <- paneViewer(600) + runGadget(ui, server, viewer = viewer) + +} diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf new file mode 100644 index 0000000..6d1c8f0 --- /dev/null +++ b/inst/rstudio/addins.dcf @@ -0,0 +1,4 @@ +Name: Create Spatial Data +Description: Create spatial data using mapedit +Binding: mapeditAddin +Interactive: true diff --git a/man/mapeditAddin.Rd b/man/mapeditAddin.Rd new file mode 100644 index 0000000..b950039 --- /dev/null +++ b/man/mapeditAddin.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addin.R +\name{mapeditAddin} +\alias{mapeditAddin} +\title{mapedit create features Addin} +\usage{ +mapeditAddin(SF_OBJECT = NULL) +} +\value{ +sf object and/or saved to file +} +\description{ +Create and save spatial objects within the Rstudio IDE. Objects can then be saved +to file types such as \code{.geojson} or \code{.shp}. Objects are also output to the console and can +be assigned to a variable using `.Last.value`. If you wish to pass the output directly to a variable +simply call the addin function, ie. \code{new_sf <- mapeditAddin()}. + +An existing sf \code{data.frame} can also be passed either indirectly by selecting text in RStudio +with the name of the object, or directly by passing the existing sf object to \code{new_sf <- mapeditAddin(existing_sf)}. +When passing an existing sf object you can only add and edit additional features, the existing +features cannot be changed. +} From e7d15f1f63cf8ceaa53e9406e7a2bf5bf9d69605 Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Thu, 17 Mar 2022 23:15:57 +1100 Subject: [PATCH 2/3] add editAttributes as addin but basic usage --- inst/rstudio/addins.dcf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf index 6d1c8f0..70ba4e4 100644 --- a/inst/rstudio/addins.dcf +++ b/inst/rstudio/addins.dcf @@ -2,3 +2,8 @@ Name: Create Spatial Data Description: Create spatial data using mapedit Binding: mapeditAddin Interactive: true + +Name: Edit Spatial Data and Attributes +Description: Create and edit spatial data and attributes +Binding: editAttributes +Interactive: true From f33ec7f60e7f71d819df40fbb930ab0a2fb2e15a Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Thu, 17 Mar 2022 23:18:40 +1100 Subject: [PATCH 3/3] update function name to createFeatures --- R/addin.R | 6 +++--- inst/rstudio/addins.dcf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/addin.R b/R/addin.R index c9b2ab5..9294f77 100644 --- a/R/addin.R +++ b/R/addin.R @@ -6,11 +6,11 @@ #' can then be saved to file types such as \code{.geojson} or \code{.shp}. #' Objects are also output to the console and can be assigned to a variable #' using `.Last.value`. If you wish to pass the output directly to a variable -#' simply call the addin function, ie. \code{new_sf <- mapeditAddin()}. +#' simply call the addin function, ie. \code{new_sf <- createFeatures()}. #' #' An existing sf \code{data.frame} can also be passed either indirectly by #' selecting text in RStudio with the name of the object, or directly by -#' passing the existing sf object to \code{new_sf <- mapeditAddin(existing_sf)}. +#' passing the existing sf object to \code{new_sf <- createFeatures(existing_sf)}. #' When passing an existing sf object you can only add and edit additional features, #' the existing features cannot be changed. #' @@ -27,7 +27,7 @@ #' @importFrom rstudioapi getActiveDocumentContext #' @export #' -mapeditAddin <- function(SF_OBJECT = NULL) { +createFeatures <- function(SF_OBJECT = NULL) { ui <- miniPage( gadgetTitleBar("Edit Map"), diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf index 70ba4e4..d5f366c 100644 --- a/inst/rstudio/addins.dcf +++ b/inst/rstudio/addins.dcf @@ -1,6 +1,6 @@ Name: Create Spatial Data Description: Create spatial data using mapedit -Binding: mapeditAddin +Binding: createFeatures Interactive: true Name: Edit Spatial Data and Attributes