Skip to contents

New to pixieweb? Start with vignette("a-quickstart") for a hands-on walkthrough. This vignette covers the design and advanced features.

Background

PX-Web is the statistical database platform used by national statistics agencies across the Nordic countries and beyond. Each agency runs its own instance (Statistics Sweden at scb.se, Statistics Norway at ssb.no, etc.), but they all share the same underlying API.

pixieweb provides a consistent, pipe-friendly R interface to all these APIs. It follows the same design principles as rKolada: tibbles everywhere, search-then-fetch, and progressive disclosure.

Design principles

  1. Tibbles everywhere. Every function returns a tibble (or a vector extracted from one).
  2. Pipe-friendly. First argument is always a tibble or API object; output is always pipeable.
  3. Search-then-fetch. Users discover metadata before downloading data.
  4. NULL on failure. API errors return NULL with a warning, never stop().
  5. Progressive disclosure. Simple things are simple; complex things are possible.

The data model

PX-Web tables are multi-dimensional data cubes. Unlike Kolada — where the dimensions are always KPI, municipality, and period — each PX-Web table defines its own set of dimensions. pixieweb calls these variables.

pixieweb entity What it represents rKolada analog
api A PX-Web instance (SCB, SSB…) (implicit — single)
table A statistical table kpi
variable A dimension within a table (municipality/year)
codelist An aggregation/value set kpi_groups
data Downloaded values values

Connecting to an API

library(pixieweb)

# Known aliases
scb <- px_api("scb", lang = "en")
ssb <- px_api("ssb", lang = "en")

# Or a custom URL
custom <- px_api("https://my.statbank.example/api/v2/", lang = "en")

# See all known APIs
px_api_catalogue()

Discovering tables

Tables are the central entity. get_tables() sends a server-side search query. The result is a tibble with rich metadata:

tables <- get_tables(scb, query = "income") |>
  table_search("taxable")

tables |> table_describe(max_n = 3)

The table tibble includes subject path, time period range, time unit, and data source — all of which are searchable by table_search().

Table helper functions

Function Purpose
table_search() Filter by regex (client-side)
table_describe() Print human-readable summaries
table_minimize() Remove constant columns
table_extract_ids() Extract ID vector for piping

Exploring variables

Each table has its own set of variables (dimensions). The key discovery step is get_variables():

vars <- get_variables(scb, "TAB638")
vars |> variable_describe()

Important variable properties: - elimination: can this variable be left out of your get_data() call? If TRUE, omitting it means the API returns a pre-computed total (e.g., omitting “Sex” gives the total for all sexes). If FALSE, the variable is mandatory — you must include it. - time: is this the time dimension? - values: the available codes and their human-readable labels. - codelists: alternative groupings (e.g. municipalities → counties).

# See what values a variable has
vars |> variable_values("Kon")

# Look up variable codes by name
variable_name_to_code(vars, "sex")

Fetching data

Direct approach

If you know exactly what you want:

pop <- get_data(scb, "TAB638",
  Region = c("0180", "1480"),
  Kon = c("1", "2"),
  ContentsCode = "*",
  Tid = px_top(5)
)

Variables you omit are eliminated (aggregated) if the API allows it. If a variable is mandatory, you must include it.

Selection helpers

Helper Meaning Example
c("0180") Specific values Item selection
"*" All values Wildcard
px_top(5) First N values Most recent
px_bottom(3) Last N values (v2 only)
px_from("2020") From value onward (v2)
px_to("2023") Up to value (v2)
px_range(a, b) Inclusive range (v2)

The prepare_query() shortcut

For interactive exploration, prepare_query() inspects the table metadata and builds a query with sensible defaults:

q <- prepare_query(scb, "TAB638")

Default strategy: - ContentsCode: all values ("*") - Time variable: latest 10 periods (px_top(10)) - Eliminable variables: omitted (API aggregates) - Small mandatory variables (≤ 22 values): all ("*") - Large mandatory variables: first value (px_top(1))

Override specific variables while letting defaults handle the rest:

q <- prepare_query(scb, "TAB638",
  Region = c("0180", "1480"),
  maximize_selection = TRUE
)

With maximize_selection = TRUE, the function expands unspecified variables to include as many values as possible while staying under the API’s cell limit.

Then fetch:

pop <- get_data(scb, query = q)

Advanced features

The sections below cover features you may not need on your first query, but that become essential for complex tables or cross-country work.

Codelists

Codelists provide alternative groupings of variable values. They are useful when you want data at a different aggregation level than the table’s default. For example, a “Region” variable with 290 municipalities might have a codelist that groups them into 21 counties:

cls <- get_codelists(scb, "TAB638", "Region")
cls |> codelist_describe(max_n = 5)

# Use a codelist in a query
get_data(scb, "TAB638",
  Region = "*",
  Tid = px_top(5),
  ContentsCode = "*",
  .codelist = list(Region = "vs_RegionLän07")
)

Wide output and multiple contents

When a table has multiple content variables (e.g. both Population and Deaths), use .output = "wide" to pivot them into separate columns. This is useful when you want to compute with multiple measures (e.g. death rate = Deaths / Population):

demo <- get_data(scb, "TAB638",
  Region = "0180",
  Tid = px_top(5),
  ContentsCode = "*",
  .output = "wide"
)
demo

Advanced: query composition

For full control over the HTTP request — useful for debugging or when you need to inspect/modify the exact query before sending it — use the low-level query composers:

q <- compose_data_query(scb, "TAB638",
  Region = c("0180"),
  ContentsCode = "*",
  Tid = px_top(3)
)

# Inspect the query
q$url
q$body

# Modify and execute
raw <- execute_query(scb, q$url, q$body)

Saved queries (v2 only)

PX-Web v2 supports server-side stored queries. Useful for recurring reports — save a query once, then retrieve it by ID later:

# Save a query
id <- save_query(scb, "TAB638", Region = "0180", Tid = px_top(5), ContentsCode = "*")

# Retrieve later
get_saved_query(scb, id)

Citation

Always cite your data sources:

px_cite(pop)