Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/evamaerey/ggnaturalearth
putting ne geometries in geoms - a test of ggnorthcarolina template repo
https://github.com/evamaerey/ggnaturalearth
Last synced: 11 days ago
JSON representation
putting ne geometries in geoms - a test of ggnorthcarolina template repo
- Host: GitHub
- URL: https://github.com/evamaerey/ggnaturalearth
- Owner: EvaMaeRey
- License: other
- Created: 2023-12-18T15:31:37.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2023-12-18T16:51:49.000Z (11 months ago)
- Last Synced: 2023-12-18T19:42:14.961Z (11 months ago)
- Language: R
- Size: 10.2 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
- License: LICENSE
Awesome Lists containing this project
README
---
output:
github_document:
toc: TRUE
---```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "50%"
)
options(tidyverse.quiet = TRUE)package_exists <- T
print_reports <- F
build_package <- T
build_package_w_readme <- Tprint_reports_action <- ifelse(print_reports, "asis", "hide")
```# {ggnaturalearth}
ggnaturalearth is a test of the ggnorthcarolina repo for use as a template repo.
ggnaturalearth allows you to create informative world maps a flat tabular data file. i.e. a file that has the country id in columns as well as characteristics about the countries to be represented by fill color for example.
## Installation
You can install the development version of ggnaturalearth from [GitHub](https://github.com/) with:
``` r
# install.packages("devtools")
devtools::install_github("EvaMaeRey/ggnaturalearth")
```## example: World choropleth made easy
Country characteristics data, and wanting to map that data, but not having experience with boundary files or just not wanting to think about joins to use a geom_sf() layer.
```{r example, eval = T}
library(tidyverse)
library(gapminder)
library(ggnaturalearth)gapminder |>
filter(year == 2002) %>%
ggplot() +
aes(country_name = country) +
geom_country()last_plot() +
aes(fill = gdpPercap)
```And here is the input dataset, which is indeed just a tabular, flat dataset. It has no boundary information
```{r}
library(gapminder)
gapminder
```By declaring the aesthetic fips, the geom_ function joins the flat file to boundary data and an SF layer is plotted.
## example with labels.
Furthermore, we also make labeling these polygons easy:
```{r, eval = T}
library(tidyverse)
gapminder |>
filter(year == 2002) %>%
ggplot() +
aes(country_name = country) +
geom_country() +
geom_country_label(aes(label = country),
check_overlap = T,
size = 2)ggwipe::last_plot_wipe_last() +
geom_country_label(aes(label = country),
lineheight = .8,
size = 2,
check_overlap = TRUE,
color = "grey35")
```# How we built this functionality
The second-order goal of ggnorthcarolina is to serve as a model and template for other ggplot-based geography-specific convenience mapping packages. Because of this, and because the package is generally new and could use other sets of eyes on pretty much every decision, I'm using a literate programming paradigm to write a narrative for this package.
## Step 000. Find an appropriate shape file
A prerequisite to embarking on the following journey is that you have geographic data that you'd like to connect up to a flat file for mapping within ggplot2. In our case, for convenience, we use nc.shp provided in the sf package. You'll see that file read in as an sf object later with the following code.
Such a shape file can live in the data-raw folder, or can be accessed from another package:
```
st_read(system.file("shape/nc.shp", package="sf"))
```## Step 00. Build the map with base ggplot2 and geom_sf
This doesn't show all the pain that you will actually be in if you want to create a choropleth. Because we are working with an object that already has geometries as a list-column. If you were working with a flat file (which is the imagined )
```{r}
library(tidyverse)
rnaturalearth::ne_countries(
scale = "medium", returnclass = "sf") %>%
select(name, continent, geometry) %>%
rename(country_name = name) ->
id_and_boundariesgapminder %>%
rename(country_name = country) |>
dplyr::full_join(id_and_boundaries, by = "country_name") |>
ggplot() +
geom_sf(aes(geometry = geometry)) + # why am I doing aes here. Surprisingly this didn't work
aes(fill = (gdpPercap / 1000) %>% round(1))
```# Step 0. Prepare reference datasets.
The functions that you create in the R folder will use data that is prepared in the ./data-raw/DATASET.R file. Let's have a look at the contents of that file to get a sense of the preparation. Functions in the {ggnc} package will help you prepare the reference data that is required. Keep an eye out for `ggnc::create_geometries_reference()` and `ggnc::prepare_polygon_labeling_data()`.
ggnc is available on git hub as shown:
```{r eval=FALSE}
remotes::install_github("EvaMaeRey/ggnc")
```## 0.i geographic dataset collection/preparation
```{r DATASET, eval=TRUE}
## code to prepare `DATASET` dataset goes here###### 00. Read in boundaries shape file data ###########
library(sf)
ne_countries_sf <- rnaturalearth::ne_countries(
scale = "medium", returnclass = "sf") %>%
select(name, continent, geometry) %>%
rename(country_name = name)####### 0. create and save flat file for examples, if desired ####
# ne_countries_sf %>%
# sf::st_drop_geometry() ->
# ne_countries_flat# usethis::use_data(northcarolina_county_flat, overwrite = TRUE)
#### 1, create boundaries reference dataframe w xmin, ymin, xmax and ymax and save
ne_countries_reference <- ne_countries_sf |>
ggnc::create_geometries_reference(
id_cols = c(country_name))usethis::use_data(ne_countries_reference, overwrite = TRUE)
############### 2. create polygon centers and labels reference data frame
# county centers for labeling polygons
ne_country_centers <- ne_countries_reference |>
ggnc::prepare_polygon_labeling_data(id_cols = c(country_name))usethis::use_data(ne_country_centers, overwrite = TRUE)
####### 3. create line data
# tigris::primary_secondary_roads("NC") -> nc_roads
# usethis::use_data(nc_roads, overwrite = TRUE)
```
Here are a few rows of each dataset that's created
```{r}
ne_countries_reference %>% head()
ne_country_centers %>% head()
```## 0.ii dataset documentation
Now you'll also want to document that data. Minimal documentation is just to quote the object that should be included in your package.
But `northcarolina_county_sf` has template text to show you how to document this more correctly (I haven't change out the WHO example I got elsewhere.)
```{r data}
#' World Health Organization TB data
#'
#' A subset of data from the World Health Organization Global Tuberculosis
#' Report ...
#'
#' @format ## `who`
#' A data frame with 7,240 rows and 60 columns:
#' \describe{
#' \item{country}{Country name}
#' \item{iso2, iso3}{2 & 3 letter ISO country codes}
#' \item{year}{Year}
#' ...
#' }
#' @source
"ne_countries_reference"#' World Health Organization TB data
#'
#' A subset of data from the World Health Organization Global Tuberculosis
#' Report ...
#'
#' @format ## `who`
#' A data frame with 7,240 rows and 60 columns:
#' \describe{
#' \item{country}{Country name}
#' \item{iso2, iso3}{2 & 3 letter ISO country codes}
#' \item{year}{Year}
#' ...
#' }
#' @source
"ne_country_centers"
```# Write functions w/ 'recipe' substeps: 1. write compute function; 2. define ggproto; 3. write geom_*; 4. test.
## Write `geom_country()` (polygon)
```{r geom_country}
################# Step 1. Compute panel function ############' Title
#'
#' @param data
#' @param scales
#' @param keep_country
#'
#' @return
#' @export
#'
#' @examples
#' library(dplyr)
#' #northcarolina_flat |> rename(fips = FIPS) |> compute_country_northcarolina() |> head()
#' #northcarolina_flat |> rename(fips = FIPS) |> compute_country_northcarolina(keep_country = "Ashe")
compute_country_ne <- function(data, scales, keep_country = NULL){reference_filtered <- ne_countries_reference
#
if(!is.null(keep_country)){keep_country %>% tolower() -> keep_country
reference_filtered %>%
dplyr::filter(.data$country_name %>%
tolower() %in%
keep_country) ->
reference_filtered}
#
# # to prevent overjoining
# reference_filtered %>%
# dplyr::select("fips", # id columns
# "geometry",
# "xmin","xmax",
# "ymin", "ymax") ->
# reference_filtereddata %>%
dplyr::inner_join(reference_filtered) #%>% # , by = join_by(fips)
# dplyr::mutate(group = -1) %>%
# dplyr::select(-fips) #%>%
# sf::st_as_sf() %>%
# sf::st_transform(crs = 5070)}
###### Step 2. Specify ggproto ###############
StatCountryne <- ggplot2::ggproto(
`_class` = "StatCountryne",
`_inherit` = ggplot2::Stat,
compute_panel = compute_country_ne,
default_aes = ggplot2::aes(geometry = ggplot2::after_stat(geometry)))########### Step 3. geom function, inherits from sf ##################
#' Title
#'
#' @param mapping
#' @param data
#' @param position
#' @param na.rm
#' @param show.legend
#' @param inherit.aes
#' @param ...
#'
#' @return
#' @export
#'
#' @examples
geom_country <- function(
mapping = NULL,
data = NULL,
position = "identity",
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE,
crs = "NAD27", # "NAD27", 5070, "WGS84", "NAD83", 4326 , 3857
...) {
c(ggplot2::layer_sf(
stat = StatCountryne, # proto object from step 2
geom = ggplot2::GeomSf, # inherit other behavior
data = data,
mapping = mapping,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = rlang::list2(na.rm = na.rm, ...)),
coord_sf(crs = crs,
default_crs = sf::st_crs(crs),
datum = crs,
default = TRUE)
)
}
``````{r}
library(ggplot2)
gapminder %>%
filter(year == 1952) %>%
ggplot() +
aes(country_name = country, fill = gdpPercap) +
geom_country() +
scale_fill_viridis_c()last_plot()-> p
p$coordinates$crs <- 4326
p
```## Write `geom_country_labels()` (polygon center)
```{r geom_country_labels}
################# Step 1. Compute panel function ###########
#' Title
#'
#' @param data
#' @param scales
#' @param keep_country
#'
#' @return
#' @export
#'
#' @examples
compute_panel_country_centers <- function(data,
scales,
keep_country = NULL){ne_country_centers_filtered <- ne_country_centers
if(!is.null(keep_country)){
keep_country %>% tolower() -> keep_countryne_country_centers_filtered %>%
dplyr::filter(.data$country_name %>%
tolower() %in%
keep_country) ->
ne_country_centers_filtered}data %>%
dplyr::inner_join(ne_country_centers_filtered) %>%
dplyr::select(x, y, label)}
###### Step 2. Specify ggproto ###############
StatCountrycenters <- ggplot2::ggproto(
`_class` = "StatCountrycenters",
`_inherit` = ggplot2::Stat,
# required_aes = c("label"), # for some reason this breaks things... why?
compute_panel = compute_panel_country_centers
)########### Step 3. 'stamp' function, inherits from sf ##################
#' Title
#'
#' @param mapping
#' @param data
#' @param position
#' @param na.rm
#' @param show.legend
#' @param inherit.aes
#' @param ...
#'
#' @return
#' @export
#'
#' @examples
geom_country_label <- function(
mapping = NULL,
data = NULL,
position = "identity",
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE, ...) {
ggplot2::layer(
stat = StatCountrycenters, # proto object from Step 2
geom = ggplot2::GeomText, # inherit other behavior
data = data,
mapping = mapping,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(na.rm = na.rm, ...)
)
}
``````{r, eval = F}
gapminder |>
dplyr::rename(label = country) |>
compute_panel_country_centers(keep_country = NULL) |>
head()
``````{r}
library(ggplot2)
gapminder %>%
filter(year == 1952) %>%
ggplot() +
aes(country_name = country, label = country) +
geom_country_label()gapminder %>%
filter(year == 1952) %>%
ggplot() +
aes(country_name = country, fill = pop, label = country) +
geom_country() +
geom_country_label(lineheight = .7,
size = 2, check_overlap= TRUE,
color = "oldlace")
```## Write `stamp_roads()` (or roads) **Placeholder**
```{r stamp_roads}
# #' Title
# #'
# #' @param data
# #' @param ...
# #'
# #' @return
# #' @export
# #'
# #' @examples
# stamp_roads <- function(data = nc_roads, fill = NULL, fips = NULL, ...){
#
# geom_sf(data = data, aes(fill = fill, fips = fips), ...)
#
# }
#
#
#
# # # have to combine... ugh...
# # tigris::area_water("NC", country = 'Alleghany')
# # nc_water
```### test it out
```{r, eval = T}
# ggplot() +
# stamp_roads()
```## Write `stamp_country()` (render polygons w/o data)
```{r stamp_country}
# overthinking it below.
stamp_country <- function(data = ne_countries_reference, fill = NULL, fips = NULL){
geom_sf(data = data,
aes(geometry = geometry, fill = fill, fips = fips))
}# ################# Step 1. Compute panel function ###########
#
# #' Title
# #'
# #' @param data
# #' @param scales
# #' @param country
# #'
# #' @return
# #' @export
# #'
# #' @examples
# #' library(dplyr)
# #' #northcarolina_flat |> rename(fips = FIPS) |> compute_country_northcarolina() |> head() |> str()
# #' #northcarolina_flat |> rename(fips = FIPS) |> compute_country_northcarolina(keep_country = "Ashe")
# compute_country_northcarolina_stamp <- function(data, scales, keep_country = NULL){
#
# reference_filtered <- northcarolina_country_reference
# #
# if(!is.null(keep_country)){
#
# keep_country %>% tolower() -> keep_country
#
# reference_filtered %>%
# dplyr::filter(.data$country_name %>%
# tolower() %in%
# keep_country) ->
# reference_filtered
#
# }
#
# reference_filtered %>%
# dplyr::select("fips", "geometry", "xmin",
# "xmax", "ymin", "ymax") ->
# reference_filtered
#
#
# reference_filtered %>%
# dplyr::mutate(group = -1) %>%
# dplyr::select(-fips)
#
# }
#
# ###### Step 2. Specify ggproto ###############
#
#
# Statcountrynorthcarolinastamp <- ggplot2::ggproto(`_class` = "Statcountrynorthcarolinastamp",
# `_inherit` = ggplot2::Stat,
# compute_panel = compute_country_northcarolina_stamp,
# default_aes = ggplot2::aes(geometry =
# ggplot2::after_stat(geometry)))
#
#
#
# ########### Step 3. 'stamp' function, inherits from sf ##################
#
# #' Title
# #'
# #' @param mapping
# #' @param data
# #' @param position
# #' @param na.rm
# #' @param show.legend
# #' @param inherit.aes
# #' @param ...
# #'
# #' @return
# #' @export
# #'
# #' @examples
# stamp_country <- function(
# mapping = NULL,
# data = reference_full,
# position = "identity",
# na.rm = FALSE,
# show.legend = NA,
# inherit.aes = TRUE,
# crs = "NAD27", #WGS84, NAD83
# ...
# ) {
#
# c(ggplot2::layer_sf(
# stat = Statcountrynorthcarolinastamp, # proto object from step 2
# geom = ggplot2::GeomSf, # inherit other behavior
# data = data,
# mapping = mapping,
# position = position,
# show.legend = show.legend,
# inherit.aes = inherit.aes,
# params = rlang::list2(na.rm = na.rm, ...)),
# coord_sf(crs = crs,
# # default_crs = sf::st_crs(crs),
# # datum = sf::st_crs(crs),
# default = TRUE)
# )
#
# }```
```{r}
ggplot() +
stamp_country()
``````{r, echo = F}
if(!build_package_w_readme){knitr::knit_exit()}
```# Part 2. Packaging and documentation 🚧 ✅
## minimal requirements for github package. Have you:
### Created files for package archetecture with `devtools::create("./ggbarlabs")` ✅
### Moved functions R folder? ✅
```{r}
library(readme2pkg)
chunk_to_dir("DATASET", dir = "data-raw")
chunk_to_r("data")
chunk_to_r("geom_country")
chunk_to_r("geom_country_labels")
chunk_to_r("stamp_country")
```### Added roxygen skeleton? ✅
for auto documentation and making sure proposed functions are *exported*
### Managed dependencies ? ✅
package dependencies managed, i.e. `depend::function()` in proposed functions and declared in the DESCRIPTION
### Chosen a license? ✅
```{r, eval = F}
usethis::use_package("ggplot2")
usethis::use_mit_license()
```### Run `devtools::check()` and addressed errors? ✅
## Listen 🚧
### Consulted with potential users 🚧
### Consulted with technical expertsGetting started with that!
## Polish. Have you...
### Settled on examples and put them in the roxygen skeleton? 🚧
### Written formal tests of functions? 🚧
### Sent tests in this readme to package via readme2pkg 🚧
That would look like this...
```
chunk_to_tests_testthat("test_geom_barlab_count")
```### Have you worked added a description and author information in the DESCRIPTION file? 🚧
### Addressed *all* notes, warnings and errors. 🚧
## Promote
### Package website built? 🚧
### Package website deployed? 🚧
## Harden
### Submit to CRAN? 🚧
# Reports, Environment
## Description file extract
```{r}
```
## Environment
Here I just want to print the packages and the versions
```{r}
all <- sessionInfo() |> print() |> capture.output()
all[11:17]```
## `devtools::check()` report
```{r, error = T, results = print_reports_action}
# rm(list = c("geom_barlab_count", "geom_barlab_count_percent"))
devtools::check(pkg = ".")
```# Install development package with `devtools::build()`
```{r, error = T, eval = build_package, results = print_reports_action}
devtools::build()
```## Repo Directory and files report
Let's look at the repository contents.
```{r}
fs::dir_tree(recurse = T)
```#############
### Changing context
Here is a suggested preparation for a package for allowing for ggbrasilstates easy creation of brazilian state choropleth, reading in an sf states object from the geombr package.
```
brasil_state_sf <- geobr::read_state() %>%
rename(state_code = code_state,
state_abb = abbrev_state,
state = name_state,
region_code = code_region,
region = name_region,
geometry = geom)# year 2010
```Then a number of changes would need to be made to update the DATASET.R file, including object names. Also notably there are quite a few columns that are ID columns compared to the North Carolina case.
Find and change can be used for object name changes.
```
id_cols = c(country_name, fips) -> id_cols = c(state_code, state_abb, state, region_code, region)
country -> state
northcarolina -> brasil
```For ggbrasil in these files changes should be made:
```
County -> State
```New examples should be crafted.