How to include sf data in R packages

An extremely opinionated guide for an extremely common problem.

R
Tutorials
Spatial
Data science
Author
Published

December 1, 2022

tl;dr

Store your sf objects as internal data. Add a .R file to data/ (probably named your_data.R) containing the following:

delayedAssign("your_data", local({
  requireNamespace("sf", quietly = TRUE)
  your_package:::your_data
}))

Document your data as usual.

See the update at the bottom of this post for a bit more information.

The Problem

If you work with spatial data in R, you’re familiar with the sf package. If you write spatially-oriented packages for R, there’s a good chance you think a lot about how to handle and work with sf objects. I think that’s a good thing; sf makes data analysis with spatial data miles easier, and I rely on it throughout my packages.

Three cute fuzzy monsters adding spatial geometries to an existing table of attributes using glue and tape, while one cuts out the spatial polygons. Title text reads "sf: spatial data…simplified." and a caption at the bottom reads "sticky geometries: for people who love their maps and sanity."

CC-BY 4.0 Artwork by Allison Horst.

If you write spatially-oriented packages, there’s a good chance your examples or tests could benefit from your package including some sf objects as demonstration data. But there’s a few weird edge cases that crop up when including sf objects in package data.

For instance, let’s look at the guerry data from the geodaData package. On its own, this object seems to load and print perfectly fine:

geodaData::guerry |> head(1)
  CODE_DE COUNT AVE_ID_ dept Region Dprtmnt Crm_prs Crm_prp Litercy Donatns
1      01     1      49    1      E     Ain   28870   15890      37    5098
  Infants Suicids MainCty Wealth Commerc Clergy Crm_prn Infntcd Dntn_cl Lottery
1   33120   35039       2     73      58     11      71      60      69      41
  Desertn Instrct Prsttts Distanc Area Pop1831
