diff --git a/DESCRIPTION b/DESCRIPTION index e32f58d..ba0b06c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -21,16 +21,19 @@ Imports: DT, waiter, dplyr, - readr, + leaflet, + sf, + terra, + readr +Suggests: markdown, - rmarkdown + rmarkdown, + spelling, + testthat (>= 3.0.0) Encoding: UTF-8 Language: en-US LazyData: true RoxygenNote: 7.3.1 URL: https://github.com/iiasa/ODPSCP BugReports: https://github.com/iiasa/ODPSCP/issues -Suggests: - spelling, - testthat (>= 3.0.0) Config/testthat/edition: 3 diff --git a/NEWS.md b/NEWS.md index b9cbaf1..a8da07e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,8 @@ * Incorporated Expert-Feedback and updated the protocol with additional fields and explanations. * Added glossary, to be further expanded in future versions #4 * Added tooltip to the protocol for each fields (can be toggled off) #6 +* Added option for enabling study region delineation #2 +* Added option to export a word or pdf summary of the protocol #5 * Added a bookmark option to store the current setting of the protocol as server id (experimental) ## Version 0.2 diff --git a/R/ODPSCP-package.R b/R/ODPSCP-package.R new file mode 100644 index 0000000..4c4d533 --- /dev/null +++ b/R/ODPSCP-package.R @@ -0,0 +1,14 @@ +#' @title ODPSCP +#' +#' @description +#' The ODPSCP shiny interface comes in a series of UI and server plus helper functions +#' that support the standardized reporting of prioritization results. +#' +#' @name ODPSCP +#' @docType package +#' @keywords internal +"_PACKAGE" + +globalVariables(c( + "element" +)) diff --git a/R/app_ui.R b/R/app_ui.R index f513cd3..221315d 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -28,13 +28,14 @@ app_ui <- function(request) { color = "primary", opacity = 0, href = NULL, - image = shiny::img(src = "www/logo.png", height = "20px") + image = shiny::img(src = base::normalizePath(system.file("app/www/logo.png", package = "ODPSCP")), + height = "20px") ), status = "white", border = TRUE, compact = FALSE, leftUi = NULL, rightUi = NULL, - shiny::div(style="position:relative; left:calc(65%);", + shiny::div(style="position:relative; left:calc(5%);", shinyWidgets::actionBttn( inputId = "bookmark", label = "Save settings", diff --git a/R/mod_Design.R b/R/mod_Design.R index 1425d6c..63dca72 100644 --- a/R/mod_Design.R +++ b/R/mod_Design.R @@ -29,7 +29,7 @@ mod_Design_ui <- function(id){ design elements of the study. These elements usually do not consider methodological specifications of the planning, but rather the conceptual understanding of the aims, purpose, and - framework underlying a study." + any framework underlying a study." ), shiny::hr() ) @@ -74,10 +74,11 @@ mod_Design_ui <- function(id){ # Study framework shiny::p("Does the study follow an analytical framework, either explicitly defined within the study or through a reference to previous - work? This could for example also be a specific planning protocol."), + work? This could for example also be a specific planning protocol or established + approaches such as structure decision making or adapative management."), shiny::p("Example framework references:"), shiny::p("Pressey, R. L., & Bottrill, M. C. (2009). Approaches to landscape-and seascape-scale conservation planning: convergence, contrasts and challenges. Oryx, 43(4), 464-475."), - shiny::p("Álvarez-Romero, J. G., Adams, V. M., Pressey, R. L., Douglas, M., Dale, A. P., Augé, A. A., ... & Perdrisat, I. (2015). Integrated cross-realm planning: A decision-makers' perspective. Biological Conservation, 191, 799-808."), + shiny::p("Alvarez-Romero, J. G., Adams, V. M., Pressey, R. L., Douglas, M., Dale, A. P., Auge, A. A., ... & Perdrisat, I. (2015). Integrated cross-realm planning: A decision-makers' perspective. Biological Conservation, 191, 799-808."), shiny::p("Niemiec, R. M., Gruby, R., Quartuch, M., Cavaliere, C. T., Teel, T. L., Crooks, K., ... & Manfredo, M. (2021). Integrating social science into conservation planning. Biological Conservation, 262, 109298."), shinyWidgets::pickerInput( inputId = ns("studyframework"), @@ -134,11 +135,14 @@ mod_Design_ui <- function(id){ such as the identification of areas to be placed under conservation management (e.g. Protected areas)"), shiny::selectizeInput(inputId = ns("studypurpose"), - label = "Identify or add a primary purpose", - choices = c("","Area-based allocation", "Management improvement", - "Action-based planning", "Monitoring and evaluation", - "Land-use allocation"), - multiple = FALSE, + label = "Identify or add primary purpose(s)", + choices = c("","Area-based allocation", + "Management evaluation", + "Management improvement", + "Action-based planning", + "Monitoring and evaluation" + ), + multiple = TRUE, options = list(create = TRUE, placeholder = "Choose from list, or type and click to add a new option.")) ), @@ -265,6 +269,10 @@ mod_Design_ui <- function(id){ solidHeader = TRUE, status = "secondary", collapsible = FALSE, + shiny::p("Select or add broad groups of who was engaged. + Note that co-authors are generally not considered stakeholders + unless co-authorship is given due to co-design of the + whole planning study."), shiny::selectizeInput(inputId = ns("stakeholdertype"), label = "Who was engaged?", choices = c("Policy makers (International)", diff --git a/R/mod_Export.R b/R/mod_Export.R index f0b337b..963a159 100644 --- a/R/mod_Export.R +++ b/R/mod_Export.R @@ -27,21 +27,45 @@ mod_Export_ui <- function(id){ width = 12, solidHeader = TRUE, collapsible = FALSE, - "All protocol entries can be exported in a Range of different formats - for further use. Currently supported are the compressed 'rData', 'csv' and - 'yaml' format. - ", + shiny::p( + "All protocol entries can be exported in a range of different formats + for further use such as appending them to a manuscript. + It should be noted that only 'rData', 'csv' and 'yaml' are + machine-readable formats and be imported again by ODPSCP. + " + ), + shiny::br(), # Output format shinyWidgets::radioGroupButtons( inputId = ns("downloadFormat"), label = "Output Format", individual = TRUE, + justified = TRUE, + size = "lg", status = "info", - choices = c('rData', 'csv', 'yaml'), - selected = 'rData' + choices = c('docx', 'pdf', 'rData', 'csv', 'yaml'), + selected = 'rData', + checkIcon = list( + yes = shiny::icon("circle-down"), + no = NULL + ) ), shiny::br(), # Conditional info + shiny::conditionalPanel( + condition = "input.downloadFormat == 'docx'", + ns = ns, + shiny::p("Protocol will be rendered as docx Word document, which + can be easily modified as well. Suitabile for manuscript + appendices or personal records.") + ), + shiny::conditionalPanel( + condition = "input.downloadFormat == 'pdf'", + ns = ns, + shiny::p("Protocol will be rendered as document and then converted + to a PDF format. This is the most convenient format for + appending the protocol to any publications for example.") + ), shiny::conditionalPanel( condition = "input.downloadFormat == 'rData'", ns = ns, @@ -66,12 +90,16 @@ mod_Export_ui <- function(id){ any text editor and loaded as lists into R via yaml::read_yaml(file).") ), shiny::br(), + shiny::hr(), + shiny::div(id = ns("missing"), class = 'missing', + shiny::textOutput(outputId = ns("missingtext"))), + shiny::br(), # Button shiny::downloadButton(ns("downloadData"), "Download the protocol") ) ), shiny::tabPanel( - title = "Render protocol", + title = "Render protocol table", icon = shiny::icon("list-alt",lib = "glyphicon"), bs4Dash::box( title = "Protocol", @@ -107,6 +135,13 @@ mod_Export_server <- function(id, results){ editable = FALSE) }) + # Get mandatory protocol entries + mand <- get_protocol_mandatory() + + # Check for mandatory outputs and highlight them in text + output$missingtext <- shiny::renderText("Highlight here all entries not yet filled!") + # observeEvent() + # Get output format oftype <- shiny::reactive({input$downloadFormat}) @@ -136,6 +171,12 @@ mod_Export_server <- function(id, results){ protocol <- format_protocol(results, format = "list") yaml::write_yaml(protocol, file = file) # yaml::read_yaml("../../../Downloads/test.yaml") + } else if(oftype() == "docx"){ + # Create document from results + message("Not yet implemented...") + } else if(oftype() == "pdf"){ + # Create document from results + message("Not yet implemented...") } } ) diff --git a/R/mod_Glossary.R b/R/mod_Glossary.R index 778b432..9913cfc 100644 --- a/R/mod_Glossary.R +++ b/R/mod_Glossary.R @@ -44,7 +44,7 @@ mod_Glossary_server <- function(id){ package = "ODPSCP", mustWork = TRUE) output$glossary_table <- DT::renderDataTable( - read.csv(ppath, sep = ",",header = TRUE) |> + utils::read.csv(ppath, sep = ",",header = TRUE) |> DT::datatable(filter = "none", rownames = FALSE, editable = FALSE) ) diff --git a/R/mod_Home.R b/R/mod_Home.R index c6c13b6..1ea4aa1 100644 --- a/R/mod_Home.R +++ b/R/mod_Home.R @@ -31,17 +31,15 @@ mod_Home_ui <- function(id){ from a range of scientific disciplines.", style= "font-size: 18px;"), - shiny::p("Area-based and action-based conservation planning are critical scientific - tools in reaching conservation policy objectives across scales. - Yet despite decades of research and numerous scientific advances - in Europe ",shiny::a(href = 'https://osf.io/8x2ug/', '(Jung et al. 2023)', + shiny::p("Area-based and action-based conservation planning are critical + in reaching conservation policy objectives across scales. Yet + despite decades of research and numerous scientific advances + in Europe ",shiny::a(href = 'https://osf.io/8x2ug/', '(Jung et al. 2023)', target = "_blank", .noWS = "outside"),".", - " and globally ",shiny::a(href = 'https://www.annualreviews.org/doi/10.1146/annurev-environ-102016-060902', - '(McIntosh et al. 2017)', - target = "_blank", .noWS = "outside"), - ", it often remains incomprehensible for those unfamiliar with the - planning how decisions where reached or what factors were considered - influential in determining the identified outcomes.", + " and globally ",shiny::a(href = 'https://www.annualreviews.org/doi/10.1146/annurev-environ-102016-060902', '(McIntosh et al. 2017)', target = "_blank", .noWS = "outside"), + ", it often remains incomprehensible for those unfamiliar with the + planning how decisions where reached or what factors were considered + influential in determining the identified outcomes.", style= "font-size: 18px;"), # img(src = "", width = "60%", style="display: block; margin-left: auto; margin-right: auto; @@ -54,7 +52,26 @@ mod_Home_ui <- function(id){ expert evaluation of the conducted planning. Third, it helps study authors and decision makers to identify key strength, but also weaknesses of a systematic planning exercise. ", style= "font-size: 18px;"), - + # --- # + shiny::hr(), + shinyWidgets::prettyCheckboxGroup( + inputId = ns("eligibility"), + label = "In order for a planning study to be eligible for the protocol they should:", + choices = c("Make use of decision theoretic or multiple-criteria-based approaches!", + "Are spatial, spatial-temporal or at least use spatial input!", + "Have a biodiversity and/or conservation focus or angle! *", + "Use an algorithic prioritization to identify best areas or actions! **"), + icon = shiny::icon("thumbs-up"), + status = "primary", + outline = TRUE, + inline = TRUE, + plain = TRUE, + animation = "jelly" + ), + shiny::helpText("* This is not say that non-biodiversity focussed planning studies (such as optimal cropland management allocation) can not be entered per se."),shiny::br(), + shiny::helpText("** Studies presenting methodological advances are not suitable for the protocol, + unless they are demonstrated in an applied scenario."), + shiny::hr(), shiny::p("This Shiny web application helps to implement the protocol through an easy understandable user interface and allows export the created protocols in a range of formats for further usages. We encourage the diff --git a/R/mod_Overview.R b/R/mod_Overview.R index 763a846..1b8000f 100644 --- a/R/mod_Overview.R +++ b/R/mod_Overview.R @@ -23,10 +23,10 @@ mod_Overview_ui <- function(id){ width = 12, solidHeader = FALSE, collapsible = FALSE, - "Let's start with a new reporting protocol. In this first step we describe + "Let's start with a new reporting protocol. In the overview step we describe all the properties of the conducted planning study. The entries below intend to both uniquely identify the study, provide necessary information - on the availability of code or data and broadly categorizes any and all studies + on the availability of code or data and allows to categorizes the study itself based on the listed properties. ", shiny::br(), @@ -61,6 +61,8 @@ mod_Overview_ui <- function(id){ solidHeader = T, status = "secondary", collapsible = TRUE, + shiny::p("Add each author of the study to the table below. If a ORCID is not + known or available, leave blank."), DT::DTOutput(outputId = ns("authors_table")), shiny::actionButton(inputId = ns("add_author"), label = "Add a new author row", icon = shiny::icon("plus")), @@ -77,7 +79,7 @@ mod_Overview_ui <- function(id){ solidHeader = TRUE, status = "secondary", collapsible = FALSE, - shiny::div("Who is the corresponding author?"), + shiny::div("Who is the corresponding author? Here contact information can be added."), shiny::textAreaInput(inputId = ns("authoremail"), label = "", placeholder = 'Email of the corresponding author', height = "45px", width = "100%", resize = "none") @@ -103,7 +105,7 @@ mod_Overview_ui <- function(id){ solidHeader = TRUE, status = "gray", collapsible = FALSE, - shiny::div("Has the study already been published? If so, pprove a reference"), + shiny::div("Has the study already been published? If so, provide a reference."), shiny::textAreaInput(inputId = ns("studylink"), label = "", placeholder = 'Link to the published study such as a DOI.', height = "45px", width = "100%", resize = "none") @@ -147,6 +149,31 @@ mod_Overview_ui <- function(id){ title = "Scale of the conducted study?") ) ), + # Study region + bs4Dash::box( + title = "Study region", + closable = FALSE, + width = 12, + solidHeader = TRUE, + status = "secondary", + collapsible = FALSE, + shiny::div("A geospatial dataset can be provided such as gridded or vector planning unit file. + Accepted are shapefiles, geopackages or geotiffs."), + shiny::hr(), + # Input: Select a file ---- + shiny::fileInput( + ns("studyregion"), + "Choose geospatial File", + multiple = FALSE, + accept = c( + ".shp", ".gpkg", + ".tif", ".geotiff" + ) + ), + shiny::helpText("Note that the maximum file size is 30 MB."), + shiny::br(), + leaflet::leafletOutput(ns("studymap")) + ), # Study location bs4Dash::box( title = "Study location", @@ -169,14 +196,16 @@ mod_Overview_ui <- function(id){ solidHeader = TRUE, status = "secondary", collapsible = FALSE, - shiny::p("Define the temporal scale over which the planning applies. - If outside the chosen scale, please provide details in the textbox."), + shiny::p("Define the temporal scale over which the planning and specifically + the planning objective applies. This should not be interpreted as + a period of data coverage. If outside the chosen scale, + please provide details in the textbox."), shinyWidgets::sliderTextInput( inputId = ns("studytime"), label = "Choose a range:", choices = 1960:2100, grid = TRUE, - selected = seq(2000,2020,1) + selected = seq(1990,2020,1) ), shiny::br(), shiny::textAreaInput(inputId = ns("otherstudytime"), label = "(Optional) Custom coverage", @@ -218,6 +247,10 @@ mod_Overview_ui <- function(id){ collapsed = FALSE, collapsible = TRUE, # icon = icon("magnifying-glass-chart"), + shiny::imageOutput(ns("peng2011"),inline = TRUE,fill = TRUE), + shiny::br(), + shiny::helpText("Source: Peng, R. D. (2011). Reproducible research in computational science. Science, 334(6060), 1226-1227."), + shiny::br(), shiny::p("This box records whether a study makes available the data - both for input and outputs - as well as the software code or analytical to reproduce the analysis."), @@ -252,6 +285,8 @@ mod_Overview_ui <- function(id){ solidHeader = TRUE, status = "gray", collapsible = FALSE, + shiny::p("Typical outputs include for example priority maps or performance indicators. + Describe all outouts here and where they are stored."), shinyWidgets::prettyToggle( inputId = ns('outputavailability'), label_on = "Yes", @@ -269,12 +304,15 @@ mod_Overview_ui <- function(id){ shiny::br(), # Link to code bs4Dash::box( - title = 'Are the analytical steps to reproduce the results made available?', + title = 'Are the analytical code to reproduce the results made available?', closable = FALSE, width = 12, solidHeader = TRUE, status = "gray", collapsible = FALSE, + shiny::p("Preparing data for analysis and creating priority maps can be done + with computer code. If such code was created, consider storing it somewhere + and make it available."), shinyWidgets::prettyToggle( inputId = ns('codeavailability'), label_on = "Yes", @@ -408,6 +446,52 @@ mod_Overview_server <- function(id, results, parentsession){ }) # ----- # + # Reactive studyregion code + myregion <- shiny::eventReactive(input$studyregion, { + if(!is.null(input$studyregion)){ + # Found vector + if(tolower( tools::file_ext(input$studyregion)) %in% c("shp","gpkg")){ + out <- sf::st_read(input$studyregion, quiet = TRUE) |> + sf::st_transform(crs = sf::st_crs(4326)) + return(out) + } else if(tolower( tools::file_ext(input$studyregion)) %in% c("tif","geotiff")){ + out <- terra::rast(input$studyregion) + out[out>0] <- 1 # Replace all with 1 + out <- out |> terra::as.polygons() |> sf::st_as_sf() |> + sf::st_transform(crs = sf::st_crs(4326)) + return(out) + } + } + }, ignoreNULL = FALSE) + + # Study region leaflet code + output$studymap <- leaflet::renderLeaflet({ + # generate base leaflet + map <- leaflet::leaflet(options = leaflet::leafletOptions(zoomControl = FALSE)) |> + leaflet::addTiles(leaflet::providers$OpenStreetMap) |> + leaflet::addProviderTiles(leaflet::providers$OpenStreetMap, + group="Open Street Map") + map + }) + + # ----- # + # Send a pre-rendered image, and don't delete the image after sending it + output$peng2011 <- shiny::renderImage({ + path_figure <- base::normalizePath( + system.file("Peng2011_Science_spectrum.png", + package = "ODPSCP", + mustWork = TRUE) + ) + # Return a list containing the filename and alt text + list(src = path_figure, + width = "80%", + height = "50%", + alt = paste("Peng 2011, Reproducible Research in Computational Science, Science")) + + }, deleteFile = FALSE) + + # ----- # + # Shiny feedback for mandatory fields # FIXME: This horribly messes up the format # shiny::observeEvent(input$studyname, { diff --git a/R/mod_Prioritization.R b/R/mod_Prioritization.R index e8dd7f5..f4733b8 100644 --- a/R/mod_Prioritization.R +++ b/R/mod_Prioritization.R @@ -46,8 +46,9 @@ mod_Prioritization_ui <- function(id){ collapsible = TRUE, shiny::p("There are multiple existing types of software that allow users to integrate various features, constraints - and targets in a single prioritization. The most - commonly used SCP software solutions are listed below."), + and targets in a single prioritization. Some make use of mathematical + optimization, others of heuristics or multi-criteria ranking approaches. + Some of the most commonly used SCP software solutions are listed below."), shinyWidgets::pickerInput( inputId = ns("software"), label = "Used software", @@ -59,7 +60,9 @@ mod_Prioritization_ui <- function(id){ options = list( style = "btn-info") ), - #TODO: Show some explanation / reference for each method + # Small + shiny::textOutput(outputId = ns("software_help"),inline = TRUE), + shiny::br(), # upon selection. shiny::conditionalPanel( condition = "input.software == 'Custom' || input.software == 'Other'", @@ -92,12 +95,11 @@ mod_Prioritization_ui <- function(id){ collapsible = FALSE, shiny::p("In many optimizations benefits can accrue in varying ways, for example through maximizing the targets achieved. If known or specific to the study, - provide information on benefit function used."), - shiny::p("Benefit functions in prioritizations are for example those minimize marginal + provide information on benefit function used.", + "Benefit functions in prioritizations are for example those minimize marginal losses from cell removal, minimize an average shortfall or maximize the number - of targets (a constraint) achieved. - - Reference: Arponen, A., Heikkinen, R. K., Thomas, C. D., & Moilanen, A. (2005). The value of biodiversity in reserve selection: representation, species weighting, and benefit functions. Conservation Biology, 19(6), 2009-2014."), + of targets (a constraint) achieved."), + shiny::p("Reference: Arponen, A., Heikkinen, R. K., Thomas, C. D., & Moilanen, A. (2005). The value of biodiversity in reserve selection: representation, species weighting, and benefit functions. Conservation Biology, 19(6), 2009-2014."), shiny::textAreaInput(inputId = ns("benefitfunctions"), label = "What is being optimized and how?", placeholder = 'If known, please provide further detail.', height = "60px", width = "100%", resize = "vertical") @@ -135,7 +137,7 @@ mod_Prioritization_ui <- function(id){ shinyWidgets::pickerInput( inputId = ns("identsolution"), label = "Identification of priorities", - choices = c("Single solution", + choices = c("","Single solution", "Selection frequency", "Overlays", "External indicator", @@ -249,15 +251,39 @@ mod_Prioritization_server <- function(id, results, parentsession){ indicators <- shiny::reactiveVal( data.frame(name = character(0), description = character(0), - unit = character(0), - reference = character(0)) + unit = character(0)) ) + # --- # + # Render some explanatory help for the software box + shiny::observeEvent(input$software, { + if(input$software!= ""){ + tt <- switch(input$software, + "Zonation" = "Zonation is a spatial prioritization software that can be used to identify priority areas to support conservation planning, land use planning, ecological impact avoidance and other similar tasks. https://zonationteam.github.io/Zonation5/", + "Marxan" = "Marxan is a suite of tools designed to help decision makers find good solutions to conservation planning problems. https://marxansolutions.org/", + "prioritizr" = "The prioritizr R package uses mixed integer linear programming (MILP) techniques to provide a flexible interface for building and solving conservation planning problems. https://prioritizr.net/", + "prioriactions" = "The prioriactions package allows you to create and solve conservation planning problems that involve multiple threats and actions using techniques of integer linear programming (ILP). https://prioriactions.github.io/prioriactions/", + "RestOptr" = "The restoptr R package provides a flexible framework for ecological restoration planning using using mathematical optimization and landscape ecology theory. https://dimitri-justeau.github.io/restoptr/", + "oppr" = "The oppr R package is decision support tool for prioritizing conservation projects in terms of funding and monitoring. https://prioritizr.github.io/oppr/", + "ConsNet" = "ConsNet is a comprehensive software package for decision support for the design of conservation area networks to represent biodiversity features while incorporating a wide range of spatial and other criteria. https://doi.org/10.1111/j.1600-0587.2008.05721.x", + "CAPTAIN" = "Software for conservation prioritization using reinforcement learning with the capacity to use most type of available data and resources. https://www.captain-project.net/", + "ROOT" = "ROOT is tool designed to facilitate multi-objective landscape planning. It uses an optimization approach to help identify opportunities to maximize cobenefits and to identify compromise solutions where required. https://natcap.github.io/ROOT/", + "C-PLAN" = "C-Plan is a conservation decision support software that links with GIS to map options for achieving explicit conservation targets. https://github.com/mattwatts/cplan", + "Custom" = "This option is for planning studies that created their own customized software or code to achieve their solutions.", + "Other" = "Any other software solution not listed among the options here (explain in fields below)." + ) + output$software_help <- shiny::renderText(tt) + } else { + output$software_help <- shiny::renderText("") + } + }) + # --- # + # Events for author table shiny::observeEvent(input$add_indicator, { new_data <- indicators() |> dplyr::add_row( data.frame(name = "EDIT ME", description = "EDIT ME", - unit = "EDIT ME", reference = "EDIT ME") + unit = "EDIT ME") ) indicators(new_data) }) diff --git a/R/mod_Specification.R b/R/mod_Specification.R index a0047c5..f278f2f 100644 --- a/R/mod_Specification.R +++ b/R/mod_Specification.R @@ -26,7 +26,9 @@ mod_Specification_ui <- function(id){ shiny::p("Under the protocol entry 'Specification' we list all the elements, features and datasets that are being used in the planning. Basic information on their broad categorization, - type and origin are recorded.") + type and origin are recorded. + It records what type of information is included in the planning, + not how individual information sources are used (for that see context).") ) ) ), @@ -46,8 +48,7 @@ mod_Specification_ui <- function(id){ shiny::p("The principal elements of a SCP application are generally called 'Planning units'. They can be for example based on a gridded Raster layer or any spatial organization such as - a polygon. There could also be no planning units for SCP - applications that are non-spatial."), + a polygon. "), shiny::br(), # Planning unit type bs4Dash::box( @@ -61,7 +62,7 @@ mod_Specification_ui <- function(id){ inputId = ns("pu_type"), label = "Type of planning unit", choices = c( - "None", "Gridded", + "Gridded", "Point", "Line", "Regular Polygon (e.g. rectangle)", "Irregular Polygon (e.g. hyrological basin)", @@ -94,8 +95,8 @@ mod_Specification_ui <- function(id){ shiny::selectizeInput(inputId = ns("pu_grainunit"), label = "Unit of the spatial grain", choices = c("", - "m²","km²", "ha", - "ft²", "yd²","mi²", + "m2","km2", "ha", + "ft2", "yd2","mi2", "acre" ), multiple = FALSE, @@ -220,9 +221,9 @@ mod_Specification_ui <- function(id){ shiny::p("Describe the zones used in the planning. Zones can be useful to prioritize for not a single, but a set of management decisions. For example, protected area managers might want to identify areas of minimal intervention ('core-areas') - as well as sustainable use areas. - Reference: Watts, Matthew E., Ian R. Ball, Romola S. Stewart, Carissa J. Klein, Kerrie Wilson, Charles Steinback, Reinaldo Lourival, Lindsay Kircher, and Hugh P. Possingham. Marxan with Zones: Software for Optimal Conservation Based Land- and Sea-Use Zoning. Environmental Modelling & Software 24, no. 12 (December 2009): 1513–21. https://doi.org/10.1016/j.envsoft.2009.06.005. -"), + as well as sustainable use areas."), + shiny::p("Reference: Watts, Matthew E., Ian R. Ball, Romola S. Stewart, Carissa J. Klein, Kerrie Wilson, Charles Steinback, Reinaldo Lourival, Lindsay Kircher, and Hugh P. Possingham. Marxan with Zones: Software for Optimal Conservation Based Land- and Sea-Use Zoning. Environmental Modelling & Software 24, no. 12 (December 2009): 1513-21. https://doi.org/10.1016/j.envsoft.2009.06.005."), + DT::DTOutput(outputId = ns("specificzones")), shiny::actionButton(inputId = ns("add_zone"), label = "Add a new zone", icon = shiny::icon("plus")), @@ -350,6 +351,8 @@ mod_Specification_ui <- function(id){ solidHeader = T, status = "secondary", collapsible = TRUE, + shiny::p("List all features used in the planning, their type and an approximate number. + Where possible assign groupings based on the Feature types above."), DT::DTOutput(outputId = ns("featurelist")), shiny::actionButton(inputId = ns("add_feature"), label = "Add a new feature row", icon = shiny::icon("plus")), @@ -357,12 +360,12 @@ mod_Specification_ui <- function(id){ icon = shiny::icon("minus")), shiny::fileInput(inputId = ns('load_feature'),label = 'Alternatively upload a feature/group list:', accept = c('csv', 'comma-separated-values','.csv', 'tsv', '.tsv')), - shiny::p("(Doubleclick on an added row to change the input values)") + shiny::helpText("(Doubleclick on an added row to change the input values)") ), shiny::br(), # How were features created? bs4Dash::box( - title = "How were features created?", + title = "How were features created and what do they contain?", closable = FALSE, width = 12, solidHeader = TRUE, @@ -439,13 +442,14 @@ mod_Specification_server <- function(id, results, parentsession){ # Define the features list feature_table <- shiny::reactiveVal( data.frame(name = character(0), - group = character(0)) + group = character(0), + number = numeric(0)) ) # Events for author table shiny::observeEvent(input$add_feature, { new_data <- feature_table() |> dplyr::add_row( - data.frame(name = "My species", group = "Species distribution") + data.frame(name = "Feature name", group = "Species distribution", number = 10) ) feature_table(new_data) }) diff --git a/R/utils_load_protocol.R b/R/utils_load_protocol.R index dfceb6a..2ae279b 100644 --- a/R/utils_load_protocol.R +++ b/R/utils_load_protocol.R @@ -97,3 +97,28 @@ get_protocol_elementgroup <- function(id, path_protocol = NULL){ return(out) } + +#' Check for mandatory fields to be filled +#' +#' @description +#' Small convenience function that checks for mandatory fields +#' +#' @param protocol A filled out protocol in [`list`] format. +#' @returns A [`vector`] of character entries that are mandatory in the protocol. +#' @noRd +get_protocol_mandatory <- function(path_protocol = NULL){ + assertthat::assert_that(is.character(path_protocol) || is.null(path_protocol)) + + # If is null, load protocol + template <- load_protocol(path_protocol) + + results <- vector() + for(gr in names(template)[-1]){ + pp <- template[[gr]] + for(element in names(pp)){ + ppp <- pp[[element]] + if(ppp$mandatory) results <- append(results,values = ppp[['render-id']] ) + } + } + return(results) +} diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..bc3a647 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,19 @@ +# Create new package environment +# .pkgenv <- new.env(parent = emptyenv()) + +# For unloading a package +.onUnload <- function(libpath) {} + +# What to do on attaching the package +.onAttach <- function(libname, pkgname) { + # packageStartupMessage("############################") + # packageStartupMessage("Loading OPSCP package ...") + # packageStartupMessage("############################") + + # Don't show constant rgdal warning + options("rgdal_show_exportToProj4_warnings" = "none") + + # Increase maximum upload size + options(shiny.maxRequestSize = 30*1024^2) +} + diff --git a/README.Rmd b/README.Rmd index 90f7fa2..42b6b90 100644 --- a/README.Rmd +++ b/README.Rmd @@ -31,7 +31,7 @@ individual elements (Overview, Design, Specification, Context, Prioritization). The protocol follows other reporting framework such [ODMAP](https://onlinelibrary.wiley.com/doi/10.1111/ecog.04960) or [ODD](https://www.jasss.org/23/2/7.html). This repository contains the shiny app behind the package and can be visualized -on [INSERT] where it will remain hosted. +on [https://odpscp.iiasa.ac.at/](https://odpscp.iiasa.ac.at/) where it will remain hosted. The code has been created with the help of the *golem* framework for production- ready shiny interfaces. Further versions of the framework are planned. diff --git a/README.md b/README.md index 38a612b..0583675 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,10 @@ other reporting framework such [ODD](https://www.jasss.org/23/2/7.html). This repository contains the shiny app behind the package and can be -visualized on \[INSERT\] where it will remain hosted. The code has been -created with the help of the *golem* framework for production- ready -shiny interfaces. Further versions of the framework are planned. +visualized on where it will remain hosted. +The code has been created with the help of the *golem* framework for +production- ready shiny interfaces. Further versions of the framework +are planned. Please note that the ODPSCP project is released with a [Contributor Code of diff --git a/inst/01_protocol.yaml b/inst/01_protocol.yaml index ce0a26b..c30286c 100644 --- a/inst/01_protocol.yaml +++ b/inst/01_protocol.yaml @@ -74,19 +74,31 @@ overview: mandatory: true popexample: "Local, for a study identified priority regions in sub-national area." - location: + studyregion: render-nr: 2 + render-id: 'studyregion' + render-group: 'study_location' + question: 'If available, provide a geospatial delineation of the study region.' + description: 'A geospatial dataset can be provided such as gridded or vector planning unit file. Note that the maximum file size is 30 MB.' + fieldtype: 'fileupload' + fieldtype_conditional_render-id: 'studymap' + fieldtype_conditional: 'leaflet' + mandatory: false + popexample: "Upload for example a shp file of the study area." + + location: + render-nr: 3 render-id: 'studylocation' render-group: 'study_location' question: 'What is the location of the study?' description: 'Add text description of the study location.' fieldtype: 'textbox' - mandatory: false + mandatory: true popexample: "The study was conducted in the state of Burgenland, Austria, focussing on the surroundings of Lake Neusiedl." studytimeline: - render-nr: 3 + render-nr: 4 render-id: 'studytime' render-group: 'study_location' question: 'What is the temporal range of the study?' @@ -95,10 +107,11 @@ overview: fieldtype_conditional_render-id: 'otherstudytime' fieldtype_conditional: 'textbox' mandatory: false - popexample: "The study objective addresses the time period from 2000 to 2020." + popexample: "The study uses data from the period 2015-2020 in order to make + recommendations for potential protected area network in 2030. The time period is thus 2015-2030." realm: - render-nr: 4 + render-nr: 5 render-id: 'studyrealm' render-group: 'study_location' question: 'What is the biophysical realm in which the planning work was conducted?' @@ -199,6 +212,7 @@ design: fieldtype: 'selectizedropdown' options: - Area-based allocation + - Management evaluation - Management improvement - Action-based planning - Monitoring and evaluation @@ -289,7 +303,6 @@ specification: description: 'Describe the type of planning units used in this work.' fieldtype: 'dropdown' options: - - None - Gridded - Point - Line @@ -322,12 +335,12 @@ specification: description: 'Leave empty if not applicable.' fieldtype: 'selectizedropdown' options: - - m² - - km² + - m2 + - km2 - ha - - ft², - - yd², - - mi² + - ft2, + - yd2, + - mi2 - acre mandatory: false popexample: "Each planning unit had a size of 1000 m²." @@ -439,7 +452,7 @@ specification: description: 'Add the features to the list.' fieldtype: 'multifieldselection' mandatory: false - popexample: "Specify groups of features, e.g. 100 species distributions layers." + popexample: "Threatened plant species, Species (distributions), 260" featureorigin: render-nr: 4 diff --git a/inst/Peng2011_Science_spectrum.png b/inst/Peng2011_Science_spectrum.png new file mode 100644 index 0000000..c3a2a9d Binary files /dev/null and b/inst/Peng2011_Science_spectrum.png differ diff --git a/man/ODPSCP.Rd b/man/ODPSCP.Rd new file mode 100644 index 0000000..37c7d50 --- /dev/null +++ b/man/ODPSCP.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ODPSCP-package.R +\docType{package} +\name{ODPSCP} +\alias{ODPSCP-package} +\alias{ODPSCP} +\title{ODPSCP} +\description{ +The ODPSCP shiny interface comes in a series of UI and server plus helper functions +that support the standardized reporting of prioritization results. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/iiasa/ODPSCP} + \item Report bugs at \url{https://github.com/iiasa/ODPSCP/issues} +} + +} +\author{ +\strong{Maintainer}: Martin Jung \email{jung@iiasa.ac.at} + +} +\keyword{internal}