Skip to contents

Every result the package returns draws itself. plot(x) needs nothing but the object; the chart is the one that result calls for, drawn with base graphics (no new dependency), with one shared look across the package. Every method takes the same customisation, and every method returns the numbers it drew, so a figure can be checked or redrawn another way.

One call per result

Stock and flow after Lakner (1976): the average daily population and the length of stay, one panel per measure.

sf <- stock_flow(days = c(13500, 14600, 15100, 14200), people = c(300, 320, 310, 290),
                 period = 2020:2023)
plot(sf)

Period-over-period change with its interval, coloured by verdict:

y <- yoy(data.frame(year = 2018:2023, n = c(40, 44, 41, 55, 52, 61)), value = "n",
         period = "year")
plot(y)

Small counts get their percentages too: each comes with its exact interval, as wide as the base is small. Only a zero base has no percentage, and its row says so.

plot(yoy(data.frame(year = 2019:2023, n = c(10, 12, 11, 15, 14)), value = "n", period = "year"))

Rates with their intervals, and the change in a rate:

d <- data.frame(division = rep(c("north", "east", "west"), 2), year = rep(2022:2023, each = 3),
                stops = c(120, 90, 60, 150, 85, 70), residents = c(1e4, 8e3, 5e3, 1e4, 8e3, 5e3))
plot(rate(d[d$year == 2023, ], count = "stops", population = "residents", by = "division"))

plot(rate_change(d, count = "stops", population = "residents", period = "year", by = "division"))

First digits against Benford’s law, the power curve of a check, and a permutation null:

set.seed(1)
amounts <- round(exp(rnorm(400, 6, 1.4)))
plot(benford_test(amounts))

dd <- data.frame(x = rnorm(120), y = rnorm(120))
shift <- function(z, s) {
  z$y <- z$y + s * z$x
  z
}
plot(capsule_power(dd, function(z) cor(z$x, z$y), inject = shift, treatment = "x",
                   sizes = c(0, 0.2, 0.4, 0.6), n = 49, reps = 6, seed = 1))

Air pollution

The concentration-response curve with the exposure marked, the burden it implies, and the whole verify_pollution() report on one page (curve, burden and the concentration curve of exposure over income):

plot(pollution_burden(25, 1, 0.008, 1e6, pollutant = "NO2"))

plot(verify_pollution("no2", demo = TRUE))

A plume on a grid, and the particle cloud of the random walk:

plot(plume_field(q = 100, u = 5, h = 50, x = seq(100, 3000, by = 100),
                 y = seq(-500, 500, by = 50)))

plot(lagrangian_particles(500, 0, 0, u = 2, v = 0.5, kx = 1, ky = 1, dt = 1, n_steps = 60,
                          grid = c(0, 200, -60, 100, 40, 32)))

The footprint of a computation: CPU, memory and the total in one unit chosen to fit, with its everyday equivalents under the bars:

plot(compute_footprint(for (i in 1:20) sum(sqrt(seq_len(2e5))), location = "CA",
                       cpu_power_w = 45, memory_gb = 8))

Courts and crime

The Ontario Court of Justice and Toronto Police Service data shipped with the package (see vignette("courts-and-crime") for the analysis behind each one):

ext <- function(f) read.csv(system.file("extdata", f, package = "rmoriebricklayer"))
f <- ext("ocj_flow_ontario.csv")
d <- ext("ocj_time_to_disposition.csv")
x <- ext("ocj_dispositions.csv")
g <- ext("ocj_offence_groups.csv")
g <- g[g$year %in% c(2014, 2022), ]
b <- ext("tps_break_enter_d14_2024.csv")
b <- b[!is.na(b$lon), ]

Cases received and disposed, and the clearance rate:

plot(case_flow(f$received, f$disposed, pending = f$pending, period = f$month))

How long cases stay open, from the published time-to-disposition bands:

last <- nrow(d)
plot(life_table(c(0, 10, 15, 18, Inf), unlist(d[last, 2:5]) * f$disposed[last]))

The mix of outcomes over the years:

plot(disposition_mix(x[, -(1:2)], period = x$year))

A Simpson’s-paradox check: the parts’ rates, where the work moved, and the change split into rate and mix effects:

plot(clearance_decomposition(g$disposed, g$received, g$offence_group, g$year))

Where break-and-enters cluster, and whether they repeat near each other soon after:

plot(crime_density(b$lon, b$lat, n_grid = 120))

plot(knox_test(b$lon, b$lat, as.Date(b$occ_date), c(100, 200, 400), c(7, 14, 28),
               nsim = 99, seed = 1))

Customising

Every method takes main, col (or a palette name), grid, and ... for the base-graphics call. bricklayer_plot_options() sets the session defaults; bricklayer_palette() gives the colour-blind-safe sets the package uses.

plot(sf, what = "alos", col = "firebrick", main = "Length of stay (days)", lwd = 3)

old <- bricklayer_plot_options(palette = "grey", grid = FALSE)
plot(y, what = "value")

bricklayer_plot_options(palette = old$palette, grid = old$grid)
bricklayer_palette("okabe", 4)
#> [1] "#0072B2" "#D55E00" "#009E73" "#E69F00"

Every method returns the data it drew, invisibly:

drawn <- plot(y)

head(drawn, 3)
#>   label pct_change     lower    upper verdict
#> 1  2018         NA        NA       NA    <NA>
#> 2  2019  10.000000 -29.95683 73.20735      up
#> 3  2020  -6.818182 -40.61975 45.94265    down

Results that are plain data frames have a plot function of their own: the Lorenz curve of a vector, and the funnel plot of observed against expected counts per area.

plot_lorenz(c(1, 1, 2, 3, 5, 8, 13, 21))

plot_funnel(observed = c(4, 20, 50, 9, 31), expected = c(5, 22, 40, 20, 30),
            area = c("a", "b", "c", "d", "e"))