1      55      46      13 218.372 5762  346.03
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          geometry
1 801150, 800669, 800688, 800780, 800589, 800333, 799095, 799136, 799690, 799329, 797715, 797655, 797410, 797149, 796755, 796738, 796612, 795234, 794905, 794547, 791555, 791465, 791935, 791835, 791670, 790205, 790035, 789304, 788617, 788005, 787670, 786705, 786350, 785720, 785562, 786670, 786930, 787055, 787208, 787367, 786900, 786795, 786830, 786811, 786384, 786550, 786560, 786465, 785956, 787211, 787415, 787600, 787536, 787137, 786610, 786457, 787138, 787365, 787545, 787880, 788198, 788225, 789130, 789370, 789790, 789995, 790445, 790237, 789585, 788993, 788830, 788650, 788638, 788673, 789501, 789510, 789596, 789680, 789845, 790050, 790594, 790750, 790740, 790739, 791139, 791749, 791860, 792199, 792285, 792880, 793615, 793737, 793650, 793618, 793480, 794012, 794347, 794535, 794686, 795135, 796115, 796193, 796250, 796311, 796335, 796324, 796316, 796385, 796495, 797830, 797970, 797959, 797910, 797905, 798850, 798930, 798980, 799122, 799255, 799340, 800295, 800326, 800757, 801505, 802043, 802820, 804846, 805165, 805338, 805485, 808352, 808655, 809605, 809930, 811710, 813076, 814292, 814670, 815189, 816978, 817045, 818290, 819798, 819990, 819753, 820496, 820305, 820810, 821023, 821020, 821753, 822453, 822690, 823263, 823585, 824250, 825284, 825600, 828440, 829372, 828470, 828705, 828395, 827745, 828485, 830445, 831525, 832747, 833030, 833286, 833885, 833687, 832940, 832830, 833866, 833825, 833752, 833675, 835995, 835930, 836194, 836185, 836190, 836405, 836690, 837059, 837545, 838628, 838735, 840056, 840530, 840855, 841371, 841670, 841591, 841093, 840525, 840483, 841576, 841898, 843750, 843973, 844372, 844675, 846805, 848292, 848440, 848651, 850029, 850390, 851184, 851650, 851857, 851710, 852195, 853883, 854050, 854684, 854950, 855010, 854706, 856495, 857425, 857675, 857795, 860115, 860522, 860356, 860868, 861160, 861499, 861800, 863931, 864270, 867954, 868320, 868625, 868940, 870819, 871569, 872099, 872230, 873891, 874080, 875215, 875688, 875836, 876350, 877249, 877575, 877751, 879950, 880577, 882757, 884049, 885600, 886165, 886435, 889069, 889778, 890867, 893000, 894101, 894575, 894622, 893375, 892712, 892540, 891600, 891281, 891245, 891340, 890292, 890080, 890987, 891235, 891560, 891794, 891337, 890413, 889185, 888822, 887853, 887180, 886092, 885735, 885432, 884760, 883760, 883455, 882749, 882058, 881989, 880591, 880422, 879890, 879855, 882197, 882019, 881408, 880810, 880202, 880177, 879600, 879351, 878142, 877449, 876853, 875845, 875089, 874800, 874322, 874925, 874725, 872900, 872100, 871837, 870648, 869972, 869296, 869435, 868710, 868663, 868525, 868760, 868985, 868525, 868617, 868760, 868864, 869034, 868545, 868661, 868975, 868911, 869020, 869215, 870970, 870979, 870925, 871130, 870721, 870455, 870800, 870344, 870311, 870897, 870710, 870615, 869975, 869465, 869314, 869040, 868989, 868710, 868050, 867940, 867995, 867975, 867825, 867736, 867995, 867979, 867788, 868170, 867935, 867643, 867110, 867246, 867588, 866723, 866013, 865294, 864275, 864000, 863659, 861885, 861845, 862185, 862398, 862694, 862533, 860925, 860842, 861160, 861300, 861210, 860973, 860337, 858511, 858205, 858072, 857453, 857320, 857265, 856650, 856355, 856182, 855610, 854744, 854474, 852864, 852620, 852647, 851685, 851354, 850753, 850470, 850320, 850069, 850023, 850741, 851509, 852157, 852073, 850451, 850375, 850111, 849805, 848375, 848150, 847545, 847281, 845980, 845694, 844840, 842895, 842098, 841825, 841604, 841170, 840895, 839825, 839769, 840798, 840745, 840580, 840305, 839320, 839165, 839016, 838200, 836342, 836100, 835840, 834252, 833175, 833017, 832785, 832719, 832433, 831189, 830330, 829565, 829550, 829422, 828638, 827810, 827523, 826955, 826653, 825785, 825487, 824587, 822700, 822339, 821748, 821660, 821459, 820815, 820470, 819281, 818215, 817851, 816405, 815735, 815844, 815501, 814830, 814502, 814175, 813785, 811510, 811202, 810503, 809935, 808612, 808305, 807965, 807085, 806759, 806450, 805480, 804700, 804426, 803230, 802864, 801150, 2092615, 2093190, 2095430, 2095795, 2096112, 2097190, 2098505, 2098838, 2100360, 2100395, 2100950, 2101330, 2102850, 2102788, 2102425, 2102785, 2103487, 2103892, 2104515, 2104359, 2102570, 2102760, 2104075, 2105023, 2105295, 2105555, 2105875, 2107116, 2107148, 2106760, 2106708, 2106990, 2107029, 2107335, 2108399, 2109486, 2109775, 2110010, 2110344, 2111056, 2113550, 2114260, 2114370, 2114751, 2116197, 2116940, 2117563, 2117860, 2119206, 2120474, 2120775, 2121475, 2121809, 2122743, 2123110, 2124100, 2124890, 2125160, 2125377, 2125830, 2126745, 2127075, 2128290, 2128585, 2129209, 2129525, 2131460, 2131793, 2132230, 2132742, 2133100, 2133655, 2134028, 2135142, 2136382, 2137110, 2138174, 2138520, 2139015, 2139590, 2140547, 2142011, 2142380, 2142716, 2143599, 2144456, 2144790, 2147049, 2147420, 2148815, 2150425, 2150782, 2152285, 2152660, 2153400, 2155103, 2155696, 2155980, 2156241, 2157025, 2159030, 2160314, 2160635, 2161408, 2161795, 2162102, 2163021, 2163470, 2163785, 2165380, 2165700, 2167362, 2167695, 2167835, 2169845, 2170117, 2170395, 2171035, 2171335, 2171435, 2171593, 2170924, 2170498, 2170754, 2171611, 2171760, 2171217, 2171380, 2170485, 2170210, 2168729, 2168520, 2168719, 2168735, 2170150, 2169640, 2170568, 2170640, 2171442, 2171075, 2172530, 2171719, 2171534, 2171205, 2170948, 2169812, 2169145, 2168648, 2167568, 2167190, 2167185, 2166355, 2166075, 2166394, 2166285, 2165476, 2165330, 2165160, 2165065, 2163119, 2162490, 2161655, 2161531, 2161519, 2161005, 2159908, 2159915, 2158958, 2158780, 2158494, 2158105, 2157807, 2157040, 2156696, 2155806, 2155445, 2155097, 2154750, 2153047, 2152675, 2151171, 2150780, 2150680, 2150149, 2150070, 2153840, 2154400, 2151187, 2150820, 2151192, 2151708, 2151840, 2151081, 2150965, 2150606, 2148479, 2148155, 2146631, 2145603, 2145394, 2145800, 2146033, 2145523, 2145410, 2146002, 2147688, 2148035, 2148733, 2148841, 2148775, 2149407, 2150710, 2150922, 2151180, 2152638, 2153465, 2153815, 2154550, 2153948, 2153605, 2152546, 2152522, 2151954, 2151680, 2151135, 2150917, 2149401, 2147845, 2145955, 2145690, 2145842, 2146060, 2146529, 2146675, 2146311, 2146245, 2146162, 2146145, 2146227, 2147047, 2147009, 2146655, 2148801, 2149145, 2148900, 2149908, 2151749, 2152270, 2151866, 2151825, 2152160, 2156500, 2157904, 2159490, 2160898, 2163565, 2164270, 2164140, 2163415, 2162493, 2162099, 2160395, 2160083, 2159465, 2158743, 2156340, 2155944, 2155185, 2153375, 2152677, 2152295, 2150917, 2149984, 2149695, 2147869, 2147615, 2147405, 2146272, 2145258, 2144570, 2145445, 2145356, 2144792, 2145110, 2143618, 2143730, 2143963, 2143997, 2143495, 2143280, 2142419, 2142149, 2141782, 2141448, 2140052, 2139555, 2139435, 2138192, 2137078, 2136753, 2134940, 2133632, 2132631, 2132205, 2132001, 2131755, 2131650, 2131962, 2130970, 2130628, 2130520, 2129464, 2128114, 2126982, 2126720, 2126810, 2127080, 2128513, 2128829, 2128495, 2127050, 2125650, 2125275, 2123780, 2123569, 2123070, 2121885, 2121591, 2120685, 2120349, 2119679, 2118760, 2118458, 2117935, 2117610, 2116295, 2115554, 2114005, 2113621, 2112855, 2111817, 2110485, 2110250, 2110165, 2109573, 2108843, 2107500, 2106390, 2106018, 2103410, 2101545, 2101232, 2099875, 2099512, 2098080, 2097320, 2096964, 2094425, 2094056, 2092595, 2092277, 2091670, 2091277, 2090131, 2088645, 2088380, 2088330, 2088110, 2087753, 2086334, 2085607, 2084278, 2084187, 2084575, 2084465, 2084328, 2084450, 2084109, 2083150, 2082820, 2082092, 2081333, 2079632, 2078870, 2078155, 2077808, 2077080, 2076787, 2076386, 2076155, 2075110, 2074811, 2074591, 2073960, 2073584, 2073221, 2073460, 2073797, 2074780, 2075941, 2077758, 2078730, 2079020, 2079386, 2079920, 2080021, 2079717, 2079917, 2080840, 2081131, 2082613, 2082507, 2081230, 2081554, 2082291, 2083206, 2083940, 2084174, 2084350, 2084500, 2084810, 2086215, 2086449, 2087620, 2087856, 2088564, 2091270, 2091898, 2092105, 2092424, 2093065, 2093318, 2094355, 2096198, 2096536, 2096910, 2097185, 2097470, 2098117, 2098880, 2099191, 2099825, 2100899, 2101165, 2101453, 2102554, 2102260, 2102031, 2101525, 2101162, 2100482, 2099710, 2098550, 2095140, 2094745, 2094389, 2093577, 2091920, 2091724, 2091325, 2091135, 2090510, 2090257, 2089517, 2089735, 2089692, 2090044, 2090765, 2091109, 2092110, 2092273, 2093148, 2093260, 2093406, 2093980, 2093715, 2092629, 2092497, 2094120, 2094025, 2093925, 2093907, 2093620, 2093793, 2093796, 2093390, 2093210, 2093030, 2092976, 2093490, 2093370, 2093210, 2092960, 2093105, 2093280, 2093210, 2093269, 2092615

