library(ggplot2)
library(plotly)
library(kableExtra)
library(tidyverse)
library(forcats)
library(here)
library(readxl)
make_url <- function(x) {
paste(sprintf('<a href="%1$s">Link</a>', x),
collapse=",")
}
df <- read_excel("1507IndProsecutorCleaned.xlsx") %>%
mutate(State = sub(" -.*", "", State)) %>%
rename(location = `Prosecutor Office Location`,
position = `Prosecutor Position`,
first = `Local PA first`,
jurisdiction = `Jurisdiction`,
scope = `Scope of actions prosecuted`,
same = `Same office does investigation?`,
input = `Non-LE input of any kind`,
access = `Public access to results`)
We searched the National Conference of State Legislatures (NCSL) online database, using the keyword “prosecut”, for 2020 and 2021.
All bills that addressed prosecution of law enforcement officers for offenses of any type were included in our summary spreadsheet.
We coded information on: year, status, location of prosecution office, prosecutor position, whether local PA gets first shot, jurisdiction of the prosecutor, conditions of jurisdiction, scope of offenses, whether the same office also does the investigation, input by non-LE at any stage, and whether the public has access to the results.
This report breaks down the bills by the attributes above, and provides a table of all bills at the end, with a link to each bill, and a summary of the key elements.
We use the abbreviation “PA” throughout to refer to the local (County or District) Prosecuting Attorney.
Three bills stand out:
Minnesota s334 (pending) This bill sets up a completely independent permanent prosecutor, selected by a 3 member board that includes an impacted family member. The Governor selects the board, but does not play a role in selecting the prosecutor.
Michigan S668 (pending) Requires the local PA to report these cases to the AG and declare a COI, the AG then decides how to proceed.
California S710 (pending) This bill requires hierarchical recusals of the local PA, and state AG if they have received any monetary benefits, including campaign contributions, from an organization or association solely representing law enforcement. If both the PA and the AG have conflicts, a special prosecutor is appointed.
sjPlot::tab_xtab(var.row = df$State,
var.col = df$Year,
title = "Bills by State and Year",
show.summary = F,
emph.total = T)
State | Year | Total | |
---|---|---|---|
2020 | 2021 | ||
California | 1 | 2 | 3 |
Georgia | 1 | 1 | 2 |
Illinois | 0 | 1 | 1 |
Iowa | 1 | 1 | 2 |
Maryland | 0 | 1 | 1 |
Michigan | 0 | 1 | 1 |
Minnesota | 4 | 2 | 6 |
New Mexico | 0 | 1 | 1 |
New York | 1 | 5 | 6 |
Ohio | 1 | 0 | 1 |
Oregon | 1 | 0 | 1 |
Tennessee | 0 | 1 | 1 |
Texas | 0 | 2 | 2 |
Virginia | 1 | 0 | 1 |
Total | 11 | 18 | 29 |
df %>%
group_by(Status) %>%
count() %>%
ggplot(aes(x=reorder(Status, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Bill Status (as of 11/2021)",
x = "Status",
y = "Count")
df %>%
group_by(location) %>%
count() %>%
ggplot(aes(x=reorder(location, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Location of Prosecutor Office",
x = "Office location",
y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 0.95))
df %>%
group_by(position) %>%
count() %>%
ggplot(aes(x=reorder(position, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Prosecutor Position",
x = "Prosecutor",
y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 0.95))
sjPlot::tab_xtab(var.row = df$location,
var.col = df$position,
title = "Office location and position",
show.summary = F,
emph.total = T)
location | position | Total | |||||
---|---|---|---|---|---|---|---|
Attorney General |
District Atty General (local PA) |
Hierarchy of options | Multiple options |
Permanent Independent Prosecutor |
Temporary Special Prosecutor |
||
AG decides | 0 | 0 | 1 | 5 | 0 | 0 | 6 |
Attorney General’s Office |
15 | 0 | 0 | 0 | 1 | 1 | 17 |
Conditional on conflict |
0 | 0 | 1 | 0 | 0 | 0 | 1 |
Court appointed | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
District Atty General (local PA) |
0 | 1 | 0 | 0 | 0 | 0 | 1 |
Governor’s Office | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
Independent | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
Study committee | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
Total | 15 | 1 | 2 | 5 | 4 | 2 | 29 |
df %>%
filter(first != "n/a") %>%
group_by(first) %>%
count() %>%
ggplot(aes(x=reorder(first, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Local PA has initial jurisdiction",
x = "PA has initial jurisdiction",
y = "Count")
df %>%
group_by(jurisdiction) %>%
count() %>%
ggplot(aes(x=reorder(jurisdiction, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Type of Jurisdiction for Prosecutor",
x = "Jurisdiction",
y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 0.95))
df %>%
filter(!is.na(`Jurisdiction Conditions`)) %>%
select(c(Jurisdiction=jurisdiction, `Jurisdiction Conditions`)) %>%
arrange(Jurisdiction) %>%
kable() %>%
kable_styling(bootstrap_options = "striped")
Jurisdiction | Jurisdiction Conditions |
---|---|
Joint | AG leads, PA can be asked to collaborate |
Joint | AG leads, PA can be asked to collaborate |
Joint | AG leads, PA can be asked to collaborate |
Joint | AG leads, PA can be asked to collaborate |
Joint | Office of Special Investigation lead if: (1) lack of prosecutorial resources, (2) can’t effectively be conducted by local DA, (3) DA failed or refused, or (4) necessary to ensure public confidence |
Sole | Conflicts |
Sole | Conflicts |
Sole | AG if (1) lack of prosecutorial resources or (2) to ensure public confidence |
Sole | PA is disqualified |
df %>%
group_by(scope) %>%
count() %>%
ggplot(aes(x=reorder(scope, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Scope of actions prosecuted",
x = "Offenses",
y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 0.95))
df %>%
group_by(same) %>%
count() %>%
ggplot(aes(x=reorder(same, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Same office for Investigation and Prosecution?",
x = "Same office",
y = "Count")
df %>%
group_by(input) %>%
count() %>%
ggplot(aes(x=reorder(input, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Non-LE input of any kind",
x = "Input",
y = "Count")
df %>%
group_by(access) %>%
count() %>%
ggplot(aes(x=reorder(access, n, desc), y=n)) +
geom_bar(stat="identity", fill="blue", alpha = 0.7) +
labs(title = "Public access to results",
x = "Access",
y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 0.95))
df %>%
rowwise() %>%
mutate(urlclick = make_url(URL)) %>%
ungroup() %>%
select(State, Year, Status, URL=urlclick, Summary) %>%
arrange(State, Year) %>%
DT::datatable(rownames = F,
caption = "Bill Summaries and Links",
filter = 'top',
escape = FALSE)