--- title: "Getting Started" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting Started} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r not-cran-check, include = FALSE} # Skip code evaluation on CRAN (external API calls will fail) not_cran_check <- identical(Sys.getenv("NOT_CRAN"), "true") && !nzchar(Sys.getenv("_R_CHECK_PACKAGE_NAME_")) run_vignette <- isTRUE(getOption("pkgdown.in_progress")) || not_cran_check knitr::opts_chunk$set(eval = run_vignette, purl = run_vignette) ``` ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, # standardized width that fits vignette text column fig.height = 5, # default height, override in individual chunks as needed fig.dpi = 150, # higher resolution for crisp rendering out.width = "100%", # constrain to page width, prevents overflow warning = FALSE, message = FALSE ) ``` ## Installation Install mongolstats and the released mongolmaps from CRAN: ```{r install, eval=FALSE} install.packages(c("mongolstats", "mongolmaps")) ``` ## Your First Analysis: Infant Mortality This walk-through uses the infant mortality rate (IMR), a key indicator of population health and health system performance. It covers the full workflow: find a table, check its structure, fetch data, calculate rates, and map them. ### Step 1: Load Packages ```{r setup} library(mongolstats) library(mongolmaps) library(dplyr) library(ggplot2) # Set language to English for readable output old_options <- nso_options(mongolstats.lang = "en") # Set global ggplot2 theme with proper margins to prevent text cutoff old_theme <- theme_set( theme_minimal(base_size = 11) + theme( plot.margin = margin(10, 10, 10, 10), plot.title = element_text(size = 13, face = "bold"), plot.subtitle = element_text(size = 10, color = "grey40"), legend.text = element_text(size = 9), legend.title = element_text(size = 10) ) ) ``` ### Step 2: Find the Right Table Search the catalogue by keyword: ```{r search} mortality_tables <- nso_search("infant mortality") mortality_tables |> distinct(tbl_id, tbl_eng_nm) ``` NSO publishes both **rates** (per 1,000 live births) and the **counts** behind them (infant deaths). We start with the monthly rate table, `DT_NSO_2100_015V1`, and later use the counts to compare aimags. ### Step 3: Explore Table Metadata Before fetching data, check which dimensions the table has: ```{r metadata} # View table structure meta <- nso_table_meta("DT_NSO_2100_015V1") meta # Periods oldest first, with their dates. Month labels are "YYYY-MM"; the # codes count back from the latest month ("0"), so select periods by label. months <- nso_table_periods("DT_NSO_2100_015V1") head(months) range(months$label) ``` ### Step 4: Fetch Data Get the national rate for every month NSO publishes: ```{r fetch-data} imr_national <- nso_data( tbl_id = "DT_NSO_2100_015V1", selections = list( Region = "0", # national total Month = months$label ), labels = "en" # add English label columns ) # The Month column holds labels such as "2024-03", which keep their meaning # when NSO publishes a new month imr_national |> arrange(Month) |> head(10) ``` NSO rounds these monthly rates to whole numbers, which is coarse for a measure that sits around 10 to 20 per 1,000. ### Step 5: Visualize the Trend ```{r plot-trend, fig.alt="Line plot of Mongolia's monthly infant mortality rate since 2016, with a LOESS smoother showing the overall direction"} imr_national |> mutate(date = nso_period_date(Month)) |> # "YYYY-MM" to Date ggplot(aes(x = date, y = value)) + geom_line(color = "#2c3e50", linewidth = 1, alpha = 0.3) + # dim raw data so trend stands out geom_point(color = "#e74c3c", size = 2, shape = 21, fill = "white", stroke = 1, alpha = 0.6) + # LOESS reveals the trend through month-to-month noise geom_smooth( method = "loess", formula = y ~ x, se = TRUE, color = "#3498db", fill = "#3498db", alpha = 0.2, linewidth = 1.5 ) + scale_x_date(date_breaks = "1 year", date_labels = "%Y") + scale_y_continuous(limits = c(0, NA)) + labs( title = "Infant Mortality Rate in Mongolia (Monthly)", subtitle = "Deaths under age 1 per 1,000 live births, national", x = NULL, y = "IMR (per 1,000)", caption = "Source: NSO Mongolia, DT_NSO_2100_015V1" ) + theme( panel.grid.minor = element_blank(), panel.grid.major.x = element_blank() # vertical gridlines clutter time series ) ``` ## Regional Comparison To compare aimags over a year, do not average the 12 monthly rates. A mean of monthly rates gives a month with few births the same weight as a busy month, and NSO's rounding makes small aimags' monthly rates jump between values. Instead, add up the infant deaths and the live births for the year, then divide: $$\text{IMR} = \frac{\text{infant deaths in the year}}{\text{live births in the year}} \times 1{,}000$$ The counts come from two monthly tables: infant deaths (`DT_NSO_2100_014V1`) and live births (`DT_NSO_2100_018V5`). ```{r regional} # Sum a monthly count table over one calendar year, for every region code annual_counts <- function(tbl, year) { months <- nso_dim_values(tbl, "Month", labels = "en") nso_data( tbl_id = tbl, selections = list( Region = nso_dim_values(tbl, "Region")$code, Month = months$code[startsWith(months$label_en, year)] ), labels = "en" ) |> summarise(count = sum(value), n_months = n(), .by = c(Region, Region_en)) } # Latest year with all 12 months published birth_months <- nso_dim_values("DT_NSO_2100_018V5", "Month", labels = "en")$label_en latest_year <- names(which(table(substr(birth_months, 1, 4)) == 12)) |> max() infant_deaths <- annual_counts("DT_NSO_2100_014V1", latest_year) live_births <- annual_counts("DT_NSO_2100_018V5", latest_year) imr_regional <- infant_deaths |> select(Region, Region_en, deaths = count) |> inner_join(select(live_births, Region, births = count), by = join_by(Region)) |> mutate( Region_en = trimws(Region_en), level = case_when( Region == "0" ~ "National", Region %in% c("1", "2", "3", "4") ~ "Region", # Ulaanbaatar's figures sit under code "5"; code "511" is an empty duplicate Region == "5" ~ "Capital", Region == "511" ~ "Duplicate", .default = "Aimag" ), imr = deaths / births * 1000, # Exact Poisson 95% confidence interval for the rate lower = qchisq(0.025, 2 * deaths) / 2 / births * 1000, upper = qchisq(0.975, 2 * (deaths + 1)) / 2 / births * 1000 ) national_imr <- imr_regional$imr[imr_regional$level == "National"] imr_units <- imr_regional |> filter(level %in% c("Aimag", "Capital")) # Highest rates imr_units |> arrange(desc(imr)) |> select(Region_en, deaths, births, imr, lower, upper) |> head(10) ``` In `r if (run_vignette) latest_year else "the latest year"`, the national IMR was `r if (run_vignette) round(national_imr, 1) else "-"` per 1,000 live births. Many aimags record only a few dozen infant deaths a year, so their rates come with wide confidence intervals. ### Visualize Regional Differences ```{r regional-plot, fig.alt="Dot plot of infant mortality rates by aimag and Ulaanbaatar for the latest complete year, with 95% confidence intervals and a dashed line at the national rate", fig.height=7} imr_units |> mutate(Region_en = forcats::fct_reorder(Region_en, imr)) |> # order by rate, not alphabet ggplot(aes(x = imr, y = Region_en)) + geom_vline(xintercept = national_imr, linetype = "dashed", color = "grey50") + geom_errorbar(aes(xmin = lower, xmax = upper), width = 0.3, color = "grey60", orientation = "y") + geom_point(aes(color = level), size = 2.5) + scale_color_manual(values = c(Aimag = "#2a78d6", Capital = "#eb6834"), name = NULL) + labs( title = paste0("Infant Mortality by Aimag, ", latest_year), subtitle = "Per 1,000 live births, with exact 95% CIs; dashed line = national rate", x = "Deaths per 1,000 live births", y = NULL, caption = "Source: NSO Mongolia, DT_NSO_2100_014V1 and DT_NSO_2100_018V5" ) + theme( panel.grid.major.y = element_blank(), panel.grid.minor = element_blank(), legend.position = "top" ) ``` Where an interval crosses the dashed line, that aimag's rate is consistent with the national rate. Infant deaths and births are counted where they are recorded, so referrals of high-risk births to hospitals in Ulaanbaatar can raise the capital's rate and lower the rate of the aimag the mother came from. ## Adding Geographic Context [mongolmaps](https://github.com/temuulene/mongolmaps) provides boundaries that carry NSO codes, so the `Region` column joins without matching names. ```{r map-example, fig.alt="Choropleth map of infant mortality rates across Mongolia's aimags and Ulaanbaatar for the latest complete year"} # mn_join() takes Ulaanbaatar's figures from region code "5" when the # capital's own code "511" is empty, as it is in this table imr_map <- imr_units |> mn_join(by = "Region", level = "aimag") mn_map( imr_map, fill = imr, title = paste0("Infant Mortality Rate, ", latest_year) ) + labs(subtitle = "Infant deaths per 1,000 live births. Data: NSO Mongolia", fill = "IMR\n(per 1,000)") ``` The map shows point estimates only. Read it with the confidence intervals above: in small aimags, a few more or fewer infant deaths can move the colour a long way. ## Key Functions Summary | Function | Purpose | Example | |----------|---------|---------| | `nso_search()` | Find tables by keyword | `nso_search("mortality")` | | `nso_table_meta()` | Get table dimensions | `nso_table_meta("DT_NSO_...")` | | `nso_dim_values()` | List dimension values | `nso_dim_values(tbl, "Region")` | | `nso_table_periods()` | Check time coverage | `nso_table_periods(tbl)` | | `nso_latest_periods()` | Latest periods, for selections | `list(Year = nso_latest_periods(tbl, n = 5))` | | `nso_data()` | Fetch data | `nso_data(tbl, selections, labels)` | | `nso_period_date()` | Period labels to dates | `nso_period_date(data$Month)` | | `mongolmaps::mn_join()` | Join NSO data to boundaries by code | `mn_join(data, by = "Region", level = "aimag")` | | `mongolmaps::mn_map()` | Quick map of joined data | `mn_map(joined, fill = value)` | ## Best Practices 1. **Use codes in scripts, labels for display**: Selections accept codes or labels, but codes such as region codes are more stable. `labels = "en"` adds readable label columns alongside the codes. Periods are the exception: NSO numbers them from the latest (`"0"`), so mongolstats always returns them as labels, and you should select them by label or with `nso_latest_periods()`. 2. **Check metadata first**: Use `nso_table_meta()` and `nso_dim_values()` to see dimensions and codes before fetching. 3. **Separate the levels**: Region columns mix the national total (`"0"`), regions (`"1"`–`"4"`), the capital (`"5"`), and aimags. Filter to one level before summing or ranking, or you will count deaths twice. 4. **Build rates from counts**: Add up numerators and denominators over the period, then divide. Do not average monthly rates. 5. **Show uncertainty**: Small populations give unstable rates. Report confidence intervals, or pool several years. 6. **Join by code**: Use `mongolmaps::mn_join()` on the `Region` code column rather than matching names. ## Common Workflows ### Time Series Analysis 1. Search for table → Check periods → Fetch months or years → Plot trend ### Regional Comparison 1. Fetch numerator and denominator counts → Sum over the period → Calculate rates and confidence intervals → Compare with the national rate ### Spatial Epidemiology 1. Calculate rates by aimag → `mn_join()` by `Region` code → `mn_map()` ## Next Steps - **Discover More Data**: See the [Discovery Guide](discovery.html) for advanced search techniques - **Create Maps**: Learn spatial analysis in the [Mapping Guide](mapping.html) - **Reference**: Browse all functions in the [Reference](https://temuulene.github.io/mongolstats/reference/index.html) ## Quick Reference: Common Health Tables ```{r health-tables, echo=FALSE} tibble::tribble( ~Indicator, ~Table_ID, ~Measure, ~Detail, "Infant mortality rate", "DT_NSO_2100_015V1", "Rate per 1,000 live births", "Aimag, month", "Infant deaths", "DT_NSO_2100_014V1", "Count", "Aimag, month", "Live births", "DT_NSO_2100_018V5", "Count", "Aimag, month", "Under-5 mortality rate", "DT_NSO_2100_030V2", "Rate per 1,000 live births", "Aimag, month", "Maternal deaths", "DT_NSO_2100_002V2", "Count", "Aimag, month", "Deaths by leading cause", "DT_NSO_2100_027V1", "Count", "Soum, year", "Cancer incidence", "DT_NSO_2100_012V1", "Rate per 10,000 population", "Cancer type, year", "Communicable disease cases (incl. tuberculosis)", "DT_NSO_2100_035V1", "Count", "Disease, month", "Communicable disease cases", "DT_NSO_2100_020V2", "Count", "Disease, soum, year", "Mid-year population", "DT_NSO_0300_002V1", "Count", "Aimag, year" ) |> knitr::kable() ``` ```{r restore-session, include=FALSE} options(old_options) ggplot2::theme_set(old_theme) ```