Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
292 lines (263 sloc) 12.2 KB
---
title: "Chart: For most offences prison is the exception, not the rule"
author: Matt Ashby
date: '2019-09-02'
slug: prison-likelihood
categories: ["Crime and justice chart of the week"]
tags:
- prison
- age
- criminal justice
---
```{r set knitr options, include=FALSE}
knitr::opts_chunk$set(cache = TRUE, include=FALSE)
```
```{r set chart parameters}
chart_details <- list(
id = "prison-likelihood",
title = "For most offences prison is the exception, not the rule",
subtitle = "Of the 663,000 non-motoring offences for which people were sentenced in 2018, only about 11% resulted in a prison sentence. Some convictions, like rape and robbery, almost always result in a prison sentence (at least for adult offenders), while other offences very rarely result in imprisonment.",
source_url = "https://www.gov.uk/government/statistics/criminal-justice-system-statistics-quarterly-december-2018",
source_title = "Ministry of Justice, 2019"
)
```
```{r load packages and helper}
# custom packages not loaded by helpers.R
# load this after loading custom packages
source(here::here("helpers.R"))
```
```{r get and tidy data}
if (!file.exists(paste0(chart_details$id, "-data.csv.gz"))) {
# download data
# data_file <- tempfile()
# GET("https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/802314/outcomes-by-offence-tool-2018.xlsx", write_disk(data_file), progress())
# The downloaded data are in a .xls file, but the data are hidden in a pivot
# table rather than a simple sheet. The data can be revealed by *selecting all
# the cells* in the pivot table, right-clicking on the pivot table and
# clicking 'Show Details' then saving the resulting sheet as a CSV file
# read data
file_data <- read_csv("prison-likelihood-data-raw.csv")
# tidy data
tidy_data <- file_data %>%
# clean variable names
clean_names()
# save tidy data
write_csv(tidy_data, paste0(chart_details$id, "-data.csv.gz"))
} else {
# load tidy data
tidy_data <- read_csv(paste0(chart_details$id, "-data.csv.gz"))
}
```
```{r count total sentences, eval=FALSE, include=FALSE}
tidy_data %>%
filter(
year == 2018,
person_other == "01: Person",
offence_group != "12: Summary motoring"
) %>%
summarise(sentenced = sum(sentenced),
custody = sum(total_immediate_custody)) %>%
mutate(`custody proportion` = custody / sentenced) %>%
gather(key = "category", value = "count") %>%
mutate(count = ifelse(category == "custody proportion",
scales::percent(count, accuracy = 0.1),
scales::comma(count, accuracy = 1000)))
```
```{r prepare plot data}
chart_data <- tidy_data %>%
filter(year == 2018, person_other == "01: Person") %>%
mutate(detailed_offence = case_when(
offence == "1 Murder" ~ "murder",
str_detect(offence, "Sexual assault") | str_detect(offence, "^Indecent assault") ~
"sexual assault",
str_detect(offence, "Rape of") ~ "rape",
offence == "46 Theft from Shops" ~ "shoplifting",
str_detect(offence, "^92E") ~ "cannabis possession",
str_detect(offence, "Burglary") ~ "burglary",
offence == "8.10 Breach of a restraining order" ~
"breach of restraining order",
offence == "8.01 Assault occasioning actual bodily harm" ~
"causing actual bodily harm",
offence == "10D Possession of article with blade or point" ~
"possess bladed article",
str_detect(offence, "^53C") | str_detect(offence, "^53D") ~
"fraud by false representation",
offence == "34 Robbery" ~ "robbery",
offence == "41 Theft by an Employee" ~ "theft by employee",
str_detect(offence, "^92A.09") ~ "class A drug supply (e.g. cocaine)",
str_detect(offence, "^92A.10") ~ "class B drug supply (e.g. cannabis)",
str_detect(offence, "^92D.01") ~ "class A drug possession",
str_detect(offence, "grievous bodily harm") ~
"causing grievous bodily harm",
offence == "54 Handling Stolen Goods" ~ "handling stolen goods",
offence == "10C.2 Possession of other weapons - triable either way" ~
"possess offensive weapon",
offence == "44 Theft of Pedal Cycle" ~ "pedal cycle theft",
offence %in% c("130 Theft of a motor vehicle - summary (MOT)", "48 Theft of a motor vehicle (excl. aggravated vehicle taking) - triable either way (MOT)") ~
"motor vehicle theft/taking",
offence == "45 Theft from Vehicle" ~ "theft from motor vehicle",
TRUE ~ "other"
)) %>%
filter(detailed_offence != "other") %>%
mutate(age_group = as.character(fct_recode(
age_group,
"juvenile offenders" = "01: Juveniles",
"adult offenders" = "02: Young adults",
"adult offenders" = "03: Adults")
)) %>%
group_by(detailed_offence, age_group) %>%
summarise(sentenced = sum(sentenced),
custody = sum(total_immediate_custody)) %>%
ungroup() %>%
mutate(custody_prop = custody / sentenced)
# chart_data <- tidy_data %>%
# # filter(offence_type %in% c("01: Indictable only", "02: Triable either way")) %>%
# mutate(detailed_offence = case_when(
# offence == "1 Murder" ~ "murder",
# str_detect(detailed_offence, "^Sexual assault") ~ "sexual assault",
# str_detect(detailed_offence, "^Rape") ~ "rape",
# detailed_offence == "Theft from shops" ~ "shoplifting",
# detailed_offence == "Having possession of a controlled drug - class B (cannabis, including cannabis resin, cannabinol and cannabinol derivatives)" ~ "cannabis possession",
# str_detect(detailed_offence, "^Burglary") | detailed_offence == "Other burglary in a dwelling" ~
# "burglary",
# detailed_offence == "Breach of a restraining order" ~
# "breach of restraining order",
# detailed_offence == "Assault occasioning actual bodily harm" ~
# "causing actual bodily harm",
# detailed_offence == "Having an article with a blade or point in a public place" ~
# "possess bladed article",
# str_detect(detailed_offence, "^Fraud by false representation") ~
# "fraud by false representation",
# detailed_offence == "Robbery" ~ "robbery",
# detailed_offence == "Theft by an employee" ~ "theft by employee",
# str_detect(str_to_lower(detailed_offence), "cocaine") & str_detect(str_to_lower(detailed_offence), "supply") ~ "cocaine supply",
# str_detect(str_to_lower(detailed_offence), "cannabis") & str_detect(str_to_lower(detailed_offence), "supply") ~
# "cannabis supply",
# detailed_offence == "Having possession of a controlled drug - class A (cocaine)" ~
# "cocaine possession",
# detailed_offence %in% c("Wound/inflict grievous bodily harm without intent", "Wounding with intent to cause grievous bodily harm") ~
# "causing grievous bodily harm",
# str_detect(str_to_lower(detailed_offence), "stolen") & str_detect(str_to_lower(detailed_offence), "goods") ~ "handling stolen goods",
# detailed_offence == "Possession of offensive weapons without lawful authority or reasonable excuse" ~
# "possess offensive weapon",
# detailed_offence == "Theft of pedal cycle" ~ "pedal cycle theft",
# detailed_offence %in% c("Unauthorised taking or driving or attempt taking or driving of a motor vehicle", "Theft of a motor vehicle (excluding aggravated vehicle taking) - triable either way") ~
# "motor vehicle theft/taking",
# detailed_offence == "Stealing from vehicles: from motor vehicles" ~ "theft from motor vehicle",
# TRUE ~ "other"
# # TRUE ~ detailed_offence
# )) %>%
# filter(detailed_offence != "other") %>%
# # count(detailed_offence, wt = sentenced, sort = TRUE)
# mutate(
# age_group = as.character(fct_recode(age_group,
# "juvenile offenders" = "01: Juveniles",
# "adult offenders" = "02: Young adults",
# "adult offenders" = "03: Adults")),
# offence_group = as.character(fct_recode(
# offence_group,
# "violent or sexual crime" = "01: Violence against the person",
# "violent or sexual crime" = "02: Sexual offences",
# "violent or sexual crime" = "03: Robbery",
# "theft or fraud" = "04: Theft Offences",
# "theft or fraud" = "10: Fraud Offences",
# "other crime" = "06: Drug offences",
# "other crime" = "07: Possession of weapons",
# "other crime" = "09: Miscellaneous crimes against society"
# ))
# ) %>%
# group_by(offence_group, detailed_offence, age_group) %>%
# summarise(sentenced = sum(sentenced), custody = sum(immediate_custody)) %>%
# ungroup() %>%
# mutate(custody_prop = custody / sentenced)
offence_order <- chart_data %>%
filter(age_group == "adult offenders") %>%
arrange(desc(custody_prop)) %>%
pull(detailed_offence)
chart_data <- chart_data %>%
mutate(
age_group = factor(age_group),
detailed_offence = fct_rev(factor(detailed_offence, levels = offence_order))
)
# add chart labels
chart_labels <- tribble(
~x, ~y, ~xend, ~yend, ~age_group, ~label, ~hjust, ~vjust, ~curve,
20, 0.35, 18.5, 0.45, "juvenile offenders", balance_lines("most children convicted of rape (and all offences except murder) received a non-custodial sentence", 5), "left", "top", "left",
16, 0.66, 14.5, 0.76, "adult offenders", balance_lines("64% of adults convicted of burglary were imprisoned, compared to 17% of juveniles", 5), "center", "top", "left",
1, 0.04, 2, 0.34, "adult offenders", balance_lines("the maximum penalty for cannabis possession is 5 years in prison, but in practice almost no offenders were imprisoned", 5), "left", "bottom", "right",
) %>%
# order factor levels according to order in chart data, to maintain facet and
# legend order
mutate(
age_group = factor(age_group, levels = levels(chart_data$age_group))
)
```
```{r build plot}
chart <- ggplot(chart_data, aes(detailed_offence, custody_prop,
fill = age_group)) +
geom_col(width = 0.8) +
# add explanatory labels
geom_curve(aes(x = x, y = y, xend = xend, yend = yend),
data = filter(chart_labels, curve == "right"), inherit.aes = FALSE,
curvature = elements$label_line_curvature,
colour = elements$label_line_colour,
arrow = elements$label_arrow, show.legend = FALSE) +
geom_segment(aes(x = x, y = y, xend = xend, yend = yend),
data = filter(chart_labels, curve == "straight"),
inherit.aes = FALSE, colour = elements$label_line_colour,
arrow = elements$label_arrow, show.legend = FALSE) +
geom_curve(aes(x = x, y = y, xend = xend, yend = yend),
data = filter(chart_labels, curve == "left"), inherit.aes = FALSE,
curvature = elements$label_line_curvature * -1,
colour = elements$label_line_colour,
arrow = elements$label_arrow, show.legend = FALSE) +
geom_label(aes(x = xend, y = yend, label = label, hjust = hjust,
vjust = vjust),
data = chart_labels, inherit.aes = FALSE,
colour = elements$label_text_colour,
fill = elements$label_text_fill, size = elements$label_text_size,
lineheight = elements$label_text_lineheight,
label.size = NA, show.legend = FALSE) +
# end of explanatory labels
scale_y_continuous(limits = c(0, 1), labels = scales::percent_format(),
expand = expand_scale(mult = c(0, 0.03))) +
scale_fill_manual(
values = unname(ucl_colours_list[c("Light Blue", "Light Green")])
) +
coord_flip(clip = "off") +
facet_grid(cols = vars(age_group)) +
labs(
title = chart_details$title,
subtitle = format_subtitle(chart_details$subtitle, .width = 80),
x = NULL,
y = "proportion of sentences that were an immediate custodial sentence, 2018",
fill = NULL
) +
theme_cjcharts() +
theme(
axis.ticks.x = element_line(),
axis.ticks.y = element_blank(),
legend.position = "none",
panel.grid.major.x = element_line(),
panel.grid.minor.x = element_line(),
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.spacing = unit(1, "lines")
)
```
`r chart_details$subtitle`
```{r display plot, echo=FALSE, include=TRUE}
add_logo(chart + labs(title = NULL, subtitle = NULL),
chart_details$source_title, chart_details$id)
```
[larger image](../`r chart_details$id`.png)
| [annotated R code to produce this chart](https://github.com/mpjashby/lesscrime.info/blob/master/content/post/`r chart_details$id`.Rmd)
Data source: [`r chart_details$source_title`](`r chart_details$source_url`)
```{r export chart}
# save PNG for social media
ggsave(
filename = paste0(chart_details$id, ".png"),
plot = add_logo(chart, chart_details$source_title, chart_details$id),
device = "png", width = 600 / 72, height = 400 / 72, units = "in"
)
```
You can’t perform that action at this time.