| Type: | Package |
| Title: | Retrieve Slices of the Small-Area Global Elections Archive |
| Version: | 0.2.0 |
| Description: | Downloads and subsets slices of the Small-Area Global Elections (SAGE) archive, a harmonized collection of polling-station and precinct-level election results, without having to read monolithic country-level files. Reads partitioned 'Parquet' from a public bucket (configurable through the 'SAGE_SOURCE' environment variable, the 'sage_set_source()' function, or a local copy of the archive) and exposes a 'sage_load(country, years, columns)' function returning a 'tibble', plus helpers for the accompanying boundary polygons and candidate-level vote sidecars. See https://github.com/noahdasanaike/sage for the archive itself. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Language: | en-US |
| Depends: | R (≥ 4.0) |
| Imports: | arrow (≥ 14.0.0), dplyr, rlang, tibble, utils |
| Suggests: | curl, sf, sfarrow, testthat (≥ 3.0.0) |
| Config/testthat/edition: | 3 |
| RoxygenNote: | 7.2.3 |
| URL: | https://github.com/noahdasanaike/sage |
| BugReports: | https://github.com/noahdasanaike/sage/issues |
| NeedsCompilation: | no |
| Packaged: | 2026-10-04 17:52:17 UTC; Noah |
| Author: | Noah Dasanaike [aut, cre, cph], Dmitry Shkolnik [ctb] |
| Maintainer: | Noah Dasanaike <dasanaike.noah@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-15 16:40:02 UTC |
Small-Area Global Elections (SAGE) Data Retrieval
Description
These helpers fetch partitioned Parquet from the SAGE public release
(default: a Google Cloud Storage bucket; override with sage_set_source()
or the SAGE_SOURCE environment variable) and let users pull (country, years,
columns) slices without reading the giant per-country RDS files.
Details
Remote reads go over plain HTTPS (one partition file at a time, guided by the
_index.csv manifest), so the package works with any build of arrow –
it does not require Arrow's S3/GCS cloud filesystem to be compiled in.
When the source is the public bucket and arrow does have GCS support
compiled in, sage_columns() reads Parquet schemas through Arrow's
random-access reader instead of downloading whole partitions. That is an
optimization only: it falls back to the HTTPS download path whenever the
cloud filesystem or an individual read is unavailable.
Source layout
The release is a hive-partitioned Parquet dataset:
<source>/ country=Afghanistan/year=2014/part-0.parquet country=Afghanistan/year=2019/part-0.parquet country=Albania/year=2009/part-0.parquet ... _index.csv
so a (country, year) slice is a single partition read.
Offline excerpt
Every example in this package runs against a small excerpt of the archive
(Iceland and Samoa) shipped under extdata/mini_archive, so no network
access is required to try the interface:
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
Point sage_set_source() back at "gs://sage-archive/parquet" to
use the full release.
List the columns available in the dataset
Description
Not every column is populated for every country; this returns the union of
columns over the largest partition of each of several countries, which is
what surfaces the optional deep-hierarchy columns (NAME4,
NAME5, ...). The answer is cached for the session, and is discarded
when sage_set_source() changes the source.
Usage
sage_columns()
Value
A character vector of column names, beginning with "country"
and "year".
See Also
sage_load(), whose columns argument takes these names.
Examples
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
sage_columns()
List countries available in the current source
Description
Reads the _index.csv manifest that ships with the archive, so this
costs one small request rather than a scan of the bucket.
Usage
sage_countries()
Value
A character vector of country names, sorted.
See Also
Examples
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
sage_countries()
Load a (country, years, columns) slice of SAGE
Description
Reads only the partitions the request needs, one file per (country, year), and returns them as a single tibble.
Usage
sage_load(
country,
years = NULL,
columns = NULL,
election_type = NULL,
min_match_confidence = NULL,
drop_all_na = TRUE
)
Arguments
country |
Single country name; required. |
years |
Optional integer vector of years (default: all available). |
columns |
Optional character vector of column names (default: all). |
election_type |
Optional character filter on |
min_match_confidence |
If non-NULL, restricts to rows whose
|
drop_all_na |
Drop columns that are entirely NA for the slice. The union schema carries every column any partition has, so a country slice would otherwise show columns that never apply to it. |
Value
A tibble, with country and year as the first two
columns.
See Also
sage_columns() for the available columns, sage_polygons() for
boundaries.
Examples
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
is_2020 <- sage_load("Iceland", years = 2020)
dim(is_2020)
names(is_2020)
# Restrict to a few columns; country and year are always kept.
sage_load("Iceland", years = 2020, columns = c("party", "votes"))
## Not run:
# Against the full release (requires network access).
sage_set_source("gs://sage-archive/parquet")
de_2021 <- sage_load("Germany", years = 2021, columns = c("party", "votes", "NAME3"))
all_de_high <- sage_load("Germany", min_match_confidence = "high")
## End(Not run)
Load the polygon set for one country
Description
SAGE ships a parallel polygons/ tree (one geoparquet per country)
alongside the main parquet release; the polygons carry only the
NAME-key + year + geometry columns and are
deduplicated to one row per unique polygon. Use this helper when you need
boundaries for choropleth mapping; the main sage_load() only
returns lat/long.
Usage
sage_polygons(country, years = NULL)
Arguments
country |
Country name. |
years |
Optional integer vector of years. |
Details
Requires the sf and sfarrow packages.
Value
An sf data frame, or NULL invisibly if the source has
no polygons for the country.
See Also
sage_load() for the vote data these boundaries join to.
Examples
## Not run:
# Requires network access, plus the sf and sfarrow packages; polygons are
# not part of the offline excerpt.
sage_set_source("gs://sage-archive/parquet")
is_poly <- sage_polygons("Iceland", years = 2021)
## End(Not run)
Load the per-candidate vote sidecar
Description
Some countries report votes for individual candidates alongside the party totals in the main release. This reads that sidecar. It is available for Germany (Erststimme by Wahlkreis) and the Netherlands (preference votes by stembureau); any other country is an error.
Usage
sage_preference_votes(country)
Arguments
country |
Country name; one of |
Value
A tibble of candidate-level votes.
See Also
sage_load() for the main party-level release.
Examples
## Not run:
# Requires network access; the sidecar is not part of the offline excerpt.
sage_set_source("gs://sage-archive/parquet")
de_cand <- sage_preference_votes("Germany")
## End(Not run)
Set the source URL or path for the SAGE archive
Description
Sets the archive every other function in the package reads from. The setting
is global to the session and persists until it is changed again; unset, the
package falls back to the SAGE_SOURCE environment variable and then to
the public bucket.
Usage
sage_set_source(source)
Arguments
source |
A local path or remote URI (e.g., |
Value
The source, invisibly.
See Also
sage_load() to read a slice from the source that is set here.
Examples
# Point the package at the offline excerpt that ships with it.
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
sage_countries()
## Not run:
# The full public release (requires network access).
sage_set_source("gs://sage-archive/parquet")
## End(Not run)
List election years available for a country
Description
List election years available for a country
Usage
sage_years(country)
Arguments
country |
Country name (e.g., |
Value
An integer vector of years, sorted. A country with no partitions in the source gives a zero-length vector.
See Also
Examples
sage_set_source(system.file("extdata", "mini_archive", package = "sage"))
sage_years("Iceland")