But if we cast this object to a tibble, we get an error:

try(tibble::as_tibble(geodaData::guerry))
Error : All columns in a tibble must be vectors.
✖ Column `geometry` is a `sfc_MULTIPOLYGON/sfc` object.

This is a known bug that packages need to work around themselves, and can be a bit of a pain to figure out solutions for. It tends to crop up when data.frame objects are implicitly casted to tibbles, for instance by dplyr functions:

try(dplyr::group_by(geodaData::guerry, CODE_DE))
Error : All columns in a tibble must be vectors.
✖ Column `geometry` is a `sfc_MULTIPOLYGON/sfc` object.

But it can happen without casting to tibbles as well, for instance when trying to use dplyr::arrange():1

try(dplyr::arrange(geodaData::guerry))
Error in vec_size() : 
  `x` must be a vector, not a <sfc_MULTIPOLYGON/sfc> object.

Any code that calls vctrs::vec_size() will wind up erroring in this situation, which includes a good amount of tidyverse code.

A final challenge with including sf objects in R packages is that some projected CRS include non-ASCII characters in their WKT, causing an aggravating warning in R CMD check: Warning: found non-ASCII string. Your package won’t be accepted to CRAN with that warning, and as such, this needs to be fixed.2

All three of these problems can be solved by the same approach, which I think is the best way to include sf objects in packages.

