library(sf)
library(mapsf)
# import dataset
<- st_read(dsn = "com.gpkg", layer = "communes", quiet = TRUE)
com
# get borders
<- mf_get_borders(com)
com_bo
# compute the gap between prices
$diff <- abs(com_bo$loypredm2 - com_bo$loypredm2.1)
com_bo
# set a cartographic theme
mf_theme(x = "darkula",
mar = c(.5, .5, 2, .5),
inner = FALSE,
pos = "center",
tab = FALSE)
# display a choropleth map of the rent price / m²
mf_map(x = com, var = "loypredm2", type = "choro",
breaks = "ckmeans", nbreaks = 6, pal = "Emrld", rev = T,
border = "grey90", lwd = .2,
leg_title = "Rent price\nindicator\n(€ per m²)",
leg_val_cex = .8, leg_val_rnd = 1, leg_pos = "topleft")
# display discontinuities
mf_map(x = com_bo[com_bo$diff >= 2, ], var = "diff", type = "grad",
breaks = c(2, 4, 6, 8, 8.9), lwd = c(1, 4, 10, 14), col = "red",
leg_title = "Price gap\n(€ per m²)",
leg_val_rnd = 1, leg_pos = "topleft", leg_adj = c(8, 0),
leg_val_cex = .8)
# Layout elements
mf_arrow("topright")
mf_credits(
txt = paste(
'Timothée Giraud, 2024\n',
'ADMIN EXPRESS COG CARTO - IGN, 2024\n',
'"Carte des loyers" - Ministère de la Transition écologique, 2023'
)
)mf_title("Discontinuities in rental price levels in Paris")
mf_annotation(x = com_bo[order(com_bo$diff, decreasing = TRUE), ][1, ],
txt = paste0("The largest gap is between\nParis XVII (29.2€/m²) and\n",
"Saint-Ouen (20.3€/m²)"),
halo = TRUE, s = 2, col_arrow = "white", col_txt = "white",
pos = "topright")
mf_scale(5)
New release of mapsf
An update of mapsf
has been deployed on CRAN.
The package now includes two new functions: mf_get_borders()
and mf_get_pencil()
. The first function extracts borders between polygons which can be used to create discontinuities maps. The second one transforms polygons into lines, simulating a pencil drawing pattern.
Other changes are bug fixes and minor improvements.
The dataset used in the following examples concerns apartment rental prices in 2023 (source).
Download the dataset:
New features
Discontinuities maps with mf_get_borders()
Discontinuities maps display the variation of a phenomenon between contiguous administrative units. This kind of representation does not focus on homogeneous zones, but rather on spatial breaks. On the map, discontinuity intensity is expressed by the thickness of the borders.
The first step to building these maps is to extract borders between units. The second step is to compute a discontinuity measure (either a ratio or an absolute difference). The third step is to display it on a map using a variations in line width. Combining these discontinuities with a choropleth representation helps to understand the discontinuity direction (which one of two regions has the higher value).
mf_get_borders()
is used to build the spatial object of borders between units. Each resulting border is described by the datasets of its two neighboring units in order to compute the discontinuity measures.
Colored pencil maps with mf_get_pencil()
mf_get_pencil()
transforms POLYGONS or MULTIPOLYGONS geometries in MULTILINESTRINGS geometries. This function creates a layer that mimicks a pencil drawing pattern. The following code details how to use the function:
# transform the POLYGON layer in a MULTILINESTRING layer
<- mf_get_pencil(com, size = 250)
comx
# set a cartographic theme
mf_theme("candy")
# display the map as a choropleth map
mf_map(x = comx, var = "loypredm2", type = "choro",
breaks = "ckmeans", nbreaks = 6, pal = "Mako",
leg_title = "Rent price\nindicator\n(€ per m²)",
leg_val_cex = .8, leg_val_rnd = 1, leg_pos = "topleft")
mf_map(com, add = T, col = NA, border = getOption("mapsf.fg"))
# Layout elements
mf_arrow("topright")
mf_credits(
txt = paste(
'Timothée Giraud, 2024\n',
'ADMIN EXPRESS COG CARTO - IGN, 2024\n',
'"Carte des loyers" - Ministère de la Transition écologique, 2023'
)
)mf_title("Rental price levels in Paris")
mf_scale(5)
Bug fixes and improvements
2 lines titles
A fix has made it easier to create titles on two lines.
# set a suitable cartographic thme
mf_theme(bg = "grey90", fg = "black",
mar = c(0,0,2.2,0), inner = FALSE, line = 2.2, cex = 1, pos = "left")
mf_map(com)
# display the title
mf_title("This title is easlily\ndisplayed on 2 lines")
A better north arrow
The north arrow has been redesigned. It is now possible to change its size (cex), fine-tune its position (adj) or use a true north azimuth (align).
mf_theme("jsk")
# use a projection that will produce a map where the north is not at the top
<- st_transform(com, "EPSG:32119")
com_usa mf_map(com_usa)
mf_arrow(pos = "topleft", align = com_usa, cex = 2)
mf_graticule(com_usa, pos = c("bottom", "left"),add = TRUE)
mf_title(txt = "A better north arrow")
New classification methods
The “Q6” and “ckmeans” methods have been added to the mf_get_breaks()
function.
The “Q6” method has also been added, it’s a variation of the “q6” method.
The “jenks”, “fisher” and “ckmeans” methods are based on the same concept of natural breaks and produce similar groupings.
- The “jenks” method produces class boundaries that fall on data points and is slow.
- The “fisher” method produces class boundaries placed more conveniently between data points, and is faster than the “jenks” method.
- The “ckmeans” method produces the exact same class boundaries as the “fisher” method, but is much faster. It uses the optimal univariate k-means method from the
Ckmeans.1d.dp
package (Wang and Song 2011). If the “ckmeans” method is selected but theCkmeans.1d.dp
package is not installed then the “fisher” method is used.
The relative speeds of these three methods may vary depending on the number of data points and the number of classes.
Jenks isn’t even included due to the prohibitive amount of time it would take.
<- runif(5000)
x library(microbenchmark)
microbenchmark(fisher = mf_get_breaks(x, 8, "fisher", largeN = 5000),
ckmeans = mf_get_breaks(x, 8, "ckmeans"))
Unit: milliseconds
expr min lq mean median uq max neval
fisher 68.162320 69.48564 71.004707 70.333813 71.618909 89.183144 100
ckmeans 2.706476 2.81163 2.946925 2.902102 3.023941 5.651169 100
identical(mf_get_breaks(x, 8, "fisher", largeN = 5000),
mf_get_breaks(x, 8, "ckmeans"))
[1] TRUE