gho_clean() and sdg_clean() now share a single 15-column output
schema: source, id, indicator, location, iso3,
location_name, year, value, value_num, low, high,
series, dim1, dim2, dim3. This lets results from the two
APIs be combined directly (see bind_indicators() below). Migration
notes from 0.6.x:
gho_clean() output no longer has 11 columns; it has 15. New
columns include source ("gho"), iso3 (the ISO3 alpha-3
code when the spatial dim matches a WHO Member State, NA
otherwise), location_name (resolved against who_countries
and WHO regional codes; see the bug-fix note below), and
series (always NA — an SDG-only concept).sdg_clean() output no longer has 10 columns and is reshaped
to the unified schema. Several columns moved or were renamed:
the SDG goal and target columns are no longer carried
forward; the SDG indicator code is now in id (was
indicator); the human-readable series description has moved
to indicator (was not present before); a new iso3 column
holds the ISO3 alpha-3 code via m49_to_iso3() for Member
States.value_num / low / high to
numeric; non-numeric raw values (e.g. SDG "<0.1") yield NA
in those columns while value keeps the raw character form.year to integer.New bind_indicators(...): stacks any number of tibbles returned by
gho_clean() and sdg_clean() into a single tibble. Because the
two cleaners now share a schema, the result is uniform and can be
filtered, joined, or visualised without source-specific code paths;
use the source column to distinguish GHO from SDG rows.
New m49_to_iso3(): maps UN M49 numeric area codes to ISO3 country
codes, the counterpart to iso3_to_m49(). Accepts zero-padded
("076") and bare ("76") input. Non-Member areas — including
region / world aggregates — return NA. Used internally by
sdg_clean() to populate the new iso3 column.
Fixed a duplicate definition of sdg_coverage(): the function was
defined in both R/sdg.R and R/sdg_coverage.R, and R's
alphabetical source-file loading meant the wrong copy (with a
fragile \r composite-key separator and no upfront .resolve_area()
call) was the one actually in effect. The surviving implementation
now uses \x1f as the composite-key separator and resolves the
area argument up-front, so the documented "unknown ISO3 codes
warn and are dropped" message surfaces cleanly from sdg_coverage()
rather than being swallowed inside an internal call to sdg_data().
.gho_get() now sets a 20-second per-request timeout and applies
the same exponential backoff (backoff = ~ min(2 ^ .x, 30)) as
.sdg_get(). Previously a hung upstream request could stall an
entire gho_data() call indefinitely.
Network helpers now also fail soft on malformed response bodies.
.gho_get(), .sdg_get(), and the inline call in gho_count()
wrap httr2::resp_body_json() in tryCatch(), so a truncated
upstream response (premature EOF) surfaces a warning and returns
NULL / NA_integer_ instead of propagating a parse error to the
caller. Previously such a response could halt an R CMD check
example run, e.g. sdg_goals(include_children = TRUE) against a
flaky UN endpoint.
gho_clean() and sdg_clean() now populate location_name
consistently across both APIs. WHO Member States are resolved
against who_countries$name_short in both cleaners, so the same
country has the same location_name regardless of source.
gho_clean() additionally resolves the WHO regional codes
(AFR, AMR, SEAR, EUR, EMR, WPR) and GLOBAL to their
human-readable names. sdg_clean() falls back to the SDG API's
original geoAreaName for non-Member-State rows (e.g. regional
and world aggregates), preserving information that who_countries
does not carry.
gho_clean() now actually populates the indicator column. The
GHO data endpoint (/api/{IndicatorCode}) does not return
IndicatorName, so the old implementation left indicator NA
for every row despite the documented mapping. gho_clean() now
lazy-loads the indicator catalog (via gho_indicators()) once per
R session and resolves IndicatorCode against it to fill the
indicator column with the human-readable name. The output
schema is unchanged; if the catalog cannot be fetched, indicator
falls back to NA and a warning surfaces from gho_indicators().
\donttest{} instead of \dontrun{},
so CRAN reviewers can opt to run them.Added httptest2 to Suggests. The GHO and SDG helpers gain offline
regression tests covering the empty value=[] fix, the OData
pagination loop, the multi-value SDG indicator / areaCode
repeated-key URL form, the client-side SDG year filter, and the
graceful-failure behaviour on HTTP errors.
Test coverage expanded for gho_clean(), sdg_clean(),
bind_indicators(), m49_to_iso3(), scale_*_dsi_col(), the
who_countries dataset, and the regional ISO3 vectors.
theme_dsi() now draws grid lines in both directions by default. New
grid argument controls direction — pass grid = "y" to restore the
previous look (horizontal grid only). This change fixes the visual
glitch where horizontal bar charts (made with coord_flip()) had grid
lines running parallel to the bars instead of crossing them.
theme_dsi_facet() gains a grid argument mirroring theme_dsi()'s —
defaults to "both" (unchanged behaviour); pass "y", "x", or
"none" to control which direction(s) the grid runs.
New scale_y_dsi_col() and scale_x_dsi_col() — drop-in replacements
for scale_y_continuous() / scale_x_continuous() that remove the
lower axis expansion, so columns in bar charts sit flush with the
axis (WHO publication style).
New theme_dsi_facet() for faceted plots — uses panel borders,
light-grey strip backgrounds, and bilateral grid lines.
New GHO data-availability helpers, for screening indicator / filter combinations before pulling a full result set:
gho_has_data() returns TRUE / FALSE / NA for whether
the server has any rows for an indicator and filter.gho_count() returns the row count the same filter would
yield, using the OData $count=true endpoint (no rows
transferred).gho_coverage() returns a tibble with location, year_min,
year_max, n_obs per area, using $select=SpatialDim,TimeDim
to keep the payload small.sdg_indicators() gains a search parameter, mirroring
gho_indicators(search). Accepts either a single string (split on
whitespace into terms) or a character vector (terms used verbatim).
All terms must match (AND semantics, case-insensitive substring on
the indicator description column). The filter is applied
client-side because the UN SDG /Indicator/List endpoint is not
OData and exposes no server-side search parameter; the list is
small enough (~250 rows) that this is cheap.
New sdg_coverage(): series-exploration helper for SDG indicators.
An SDG indicator (e.g. "3.4.1") typically contains several series
stratified by sex, age, or cause; sdg_coverage() returns a tibble
of (location, series, year_min, year_max, n_obs) so you can see
which series exist and how each is covered. This is intentionally
framed as series-exploration rather than as a gho_has_data() /
gho_count()-style availability precheck — SDG data is generally
complete, so those screening helpers are deliberately not provided
for SDG.
New geomean(): geometric mean of a numeric vector, with optional
weights via w. Useful for aggregating ratio-based health
indicators such as UHC service-coverage tracers. Handles NA
(removed by default), zeros (returns 0), and negative values
(warns and returns NaN).
New iso3_to_m49(): maps ISO3 country codes to UN M49 numeric
codes using the bundled who_countries dataset. Non-Member codes
return NA. Input is case-insensitive.
sdg_data() and sdg_coverage() now accept ISO3 codes directly
for the area argument; M49 codes continue to work unchanged.
DSIR's regional vectors (wpro_cty, afro_cty, etc.) can now be
passed directly to SDG functions, matching the existing GHO
workflow. ISO3 and M49 cannot be mixed within a single call.
New iso3_to_region(): maps ISO3 country codes to WHO region codes
("AFR", "AMR", "SEAR", "EUR", "EMR", "WPR") using the
bundled who_countries dataset. Pass long = TRUE for full names
("Western Pacific", etc.). Non-Member codes (e.g. Associate Members
like "PRI") return NA. Stays in sync with WHO governance changes
reflected in DSIR — e.g. Indonesia in WPR since EB156 (May 2025).
sdg_data(): year filtering (year_from / year_to) is now
applied client-side. The UN SDG API's server-side
timePeriodStart / timePeriodEnd parameters were causing
HTTP 500 errors and ~30x slowdowns on at least some
indicator/area combinations (e.g. 3.2.1 with area = "608");
client-side filtering avoids the issue. User-facing behaviour is
unchanged. sdg_coverage() inherits the fix automatically because
it dispatches through sdg_data().
.sdg_get() now sets a 20-second per-request timeout and
exponential backoff between retries (backoff = ~ min(2^.x, 30)),
so a hung upstream request cannot stall a call indefinitely.
The internal pagination helper .gho_get() previously produced a
spurious 1-row, 1-column tibble (V1 of type list) when the
server returned an empty result set (value = []). Empty value
chunks are now skipped and an empty tibble is returned when no
rows accumulate. This affected gho_data() on filters with no
matches (e.g. an indicator + area combination GHO has no data for)
and gho_indicators(search) when no indicator name matched the
search term.
sdg_data() now correctly filters when more than one indicator
or area code is supplied. The SDG API expects multi-value
parameters as repeated keys (indicator=A&indicator=B), but the
previous implementation joined them with commas
(indicator=A,B); the API silently dropped the filter and
returned all rows. Single-value calls were unaffected.
sdg_data() no longer errors with duplicate 'row.names' are not allowed when the result spans more than one page. The
per-page row-name handling has been simplified.
theme_dsi(): removed the color argument and added accent instead.
The semantics are different: color previously controlled text colour,
while accent now controls axis line and tick colour. If you used
theme_dsi(color = X) in 0.2.x, change to theme_dsi(accent = X) and
note that the visual effect has shifted from "everywhere" to "axis
only". Text colour is now fixed to grey20 to follow modern
publication conventions.gho_data() now correctly handles long area vectors. Previously,
passing more than ~22 ISO3 codes hit the upstream query string length
limit and resulted in HTTP 400 errors. Switched from chained OR clauses
to the OData in operator, which generates a much shorter URL and
supports up to ~115 codes per call.New gho_clean(): post-processor for gho_data() output. Selects
the useful columns and renames them to snake_case (id, location, year,
dim1-dim3, value, value_num, low, high, indicator). Output
schema is stable across indicators — missing columns are filled
with NA. See ?gho_clean for details.
New sdg_clean(): counterpart for sdg_data(). Renames the
SDG API columns to snake_case and flattens the indicator
list-column. Returns value, low, and high as character to
preserve non-numeric entries ("<0.1", aggregate notes); coerce
with as.numeric() downstream. See ?sdg_clean for details.
theme_dsi() redesigned to follow modern publication conventions
(BBC, OECD, Financial Times style):
grey92, was grey85)grey20legend_position argumentgho_data() now infers spatial_type = "country" when area is
provided without an explicit spatial_type. Pass spatial_type
explicitly to silence the message.
gho_data() now validates the area argument: must be a non-NA,
non-empty character vector.
New who_countries dataset: a tibble of all 194 WHO Member States with
ISO3, ISO2, UN M49 numeric code, official and short names, WHO region,
and a is_pic flag for the 14 Pacific Island Country Member States.
New regional ISO3 character vectors for ergonomic filtering:
afro_cty, amro_cty, searo_cty, euro_cty, emro_cty, plus
pic_cty. All are derived from who_countries and stay consistent
with the master table.
wpro_cty now contains 28 countries (was 22 in 0.2.0). This
reflects the May 2025 World Health Assembly decision (EB156) reassigning
Indonesia from the South-East Asia Region to the Western Pacific Region,
along with Cook Islands and Niue, which are full WHO Member States but
were previously omitted. Code that aggregates over wpro_cty (sums,
counts, joins) will produce different results than under DSIR 0.2.x —
this is intended.data-raw/who_countries.R as the single source of truth for all
country-related datasets. Editing one file regenerates the master tibble
and all derived vectors.Initial CRAN submission. Renamed from DSI to avoid a name clash
with the existing CRAN DSI package.
gho_dimensions() returns the unique values of a dimension
column for a given GHO indicator, to make it easier to discover
which breakdowns (sex, age, region, etc.) are available before
calling gho_data().sdg_targets() lists Sustainable Development Goal targets from
the UN SDG API, complementing sdg_goals() and
sdg_indicators().theme_dsi() and dsi_flextable_defaults() now default to the
device / package default font (base_family = ""), so they work
on systems where Cambria is not installed. Pass
base_family = "Cambria" to get the original look.ggpie() gains input validation and uses tidy-evaluation
helpers internally, so R CMD check no longer reports
undefined global variables.gho_*() and sdg_*() now fail gracefully when the remote
service is unreachable, per CRAN policy for packages that hit
the network. They warn and return an empty data frame (or
NULL) instead of raising a hard error.roxygen2 help pages for every exported function, with
cross-references between related functions.\donttest{} (not \dontrun{}) for
network-dependent code, so CRAN reviewers can opt into running
them.