The goal of polr is to provide bindings to the OpenLayers javascript library, with a focus on polar mapping applications.
remotes::install_github("SCAR/polr")
## or
install.packages("polr", repos = c("https://scar.r-universe.dev", "https://cloud.r-project.org"))
library(polr)
library(shiny)
ui <- fluidPage(
polOutput("map", height = "80vh", width = "100%"),
actionButton("add_cog", "Add COG"),
actionButton("remove_cog", "Remove COG", disabled = TRUE)
)
server <- function(input, output, session) {
output$map <- renderPol({
polr::pol(view_options = list(extent = 6e6 * c(-1, -1, 1, 1))) %>%
## add a layer from a WMS server
add_wms_tiles(url = "https://geos.polarview.aq/geoserver/wms",
layers = "polarview:coastS10") %>%
## add lines from a local file in flatgeobuf format
add_fgb(file = system.file("extdata/fronts_park.fgb", package = "polr"),
style = list(`stroke-color` = "black"), zIndex = 99)
})
## dynamically update the map
prox <- pol_proxy("map")
observeEvent(input$add_cog, {
## when the button is clicked, add a COG (cloud-optimised geotiff)
prox %>% add_cog(
"https://data.source.coop/scar/distant/hindell_et_al-2020/Hi2023-aes_colony_weighted_cog.tif",
geotiff_source_options = list(interpolate = FALSE), opacity = 0.7,
style = list(color = pol_colormap(hcl.colors(21, "Spectral", rev = TRUE))),
name = "COG layer")
updateActionButton(session, inputId = "add_cog", disabled = TRUE) ## can't add twice
updateActionButton(session, inputId = "remove_cog", disabled = FALSE) ## but we can now remove it
})
observeEvent(input$remove_cog, {
prox %>% remove_layer("COG layer")
updateActionButton(session, inputId = "add_cog", disabled = FALSE)
updateActionButton(session, inputId = "remove_cog", disabled = TRUE)
})
}
shinyApp(ui = ui, server = server)

library(htmltools)
library(lorem)
## random text formatted as HTML for popups
px <- sapply(1:100, function(i) as.character(tags$div(tags$h1(ipsum_words(3)), ipsum_words(5))))
polr::pol(view_options = list(extent = 6e6 * c(-1, -1, 1, 1))) %>%
## background layer
add_wmts_from_capabilities("https://services.arcgisonline.com/arcgis/rest/services/Polar/Antarctic_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml",
layer = "Polar_Antarctic_Imagery", zIndex = -1) %>%
## WMS coastline layer in polar stereographic projection
add_wms_tiles(url = "https://geos.polarview.aq/geoserver/wms", layers = "polarview:coastS10",
name = "Coastline") %>%
## local geojson lines file
add_geojson(file = system.file("extdata/fronts_park.geojson", package = "polr"),
style = pol_style(stroke = list(color = "green")), data_proj = "EPSG:4326",
name = "Fronts") %>%
## markers, shown as clusters
add_clustered_points(lon = (runif(100) - 0.5) * 360, lat = runif(100) * -40 - 40,
cluster_options = list(distance = 50),
cluster_style = pol_style(text = list(fill = list(color = "blue")),
circle = list(fill = list(color = "orange"))),
marker_style = pol_style(text = list(text = "\uf041",
font = "normal 18px FontAwesome",
fill = list(color = "#00f"))),
popup = px, name = "Markers") %>%
## add a legend that allows layers to be turned on and off
add_layer_switcher()
OpenLayers is quite forgiving when it comes to projections: layers will typically be reprojected automatically to the map projection. That means that you can add a layer in longitude-latitude coordinates to a polar-projected map, and the layer will be reprojected as required. However, be aware that you might still encounter issues:
interpolation artifacts around the anti-meridian (e.g. when adding WMS tiles in long-lat coordinates)
some functions also expect inputs to be in longitude and latitude
(e.g. add_points)
or encourage you to specify the projection (because it can’t always
automatically be deduced, e.g. add_geojson).
polr provides bindings to the OpenLayers
javascript library, and uses the excellent packer package to
facilitate the interactions between R and javascript.
Some notes:
the majority of the package functionality is achieved with short R
functions that expose the underlying OpenLayers functions. The R
functions are found in the R/ directory that will be familiar to R
package developers. The corresponding javascript is in
srcjs/widgets/pol.js
packer::npm_install("node-package-name", scope = "prod") will add a
new javascript (node) package dependency to the project
packer::bundle() will run the webpack process that builds the
javascript files for deployment (these get saved in
inst/htmlwidgets). Note that we have modified the
webpack.common.js with the chunkFormat: false directive: this
causes all the javascript to be saved in one file rather than spread
across file chunks. This is less efficient but polr widgets in
rmarkdown did not work with chunking (there is probably a better way
to solve this …)
See https://book.javascript-for-r.com/packer-adv and
https://github.com/JohnCoene/packer for more information about
packer.