The maps in this package (gfrance,
gfrance85) were originally built as sp
SpatialPolygonsDataFrame objects, and the other vignettes
and the README use the older sp::spplot() function to
display them. The current standard toolchain for spatial visualization
in R is the sf package,
together with ggplot2::geom_sf(). This short vignette shows
how to work with Guerry’s map data that way.
This doesn’t replace the sp/spplot()
examples used elsewhere in the package – both remain fully supported –
it’s simply the modern alternative for anyone building on
Guerry’s map data in a ggplot2 workflow.
library(Guerry)
library(sf)
library(ggplot2)
library(dplyr)
library(tidyr)
data(gfrance85)
data(Guerry_ranks)sfConverting the package SpatialPolygons sp object to use
the Simple Features, sf, representation is a single call to
sf::st_as_sf():
gf_sf <- st_as_sf(gfrance85)
class(gf_sf)
#> [1] "sf" "data.frame"
names(gf_sf)
#> [1] "CODE_DEPT" "COUNT" "AVE_ID_GEO" "dept"
#> [5] "Region" "Department" "Crime_pers" "Crime_prop"
#> [9] "Literacy" "Donations" "Infants" "Suicides"
#> [13] "MainCity" "Wealth" "Commerce" "Clergy"
#> [17] "Crime_parents" "Infanticide" "Donation_clergy" "Lottery"
#> [21] "Desertion" "Instruction" "Prostitutes" "Distance"
#> [25] "Area" "Pop1831" "geometry"The result is an ordinary data frame – all the usual
Guerry variables are still there as columns – with one
addition: a geometry list-column, where each row holds the
polygon (or multi-polygon) boundary for that department as an
sfc object, instead of a separate @polygons
slot as in the sp representation.
Because it’s just a data frame, it can be manipulated with the usual
tools (dplyr, tidyr, …) before plotting, and
geom_sf() knows to look for a geometry column
automatically.
We’re using gfrance85 here (rather than
gfrance), so Corsica – geographically distant from the
mainland and excluded from the Region classification – is
not shown in any of the maps below.
geom_sf() handles the geometry column automatically to
draw the map. There’s no need to supply x/y
aesthetics. You can supply attributes like fill and
color. For maps, theme_void() is often the
most sensible choice for overall styling.
Mapping a variable to fill gives a
choropleth map, shading the departments according to the values of that
variable. This is a good example of how the “Grammar of Graphics” (Wilkinson (1999)) helps you think about the
task that Guerry worked on for each of his maps, laboriously translating
the values of a moral variable into visible tints.
In this example, Literacy (percent of military
conscripts who could read and write) is mapped to a PuBu
palette, the same one used elsewhere in this package.
Literacy is one of the variables Guerry recorded so that a
higher value is morally better;
following the convention of his own (black-and-white) maps, where
“worse” printed darker, direction = -1 makes low (bad)
values dark and high (good) values light.
This isn’t just an assumed convention – it’s exactly what Guerry says
himself. His original 1833 map of the closely related
Instruction variable (Plate III of the Statistique
morale) carries this footnote: “Dans cette carte, l’obscurité
des teintes correspond au minimum de l’instruction” – “In this map,
the darkness of the tints corresponds to the minimum of instruction
[literacy]”:
ggplot(gf_sf) +
geom_sf(aes(fill = Literacy), color = "white", linewidth = 0.2) +
scale_fill_distiller(palette = "PuBu", direction = -1, name = "Literacy") +
theme_void()The historically low-literacy departments of Brittany and central France stand out as the darkest; the generally more literate northeast is lightest – the same departments that are darkest in Guerry’s own hand-tinted map above.
Note that the numbers on Guerry’s map are his own rank
labels for Instruction, where 1 is the best (lightest)
department – the opposite direction from Guerry_ranks in
this package (see below), which is worth keeping in mind if you compare
the two directly.
The package README shows a static image of six choropleth maps of
Guerry’s main “moral variables”. Here is a living, code-generated
version of the same idea, using facet_wrap() and the
pre-ranked Guerry_ranks data set.
Guerry_ranks gives each variable’s plain ascending rank
(dplyr::dense_rank(), so ties share a rank and the maximum
rank can be less than 86): rank 1 is always the
smallest raw value, and the largest rank is the
largest raw value. Because these variables are already
recoded so that a larger raw value is morally better (as above), rank 1
is the worst department on that variable, and the highest rank
is the best – the reverse of the raw-value case, even though
it’s the same underlying idea. To keep “worse = dark, better = light”
consistent with the previous figure, direction has to flip
along with it: direction = -1 on the rank scale makes the
low rank (worst) dark and the high rank (best) light.
main_vars <- c("Crime_pers", "Crime_prop", "Literacy", "Donations", "Infants", "Suicides")
ranks_sf <- gf_sf |>
select(dept) |>
left_join(Guerry_ranks |> select(dept, all_of(main_vars)), by = "dept") |>
pivot_longer(cols = all_of(main_vars), names_to = "variable", values_to = "rank")
ggplot(ranks_sf) +
geom_sf(aes(fill = rank), color = NA) +
facet_wrap(~ variable) +
scale_fill_distiller(palette = "PuBu", direction = -1, name = "Rank") +
theme_void() +
theme(strip.text = element_text(size = 11, face = "bold"))Comparing the Literacy panel here with the
single-variable choropleth above confirms the two now agree: the same
departments read dark (worse) and light (better) in both.
Finally, a map colored by Region, with department names
added via geom_sf_text() – the
sf/ggplot2 equivalent of the
plot() + text() approach used for this same
map in the README.
col.region <- colors()[c(149, 254, 468, 552, 26)] # same colors used in the README
ggplot(gf_sf) +
geom_sf(aes(fill = Region), color = "white", linewidth = 0.3) +
geom_sf_text(aes(label = Department, color = Region == "W"),
size = 3.2, check_overlap = TRUE) +
scale_color_manual(values = c(`FALSE` = "black", `TRUE` = "white"), guide = "none") +
scale_fill_manual(values = col.region) +
theme_void()A themed, styled version of these maps using the historical color
palettes and patterns of the ggCheysson
package is planned once that package reaches CRAN.