The MRM empirical callables (mrm_otis_*,
mrm_tps_*, mrm_siu_*) operate on three
external data sources. This vignette documents how rmorie makes each of
them accessible:
data.ontario.ca, reached via the existing
morie_load_dataset() infrastructure.morie_fetch_tps().morie_fetch_siu() writes the
panel-reviewed corpus bundled in rmoriedata, or fetches the reports live
on request.Four small reference tables, read by morie_sample(), let
the examples run offline.
otis_b09 and otis_c11 ship in rmorie and
are the whole published tables. otis_b01 and
tps_assault ship in rmoriedata and are 1,000-row
extracts.
# Included samples
b01 <- morie_sample("otis_b01")
b09 <- morie_sample("otis_b09")
c11 <- morie_sample("otis_c11")
tps <- morie_sample("tps_assault")
# Schema sanity
str(b01, max.level = 1)
#> 'data.frame': 1000 obs. of 18 variables:
#> $ EndFiscalYear : int 2025 2023 2023 2023 2024 2024 2025 2025 2024 2023 ...
#> $ UniqueIndividual_ID : chr "2025-08960-SG" "2023-11152-SG" "2023-08955-SG" "2023-11360-SG" ...
#> $ Gender : chr "Male" "Male" "Female" "Male" ...
#> $ Region_AtTimeOfPlacement : chr "Eastern" "Northern" "Central" "Central" ...
#> $ Region_MostRecentPlacement : chr "Eastern" "Northern" "Central" "Central" ...
#> $ Age_Category : chr "25 to 49" "25 to 49" "25 to 49" "25 to 49" ...
#> $ NumberConsecutiveDays_Segregation : int 4 1 6 1 2 1 1 1 2 3 ...
#> $ SegReason_SecurityOfInstitution_SafetyOfOthers : chr "No" "No" "No" "No" ...
#> $ SegReason_InmateNeedsProtection : chr "No" "Yes" "No" "No" ...
#> $ SegReason_InmateNeedsProtection_Medical : chr "Yes" "No" "No" "No" ...
#> $ SegReason_SecurityOfInstitution_SafetyOfOthers_Medical: chr "No" "No" "Yes" "Yes" ...
#> $ SegReason_Disciplinary_Segregation : chr "No" "No" "No" "No" ...
#> $ SegReason_InmateRefuseSearch_Scan : chr "No" "No" "No" "No" ...
#> $ MentalHealth_Alert : chr "Yes" "No" "Yes" "No" ...
#> $ SuicideRisk_Alert : chr "Yes" "No" "Yes" "No" ...
#> $ SuicideWatch_Alert : chr "Yes" "No" "Yes" "No" ...
#> $ SegReason_Other : chr "No" "" "" "" ...
#> $ Number_Of_Placements : int 1 8 1 1 1 2 2 1 2 1 ...
nrow(b09)
#> [1] 78
nrow(c11)
#> [1] 33
dim(tps)
#> [1] 1000 31data.ontario.ca)The OTIS public release is hosted at
data.ontario.ca/dataset/data-on-inmates-in-ontario (31
resources when this vignette was written, 29 of them CSV). The catalogue
registers these tables with their CKAN resource IDs:
catalog <- morie_dataset_catalog()
catalog[catalog$source == "otis", c("key", "name", "ckan_resource_id")]
#> key
#> 37 otisloc
#> 38 otisa01
#> 39 otisb01
#> 40 otisb09
#> 41 otisc11
#> name
#> 37 OTIS: Ontario's adult provincial correctional institutions (locations)
#> 38 OTIS a01: Restrictive Confinement - Detailed Dataset
#> 39 OTIS b01: Segregation - Detailed Dataset
#> 40 OTIS b09: Individuals in Segregation - Number of Placements
#> 41 OTIS c11: Individuals in Segregation/RC by Aggregate Length
#> ckan_resource_id
#> 37
#> 38 5a0c5804-a055-4031-9743-73f556e43bb4
#> 39 406e6d90-d568-4553-8ca7-bc9f90e133b9
#> 40 df24e943-d52b-43a8-a10e-a3cc906e26bb
#> 41 9c7b74a5-53ad-4ef0-a7a6-97772cd01c55To pull the full b01 from CKAN (network; not run when the vignette is built):
The loader downloads the CSV on the first call, keeps it in the
per-user cache under morie_cache_dir(), and reads that copy
on later calls (refresh = TRUE downloads it again).
Toronto Police Service publishes per-category crime events through ArcGIS Online. MORIE knows the layer URLs for nine categories.
morie_tps_layer_urls()
#> Assault
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Assault_Open_Data/FeatureServer/0"
#> AutoTheft
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Auto_Theft_Open_Data/FeatureServer/0"
#> BicycleTheft
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Bicycle_Thefts_Open_Data/FeatureServer/0"
#> BreakAndEnter
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Break_and_Enter_Open_Data/FeatureServer/0"
#> Homicides
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Homicides_Open_Data_ASR_RC_TBL_002/FeatureServer/0"
#> Robbery
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Robbery_Open_Data/FeatureServer/0"
#> ShootingAndFirearmDiscarges
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Shooting_and_Firearm_Discharges_Open_Data/FeatureServer/0"
#> TheftFromMV
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Theft_From_Motor_Vehicle_Open_Data/FeatureServer/0"
#> TheftOver
#> "https://services.arcgis.com/S9th0jAJ7bqgIRjw/arcgis/rest/services/Theft_Over_Open_Data/FeatureServer/0"To fetch a single category (network; not run when the vignette is built):
csv_path <- morie_fetch_tps("Assault")
assault <- utils::read.csv(csv_path)
nrow(assault)
# 267796 (the layer count in October 2026)The fetcher pages through /query with up to 2,000
records per page (max_per_page) and writes
tps_Assault.csv into cache_dir, which defaults
to a directory under tempdir(). Later calls in the session
return the cached path unless overwrite = TRUE; pass a
persistent cache_dir to keep the file between sessions.
Filtering at the server side:
The Ontario SIU publishes Director’s Reports at
siu.on.ca. morie_fetch_siu() returns the path
of an SIU.csv file. By default it writes the panel-reviewed corpus
bundled in rmoriedata, which needs no network access:
csv_path <- morie_fetch_siu(lang = "en")
#> SIU: wrote the panel-reviewed corpus from rmoriedata (2309 rows) to /tmp/RtmptC55W1/morie/siu/SIU.csv. For a live re-fetch set options(morie.siu.allow_fetch = TRUE).
siu <- utils::read.csv(csv_path)
dim(siu)
#> [1] 2309 66With options(morie.siu.allow_fetch = TRUE) it fetches
the reports live instead: it walks the DRID manifest shipped with rmorie
(morie_siu_index()), requests each report and news release
at rate_rps requests per second with
concurrency parallel requests, and parses them with the
package’s C++ parser. That takes a long time and needs the network, so
it is not run here:
options(morie.siu.allow_fetch = TRUE)
csv_path <- morie_fetch_siu(lang = "en", cache_html = TRUE,
rate_rps = 4, overwrite = TRUE)The siu-pipeline vignette covers the manifest, auditing
and corrections.
Putting it together – a complete worked example without any network call:
b01 <- morie_sample("otis_b01")
# Mandela classification, one row per placement
mrm_classify_mandela(b01, denominator = "row")
#> year denominator n_mandela rate pct n_broader_rc rate_broader
#> 1 2023 362 0 0.000000000 0.00 0 0.000000000
#> 2 2024 337 3 0.008902077 0.89 3 0.008902077
#> 3 2025 301 4 0.013289037 1.33 4 0.013289037
#> 4 pooled 1000 7 0.007000000 0.70 7 0.007000000
# Segregation duration KM
mrm_otis_seg_duration_km(b01,
group_cols = "MentalHealth_Alert")
#> stratum n mean_days median_days q75_days pct_above_mandela
#> 1 No 499 2.76 2 3 0.6
#> 2 Yes 501 3.29 2 4 0.8
#> median_among_above_mandela days_at_S50 days_at_S25 days_at_S10 days_at_S05
#> 1 54.0 2 3 4 6
#> 2 41.5 2 4 5 8
#> days_at_S01
#> 1 11.02
#> 2 13.00
# Mortification co-occurrence: Cramer's V across alert pairs
mrm_otis_mortification_cooccurrence(b01)
#> alert_a alert_b n chi2 df p_value cramers_v
#> 1 MentalHealth_Alert SuicideRisk_Alert 1000 33.25 1 8.12e-09 0.1823
#> 2 MentalHealth_Alert SuicideWatch_Alert 1000 12.09 1 5.08e-04 0.1099
#> 3 SuicideRisk_Alert SuicideWatch_Alert 1000 470.37 1 2.66e-104 0.6858For a full-data version, swap morie_sample("otis_b01")
for morie_load_dataset("otisb01") and re-run the same
callables.
Access to Algorithmic Justice (A2AJ) publishes Canadian court and
tribunal decisions and statutes and regulations as open data, through a
REST API and as one Parquet file per court on Hugging Face. The
morie_ingest_a2aj_* functions wrap both channels. The
chunks in this section need the network and are not run when the
vignette is built.
cov <- morie_ingest_a2aj_coverage("cases")
cov[cov$dataset %in% c("SCC", "ONCA", "FC"),
c("dataset", "earliest_document_date", "number_of_documents")]Search is full-text or by name, capped at 50 hits per call, and a single decision comes back with its unofficial text:
hits <- morie_ingest_a2aj_search("right to housing",
dataset = c("SCC", "ONCA"),
start_date = "2020-01-01")
doc <- morie_ingest_a2aj_fetch("2023 SCC 17", include_citations = TRUE)
substr(doc$unofficial_text_en, 1, 300)
doc$cases_cited_en[[1]]For a whole court, load its Parquet file. The native reader decodes
the LIST-typed citation columns without arrow;
pass columns to skip the full texts, which dominate the
file:
sct <- morie_ingest_a2aj_load("SCT",
columns = c("citation_en", "document_date_en", "cases_cited_en"))
edges <- morie_ingest_a2aj_citation_edges(sct)
head(sort(table(edges$to), decreasing = TRUE))A2AJ does not yet carry the Human Rights Tribunal of Ontario, the BC
Human Rights Tribunal, the Ontario Superior Court, Alberta, Quebec or
the remaining provinces (its issues #1, #3 and #4), and individual
decisions can be missing (2007 BCSC 1700, issue #2). Those
are reachable through CanLII’s API, which needs a free key
(CANLII_API_KEY; the chunk stops with a message without
one) and returns metadata plus the citation network rather than full
text:
morie_ingest_a2aj_gaps()[, c("code", "canlii_database_id")]
hrto <- morie_ingest_canlii_cases("onhrt", result_count = 200,
decision_date_after = "2024-01-01")
ids <- morie_ingest_canlii_case_id("2007 BCSC 1700")
morie_ingest_canlii_case(ids$database_id, ids$case_id)Every A2AJ record carries an upstream_license field;
check it before any commercial use, and treat all texts as unofficial
copies.
| Data | Fetched by | Cached in |
|---|---|---|
| catalogue datasets (OTIS, PUMFs, …) | morie_load_dataset() |
per-user cache under morie_cache_dir() |
| TPS layers | morie_fetch_tps() |
cache_dir argument (default under
tempdir()) |
| SIU reports | morie_fetch_siu() |
cache_dir argument (default under
tempdir()) |
data.ontario.ca/dataset/data-on-inmates-in-ontariodata.torontopolice.on.ca/siu.on.ca/en/case_directors_reports.phpcitation("rmorie")