The Solution

Rather than including sf objects directly as package data in the normal manner, you should store the sf object as internal data and then load it via delayedAssign. This is an approach inspired by palmerpenguins (here’s the relevant PR), now in use in the spatialsample and waywiser packages I maintain.

To store your sf objects as internal data, save them into a file named R/sysdata.rda. If you use usethis::use_data(), set the argument internal = TRUE to make this happen automatically. This solves the third problem for us; something about not exporting the sf object directly means that R CMD check no longer checks the CRS for non-ASCII characters, and the warning is no longer triggered.

You now need to somehow export this data, in order to let users actually use your newly-internal sf object. To do so, we’re going to write a file in the data/ folder, named something like your_data.R, taking advantage of the delayedAssign() function like so:3

delayedAssign("your_data", local({
  requireNamespace("sf", quietly = TRUE)
  your_package:::your_data
}))

This function makes it so that, whenever a user calls your data object for the first time in a session, you quietly load the sf package before assigning your internal data to the exported object. This doesn’t attach the sf package, meaning that your users won’t accidentally have the entire sf package dumped into their search path. Loading the sf package, however, is enough to fix both problems 1 and 2; your data will now play happily with tibbles, dplyr functions, and the broader R ecosystem.

You then need to document your data in a file under R/ the same way you always would.

And that’s it! Your package will now be more user-friendly and CRAN-acceptable. I’ve been using this approach for months with no side effects4 and am planning to keep using it going forward.

Update

Edzer points out on Mastodon that, in order to play nicely with potential changes in sf, you can include your data as an external file instead. The steps here are broadly similar: save your sf object to a file in inst/extdata, and write a file in R/ that looks something like this:

delayedAssign("your_data", local({
  try(
    sf::read_sf(
      system.file("extdata/your_data.gpkg", package = "your_package")
    ),
    silent = TRUE
  )
}))

We need to wrap the call in try() in order to make this approach work with tooling like devtools::document(), which will otherwise complain about trying to read a file that isn’t there.

In my tests, this was enough to fix issues 1 and 2; calling sf::read_sf() will load the sf package and should fix any interoperability issues. However, this approach doesn’t necessarily fix the non-ASCII character WARNING given off by R CMD check.

Of course, you can also include external files in inst/ and then have your users read it themselves using system.file(), like the sf vignettes do themselves!

Footnotes

  1. This section was edited on 2022-12-01; thanks to Barry Rowlingson for pointing out a mistake in the original draft.↩︎

  2. Theoretically this should be fixed by setting Encoding: UTF8 in your package DESCRIPTION, but that rarely seems to help.↩︎

  3. Just in case it’s not clear: make sure to change your_data and your_package below to, well, the name of your data and the name of your package.↩︎

  4. Knock on wood for me, I’ve tempted the gods.↩︎