library(tidyverse)
library(plotly)
library(kableExtra)
library(here)
library(leaflet)
library(lubridate)
library(icons)
library(htmlwidgets)
# get cleaned, merged data for WA
load(file = here("Data", "Clean", params$rdafile))

# Data prep (common)
source(here("Analyses", "Common", "waAnalysesPrep.R"))

# for geocoded LDs
with(homicides, write.csv(cbind(feID,latitude,longitude),
                          here("Data", "Clean",
                               "geocodes2015.csv")))

Introduction

This report tracks the trends in people killed by police in WA since 2015, a period that spans before and after a series of legislative reforms intended to reduce police violence and increase accountability for excessive force and misconduct. A brief overview of these changes is given in the Legislative History section of this report.

MOST RECENT DATA UPDATE (2025-11-04):

  • Total homicides by police since 2015: 457

  • Last reported case: Marvin Oliva Medina, 34 years old, on November 04, 2025 by King County Sheriff’s Office, Burien Police Department, Lakewood Police Department

    Marvin Oliva Medina is the 37th person killed by police in 2025. The cause of death is reported as vehicle and the manner of death appears to be motorcycle accident. This incident involved a police vehicular pursuit. https://komonews.com/news/local/man-dead-in-lakewood-motorcycle-crash

Before the 2021 legislative reforms, one out of every 6 persons killed in Washington state was killed during an encounter with law enforcement. (On average, about 250 homicide deaths were recorded each year in WA State from 2015-2020, with about 40 killed during encounters with police. You can view and download the state’s official death data here).

In 2021, the year many reforms passed, the number of people killed by police in Washington dropped by 60%, the largest decline seen in any state. More information on the temporal trends can be found in the section on “Trends over time”.


To find out more about what we do or get involved, please email us at Next Steps Washington


How to navigate this report

The TOC on the left can be used to navigate through the sections of the report. There are interactive maps with links to media reports, breakdowns by demographics, geography, cause of death, agency and time to provide some insight into the patterns and trends, and a list of all persons killed to acknowledge the lives lost and provide a starting point for those seeking more information on specific cases. Information on the data sources and limitations can be found in the Data sources section. The data and scripts used for this report are available on GitHub, access details can be found in the Public Access section.


Interactive Map

You can click the numbered circles to reach the individual map pointers for each person killed by police.

  • Hovering over the pointer brings up the name of the person killed and agency of the officer who killed them;

  • Clicking the pointer will bring up a url to a news article on the case (if available).

popup_text <- homicides %>%
  mutate(url_click_new = paste0("\"", url_click, "\"")) %>%
  select(url_click_new)

map <- leaflet(data = homicides, 
               width = "100%") %>% 
  addTiles() %>%
  addMarkers( ~ longitude,
              ~ latitude,
              popup = ~ popup_text$url_click_new,
              label = ~ as.character(paste(name, "by", agency)),
              clusterOptions = markerClusterOptions()
              )
map

Breakdowns

Race

Table

See the “Discussion” tab for more information on how race is ascertained and why the number of missing cases is so high.

tab <- homicides %>%
  mutate(race = case_match(race,
    "API" ~ "Asian/Pacific Islander",
    "BAA" ~ "Black/African American",
    "HL" ~ "Hispanic/Latinx",
    "NAA" ~ "Native American/Indigenous",
    "WEA" ~ "White/European American",
    .default = race),
    race = fct_relevel(race,  "Unknown", after = Inf)
  ) %>%
group_by(race) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  bind_rows(data.frame(race="Total", 
                       Number = sum(.$Number), 
                       Percent = sum(.$Percent))) %>%
  rename(Race = race) 

tab %>%
  kable(caption = "Breakdown by Race") %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  row_spec(row=dim(tab)[1], bold = T) %>%
  add_footnote(label = "Percents may not sum to 100 due to rounding",
               notation = "symbol")
Breakdown by Race
Race Number Percent
Asian/Pacific Islander 29 6.3
Black/African American 56 12.3
Hispanic/Latinx 66 14.4
Native American/Indigenous 20 4.4
White/European American 223 48.8
Unknown 63 13.8
Total 457 100.0
* Percents may not sum to 100 due to rounding

Plots

homicides %>%
  mutate(race = case_match(race,
    "API" ~ "Asian/Pacific Islander",
    "BAA" ~ "Black/African American",
    "HL" ~ "Hispanic/Latinx",
    "NAA" ~ "Native American/Indigenous",
    "WEA" ~ "White/European American",
    .default = race),
    race = fct_relevel(race,  "Unknown", after = Inf)
  ) %>%
  count(race) %>%
  mutate(perc = n / nrow(homicides)) %>%
  
  ggplot(aes(x=race, 
             y = perc, 
             label = n)) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  geom_text(aes(y = perc), size = 3, nudge_y = .025) +
  
  theme(axis.text.x = element_text(size=5.5)) +
  
  scale_y_continuous(labels = scales::percent_format(acc=1)) +
  
  labs(title = "Fatalities by Race",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; y-axis=pct, bar label=count")) +
         xlab("Reported Race") +
         ylab("Percent of Total")

homicides %>%
  mutate(raceb = case_when(race == "WEA" ~ "White",
                           race == "Unknown" ~ "Unknown",
                           TRUE ~ "BIPOC"),
         raceb = fct_relevel(raceb, "Unknown", 
                             after = Inf)) %>%
  count(raceb) %>%
  mutate(perc = n / nrow(homicides)) %>%
  ggplot(aes(x=raceb, 
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 3, nudge_y = .025) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  
  scale_y_continuous(labels = scales::percent_format(acc=1)) +
  
  labs(title = "Fatalities by Race",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; y-axis=pct, bar label=count")) +
  xlab("Reported Race") +
  ylab("Percent of Total")


Discussion

Racial disparities in the risk of being killed by police are one of the most important factors driving the public demand for police accountability and reform. For that reason it is important to understand how these numbers can, and cannot be used.

TL;DR While there are many uncertainties in the data that make it difficult/impossible to know the exact numbers, there are still some conclusions we can draw with confidence.


How is race identified in our data?

All crowd-sourced datasets rely primarily on media reports to find cases, and these media reports rarely include information on the race of the person killed. Each of the projects that provide data for this report has made additional efforts made to identify race.

  • MPV

The MPV project makes extensive additional efforts to identify the race of the person killed. From their data methodology page:

Our data has been meticulously sourced from official police use of force data collection programs in states like California, Texas and Virginia, combined with nationwide data from The Gun Violence Archive and the Fatal Encounters database, two impartial crowdsourced databases. We’ve also done extensive original research to further improve the quality and completeness of the data; searching social media, obituaries, criminal records databases, police reports and other sources to identify the race of 90 percent of all victims in the database.

  • Fatal Encounters

The FE project used a statistical imputation model to predict race for the missing cases. A brief description of the methodology is online here. They were able to impute just over half of the missing cases with reasonable confidence, and we use these imputations for the FE data in this report.

  • Incarcernation

The IN project do not provide a description of the methods they use for coding race, but their records typically include information on the race of the person killed, as well as a photo.

  • WA local

The local project conducts a search for coroner/ME reports, obituaries, multiple media reports and social media channels for information that can be used to assign the race of the person killed.

How often is race missing in our data?

We use a hierarchical assignment of race for the data in this report: MPV data when available, IN data when available, WA local data for cases not included in MPV or IN, and Fatal Encounters (FE) with imputation for cases uniquely contributed by FE.

tab <- homicides %>%
  mutate(race = factor(race),
         Race = fct_relevel(race, "Unknown", after = Inf)) %>%
  group_by(Race, Source=source) %>%
  count()  %>%
  
  pivot_wider(names_from = Race, values_from = n) %>%
  ungroup() %>%
  mutate(across(where(is.numeric), ~replace_na(., 0))) %>%

  add_row(Source = "Total", summarise(., across(where(is.numeric), sum))) %>%

  rowwise() %>%
  mutate(Total = sum(across(where(is.numeric))),
         "Unknown Pct" = round(100*Unknown/Total, 1)) %>%
  arrange(Total)


tab %>%
  kable(caption = "Breakdown by Source of Information") %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  row_spec(which(tab$source == "Total"), bold=T) %>%
  column_spec(which(names(tab)=="Total"), bold=T) %>%
  column_spec(which(names(tab)=="Unknown Pct"), italic=T) %>%
  add_footnote(label = "API = Asian and Pacific Islander; BAA = Black/African American; HL = Hispanic/Latino; NAA = Native American/Alaskan native; WEA = White/European American",
               notation = "symbol")
Breakdown by Source of Information
Source API BAA HL NAA WEA Unknown Total Unknown Pct
IN 0 4 3 2 4 3 16 18.8
FE 5 8 4 2 36 13 68 19.1
WA 11 18 29 5 85 23 171 13.5
MPV 13 26 30 11 98 24 202 11.9
Total 29 56 66 20 223 63 457 13.8
* API = Asian and Pacific Islander; BAA = Black/African American; HL = Hispanic/Latino; NAA = Native American/Alaskan native; WEA = White/European American

Bottom line: The unknown race cases make it impossible to say exactly how many people killed by police are in each racial group.


Reported vs. self-identified race

The race classification in our data represent the subject’s race as reported by by some other person – law enforcement, an ME/Coroner, a journalist, or a coder for one of the open-source projects that we draw from. It may be that person’s perception, or it may be informed by interactions with the subject’s friends or family, we have no way of knowing.

Bottom line: The accuracy of the race classification in the data we have is unknown.


We report the raw counts in this report, not per capita rates

Breaking the total count down by race, the largest single group of persons killed by police are identified as White/European-American: 49%

So, does this mean that we can say: “There aren’t any racial disparities in persons killed by police?”.

No. This raw count can not be used to assess racial disparities, because the word disparity implies the risk is “disproportionate” – that is, higher (or lower) than proportional. Proportional is a comparative term: it compares the proportion of fatalities by race, to the proportion of the population by race. If the two proportions are the same, then we can say there are no disparities. In this case, if 49% of the WA state population is White, only then would we be able to say that their risk of being killed by police is proportional to their share of the population.

Bottom line: The raw counts can not be used to identify racial disparities.


Why don’t we calculate standardized per capita rates?

We don’t calculate standardized per capita rates because the race categories our dataset are not consistent with the race categories used by the US Census. This is currently a limitation shared by all of the open-source datasets we rely on.

Per capita rates are calculated by taking the ratio of the fatality count (in the numerator) to the population count (in the denominator). This requires a consistent measure of race to use for the cases in the numerator and denominator - and we don’t have that. Census race categories are different for three reasons:

  • The Census allows for multiple race coding: About 5% of people in WA state report two or more races in the Census. This type of multiple-race classification does not exist in the data from any of our source datasets, and it is almost never used in reports on persons killed by police, law enforcement statistics, or official medical examiner reports. The likely reason for this is because the Census categories are self-reported – by the persons themselves – while race classification in the other settings is assigned by someone to another (deceased) person.

  • The Census categories for single race are different: The standardized Census categories for race are American Indian/Alaska Native, Asian, Black, Native Hawaiian/Pacific Islander, White. Slightly different versions are used in each of our source datasets.

  • The Census separates the coding of race from ethnicity: Hispanic/Latinx is an ethnicity that crosses several racial groups, primarily White, Black and Native American. In the US Census data, ethnicity is measured separately from race, so one can observe both values for each person. In all of our source datasets, “Hispanic” is coded as one of the racial classifications, rather than as a separate ethnicity classification, so the race of Hispanic persons can not be observed.

For more information on how the Census codes race and ethnicity:

U.S. Decennial Census Measurement of Race and Ethnicity Across the Decades: 1790–2020

Bottom line: The mismatch between racial categories coded in our data, and the categories used in the US Census makes it impossible to calculate per capita rates accurately for all groups.


What can we say about racial disparities in the police use of deadly force in WA State?

We can say that, while we can not estimate the disparities with precision, or for all groups, the the data do suggest there are racial disparities in the police use of deadly force in WA State.

The population of Washington State overwhelmingly identifies as White – 73% in the last US Census – while the fraction who identify as Black is 4% (2020, source: WA State OFM for this and all other population estimates in this section). The fraction (of all races) who report Hispanic ethnicity is 14%. If we restrict the focus to non-Hispanics, these fractions drop to 64% and 4% for those who identify as White and Black respectively.

For these three groups – non-Hispanic White, non-Hispanic Black and Hispanic – our source data are coded in a way that we can compare our data to the Census populations, if we make three assumptions:

  • First, that that cases classified as “White” or “Black” in the our datasets are not Hispanic – because they would be classified as Hispanic otherwise – and that cases classified as “Hispanic” in our dataset include all races.

  • Second, that the coding of race and Hispanic origin in our dataset are accurate, and

  • Third, that all race/Hispanic groups are equally likely to be coded as “unknown” race in our data.

Under these assumptions (or, to the extent that they hold) we can compare the fraction of each group in the fatality data to their fraction in WA population. The table below shows this, along with a summary based on the “risk ratio”.

The “risk ratio” is the ratio of the fatality share to the population share. When the two shares are the same, the risk ratio equals 1. When the risk ratio is less than one, this means the share of fatalities is lower than the population share; the risks are disproportionately low. When the risk ratio is greater than one it means the share of fatalities is larger than the population share; the risks are disproportionately high.

This can be translated into a relative risk percentage: 100*(risk ratio-1), representing the percent lower (or higher) the risk ratio is than expected if the risk was proportional to the share of population.

tab.all <- homicides %>%
  group_by(race) %>%
  summarize(all.cases = n()) %>%
  mutate(pct.all = round(100*all.cases/sum(all.cases), 1)) %>%
  filter(race %in% c("BAA", "HL", "WEA", "Unknown"))

tab.known <- homicides %>%
  filter(race != "Unknown") %>%
  group_by(race) %>%
  summarize(known.cases = n()) %>%
  mutate(pct.known = round(100*known.cases/sum(known.cases), 1)) %>%
  filter(race %in% c("BAA", "HL", "WEA")) %>%
  select(-known.cases)

tab.pop <- data.frame(race = c("BAA", "HL", "WEA"),
                      pct.pop = c(round(100*prop.nhb.census,1), round(100*prop.hisp.census, 1), 
                                  round(100*prop.nhw.census,1))
                      )

tab <- tab.all %>%
  left_join(tab.known) %>%
  left_join(tab.pop) %>%
  mutate(#rr.all = round((pct.all/pct.pop -1), 2),
         rr.known = round((pct.known/pct.pop - 1), 2)) %>%
  rename(Race=race, Fatalities=all.cases, "Percent (all cases)"=pct.all,
         "Percent (known race)"=pct.known, "Percent (WA pop)"=pct.pop, "Relative Risk" =rr.known) %>%
  mutate(Race = case_match(
    Race, "BAA" ~ "Black/African-American", 
    "HL" ~ "Hispanic/Latinx", 
    "WEA" ~ "White/European-American",
    .default = Race)
  )

tab %>% 
    kable(caption = "Police use of deadly force by race: Relative risks") %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  add_footnote(label = "Relative risks are calculated based on percent of fatalities with known race",
               notation = "symbol")
Police use of deadly force by race: Relative risks
Race Fatalities Percent (all cases) Percent (known race) Percent (WA pop) Relative Risk
Black/African-American 56 12.3 14.2 3.9 2.64
Hispanic/Latinx 66 14.4 16.8 14.1 0.19
White/European-American 223 48.8 56.6 64.1 -0.12
Unknown 63 13.8 NA NA NA
* Relative risks are calculated based on percent of fatalities with known race

In WA State:

  • For non-Hispanic Whites/European Americans this value is 100*( 57% / 64% -1) = -0.12 – their risk of being killed by police is 12% lower than expected.

  • For non-Hispanic Blacks/African Americans this value is 100*( 14% / 4% -1) = 2.66 – their risk of being killed by police is 266% higher than expected.

  • For Hispanics this value is 100*( 17% / 14% -1) = 0.19 – their risk of being killed by police is 19% higher than expected.

Note the direction of these disparities is robust to one of our assumptions: that each group is equally likely to be reported as “race unknown”. Even if we assume that all of the “Unknown” race cases are non-Hispanic White, their share of incidents, 63%, would still be below their share in the population. And if all of the unknown cases are assumed to be either non-Hispanic Black or Hispanic, that would actually increase the relative risks for these groups.

So, even though we can’t be certain of the exact value of the risk ratio, we can say with some confidence that there are racial disparities in the risk of being killed by police, and that these disparities indicate that non-Hispanic Whites are less likely than other racial groups to be killed by law enforcement officers, while non-Hispanic Blacks and Hispanics are more likely to be killed.

Bottom line: while the largest single group of persons killed by police in WA is identified as White, the risk ratio for this group, which adjusts for their share of the population, shows they are disproportionately less likely to be killed than those identified as Black or Hispanic.


Can we say anything about implicit bias?

Probably not. To use these data as evidence for (or against) the effects of systemic implicit bias in the police use of deadly force, we would need to know the officer’s perception of the subject’s race, and control for other variables that may influence these patterns, like the perceived and actual weapon status of the person killed, the circumstances that precipitated the incidents, the presence or absence of other persons at risk in the incidents, as well as the demographic composition of the jurisdiction.

Bottom line: We can’t use these data to answer the question of the officer’s subjective intention or implicit bias. But the data do support the argument that objective per capita disparities in risk by race exist.


Cause of death

The table shows all of the causes that appear in the dataset. The plot aggregates these into three categories, as the first two (shot and vehicle-related) account for the large majority of cases. Vehicle-related refers to deaths caused by vehicle crashes or getting run over by a car. Typically these occur in the context of vehicle pursuits/chases, but sometimes they are the result of fatal accidents caused by on-duty officers.

Plot

homicides %>%
  mutate(
    cod_3 = factor(
      case_when(
        cod == "Gunshot" ~ "shot", 
        grepl("Vehicle|Motorcycle", cod) ~ "vehicle-related",
        TRUE ~ "other"),
      levels = c("shot", "vehicle-related", "other"))
  ) %>%
  count(cod_3) %>%
  mutate(perc = n / nrow(homicides)) %>%
  ggplot(aes(x=cod_3, 
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 3, nudge_y = .025) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  labs(title = "Fatalities by Cause of Death",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; y-axis=pct, bar label=count")) +
  xlab("Cause of Death") +
  ylab("Percent of Total")

Table

tab <- homicides %>%
  group_by(cod) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  arrange(desc(Number)) %>%
  bind_rows(data.frame(cod ="Total", 
                       Number = sum(.$Number), 
                       Percent = sum(.$Percent))) 

tab %>%
  kable(caption = "Breakdown by Cause of Death",
        col.names = c("Cause of Death", "Number", "Percent")) %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  row_spec(row=dim(tab)[1], bold = T)  %>%
  add_footnote(label = "Percents may not sum to 100 due to rounding",
               notation = "symbol")
Breakdown by Cause of Death
Cause of Death Number Percent
Gunshot 318 69.6
Vehicle 90 19.7
Taser 12 2.6
Asphyxiated/Restrained 10 2.2
Multiple types of force 10 2.2
Drowned 9 2.0
Beaten 2 0.4
Burned/Smoke inhalation 2 0.4
Jumped to death 2 0.4
Drug overdose 1 0.2
Knife 1 0.2
Total 457 99.9
* Percents may not sum to 100 due to rounding

Alleged weapon

The source of this information is typically the initial press release or report to the media from the involved law enforcement agency; it is not always possible to get independent verification. So it should be interpreted as the alleged weapon status of the person who was killed.

Plot

homicides %>%
  count(weapon) %>%
  mutate(perc = n / nrow(homicides)) %>%
  ggplot(aes(reorder(weapon, perc),
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 3, nudge_y = .025) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  labs(title = "Fatalities by Alleged Victim Weapon",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; y-axis=pct, bar label=count")) +
  xlab("Alleged Weapon Used by Victim") +
  ylab("Percent of Total")

Video

This information comes from the MPV dataset, so is not available for the data from other sources. These additional cases are listed as “Unknown” below.

homicides %>%
  mutate(
    video = case_when(
      grepl("Body|Surv", bodycam) ~ "Yes",
      bodycam=="None" ~ "No",
      TRUE ~ "Unknown"),
    video = fct_relevel(video, "Unknown", 
                        after = Inf)) %>%
  group_by(video) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  bind_rows(data.frame(video ="Total", 
                       Number = sum(.$Number), 
                       Percent = sum(.$Percent))) %>%
  kable(caption = "Breakdown by video availability",
        col.names = c("Video", "Number", "Percent")) %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  row_spec(row=4, bold = T)  %>%
  add_footnote(label = "Percents may not sum to 100 due to rounding",
               notation = "symbol")
Breakdown by video availability
Video Number Percent
No 234 51.2
Yes 44 9.6
Unknown 179 39.2
Total 457 100.0
* Percents may not sum to 100 due to rounding

County

Washington State has 39 Counties. Since 2015 there have been people killed by police in 29 of them.

Plot

homicides %>%
  group_by(county) %>%
  summarize(n = n(),
            perc = n / nrow(homicides)) %>%
  ggplot(aes(reorder(county, perc),
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 3, nudge_y = .005) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  
  labs(title = "County",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; x-axis=pct, bar label=count")) +
  xlab("County where fatal encounter happened") +
  ylab("Percent of Total") +
  
  scale_y_continuous(labels = scales::percent_format(acc=1)) +
  
  coord_flip()

Table

homicides %>%
  group_by(county) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  DT::datatable(rownames = F,
                caption = "Breakdown by County")

Agency involved

  • The plot only shows agencies with 3 or more fatalities since 2015. Since there are more than 100 agencies with fatalities, the plot text would become impossible to read if all of them were included. Incidents with more than one agency involved are grouped together and labeled “Multiple Agencies”.

  • The table includes all agencies, all fatalities, and identifies the full list of agencies when there is more than one involved in the incident(s).

Plot

homicides %>%
  mutate(agencyR = ifelse(grepl(",", agency), "Multiple agencies", agency),
         agencyR = sub("Police Department", "PD", agencyR),
         agencyR = sub("Sheriff's Office", "SO", agencyR),         
         ) %>%
  group_by(agencyR) %>%
  summarize(n = n(),
            perc = n / nrow(homicides)) %>%
  filter(n > 2) %>%
  
  ggplot(aes(reorder(agencyR, perc),
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 2, nudge_y = .003) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  
  labs(title = "Agency responsible (agencies with > 2 fatalities only)",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; x-axis=pct of all incidents, bar label=count")) +
  xlab("") +
  ylab("Percent of Total") +
  
  # this works with the flipped axis id
  theme(axis.text.y = element_text(size=6)) +
  
  scale_y_continuous(labels = scales::percent_format(acc=1)) +
  
  coord_flip()

Table

homicides %>%
  group_by(agency) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  DT::datatable(rownames = F,
                caption = "Breakdown of Fatalities by Agency of Involved Officer",
                filter = 'top',
                escape = FALSE, 
                extensions = 'Buttons', 
                options = list(
                  dom = 'Bfrtip',
                  buttons = c('copy', 'csv', 'excel', 'pdf', 'print')) )

Legislative Districts

This information is obtained by geocoding the latitude and longitude data on the geocodio platform.

Washington State has 49 legislative districts. Since 2015 there have been people killed by police in 45 of them.

Given the number of districts involved, we only plot those with more than one fatality since 2015 for legibility .

The table includes all districts and all incidents.

Plot

homicides %>%
  group_by(WA_District) %>%
  summarize(n = n(),
            perc = n / nrow(homicides)) %>%
  filter(n > 1) %>%
  
  ggplot(aes(reorder(WA_District, perc),
             y = perc, 
             label = n)) +
  geom_text(aes(y = perc), size = 2, nudge_y = .003) +
  geom_bar(stat="identity", fill="blue", alpha=.5) +
  
  labs(title = "WA Legislative District (LDs with > 1 fatality only)",
       caption = paste0("WA State since ", 
                        params$from, 
                        "; x-axis=pct of all incidents, bar label=count")) +
  xlab("") +
  ylab("Percent of Total") +
  
  # this works with the flipped axis id
  theme(axis.text.y = element_text(size=6)) +
  
  scale_y_continuous(labels = scales::percent_format(acc=1)) +
  
  coord_flip()

Table

homicides %>%
  group_by(WA_District) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  DT::datatable(rownames = F,
                caption = "Breakdown of Fatalities by WA Legislative District",
                filter = 'top',
                escape = FALSE, 
                extensions = 'Buttons', 
                options = list(
                  dom = 'Bfrtip',
                  buttons = c('copy', 'csv', 'excel', 'pdf', 'print')) )

Online information availability

This takes the form of a single url to a news article that is available online. There are often multiple news articles available online, and they may report the conflicting details of the event, as well as conflicting perspectives on the justifiability of the use of lethal force. It provides definitive evidence of a fatality, but the information contained in the article should be treated as a place to start research, not as the definitive description of the event.

Clickable urls are available in this report in the Interactive Map and Say their names sections. When clicked, they will take you to the article.

tab <- homicides %>%
  mutate(url_info = case_when(url_info == "" ~ "No",
                               is.na(url_info) ~ "No",
                               TRUE ~ "Yes")) %>%
  group_by(url_info) %>%
  summarize(Number = n(),
            Percent = round(100*Number/nrow(homicides), 1)
  ) %>%
  bind_rows(data.frame(url_info ="Total", 
                       Number = sum(.$Number), 
                       Percent = sum(.$Percent))) 

tab %>%
  kable(caption = "URL for media reference",
        col.names = c("Availability", "Number", "Percent")) %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  row_spec(row=dim(tab)[1], bold = T) %>%
  add_footnote(label = "Percents may not sum to 100 due to rounding",
               notation = "symbol")
URL for media reference
Availability Number Percent
Yes 457 100
Total 457 100
* Percents may not sum to 100 due to rounding

Trend over time

There are two sets of plots here. The first focuses on the monthly totals, and how they have changed over time. The second focuses on the cumulative totals as the year progresses, and how this has changed over time.

# index restricted to first/last complete month
thisyr <- as.character(max(index$year))
prevyrs1 <- paste0(min(index$year), "-", max(index$year)-1)
prevyrs2 <- paste0(min(index$year), "-", last_complete_yr-1)

# left_join to index imposes same restriction
df_by_month <- homicides %>%
  group_by(year, month) %>%
  summarize(count = n()) %>%
  left_join(index, ., by = c("year", "mon"="month")) %>%
  mutate(count = tidyr::replace_na(count, 0),
         mo = match(mon, month.abb),
         mon = factor(mon, levels = month.abb),
         this.yr = factor(ifelse(year==max(year),
                                 thisyr,
                                 prevyrs1),
                          levels = c(prevyrs1, thisyr)),
         last.compl.yr = factor(ifelse(year==last_complete_yr,
                                 as.character(last_complete_yr),
                                 prevyrs2),
                          levels = c(prevyrs2, as.character(last_complete_yr))))

yrs <- as.numeric(lubridate::ymd(
  paste0(seq(min(index$year), max(index$year), 1), 
         "-", start_mo, "-01")))

Monthly totals

Trend

  • The points show the monthly totals, the grey line shows the smoothed average trend in monthly fatalities over time, and the grey shaded ribbon shows the 95% confidence interval around the trend line.

  • We only plot months once the data are complete, so the plot will lag 1-2 months behind the current date.

  • This is an interactive plot: You can hover over points to get the exact values for the number of cases for that month and year.

# we will only plot after current month has finished

p <- ggplot(df_by_month, aes(x = index.date, 
                     y = count))  +
  geom_point(size=1.5, shape=21, stroke=0.25,
             aes(fill = factor(year),
                 text = paste0(mon, ": ", count))) +
  geom_smooth(span = params$smooth_span, col="grey")  +
  
  # year boundaries
  geom_vline(xintercept = yrs, col="white", alpha=.5) +
  
  geom_hline(yintercept = 0, col="grey") +
  
  labs(title = paste("Monthly fatalities:",
                     month.abb[start_mo], start_yr, " - ",
                     month.abb[last_complete_mo], max(index$year)),
       x = "Month/Year",
       y = "Number",
       caption = paste("WA since", params$startyr),
       fill = "Year") +
  
  ylim(c(-2, NA)) + # min needs to be < smoother lower se
  
  scale_x_continuous(
    breaks = df_by_month$index.date[seq(1, nrow(df_by_month), 12)],
    label = df_by_month$year[seq(1, nrow(df_by_month), 12)]
    )  +
  
  scale_y_continuous(breaks = seq(0, 12, by=2)) +
  
  theme(axis.text.x = element_text(size = rel(0.8))) +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())

ggplotly(p, tooltip = "text") %>% 
  style(hoverinfo = "y", traces = 9) # use plotly_json(p) to verify

With key dates

This plot highlights key dates for legislation and legal actions related to police practices and accountability.

  • The \(\color{blue}{\textsf{blue lines}}\) are legislative/regulatory actions (940 passes, 940 WACs, and effective dates of legislation from 2021 forward). Solid lines are reform policies aimed at reducing police violence; dashed lines are partial rollbacks of these reforms.

  • The \(\color{red}{\textsf{red lines}}\) are legal actions (Ellis investigation taken over by AGO, ex-Officer Nelson charged in Jesse Sarey case, Officers Burbank Collins and Rankine charged in Ellis case). Solid lines are actions taken to hold officers accountable; dashed lines are acquittals and exonerations.

  • This is an interactive plot: You can hover over points to get the number of cases for that month, and hovering at the top or bottom of the vertical lines will identify the action.

p <- ggplot(df_by_month, 
            aes(x = index.date, y = count))  +
  geom_point(size=1.5, shape=21, stroke=0.25,
             aes(text = paste0(mon, ": ", count))) +
  geom_smooth(span = params$smooth_span, col="grey")  +
  
  # year boundaries
  geom_vline(xintercept = yrs, col="white", alpha=.5) +


  # reline y-axis in case yr[1] = start_date 
  geom_vline(aes(xintercept = as.numeric(start_date),
                 text = ""),
             col="grey", alpha=.8) +
  
  # key dates for prosecution
  geom_vline(aes(xintercept = as.numeric(date.ellis.ago),
                 text = "Ellis case taken over by AGO"),
             col="red", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.sarey.charged),
                 text = "Sarey case officer charged"),
             col="red", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.ellis.charged),
                 text = "Ellis case officers charged"),
             col="red", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.ellis.acquit),
                 text = "Ellis case officers acquitted"),
             col="red", lty=2, alpha=.8) +
    geom_vline(aes(xintercept = as.numeric(date.nelson.convicted),
                 text = "ex-Officer Nelson convicted of murder"),
             col="red", alpha=.8) +

  
  # key dates for legislation
  geom_vline(aes(xintercept = as.numeric(date.940.pass), 
                 text = "940 passes"), 
             col="blue", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.940.WAC), 
                 text = "940 WACs take effect"), 
             col="blue", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.2021.law), 
                 text = "2021 laws"), 
             col="blue", alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.2022.law), 
                 text = "2022 laws"), 
             col="blue", lty=2, alpha=.8) +
  geom_vline(aes(xintercept = as.numeric(date.2023.law), 
                 text = "2023 laws"), 
             col="blue", lty=2, alpha=.8) +
    geom_vline(aes(xintercept = as.numeric(date.2024.rollback), 
                 text = "2024 pursuit rollback"), 
             col="blue", lty=2, alpha=.8) +

  # zero axis
  geom_hline(yintercept = 0, col="grey") +
  
  labs(title = paste("Monthly fatalities with key dates:",
                     month.abb[start_mo], start_yr, " - ",
                     month.abb[last_complete_mo], max(index$year)),
       x = "Month/Year",
       y = "Number",
       caption = paste("WA since", params$startyr),
       fill = "Year") +
  
  scale_x_continuous(
    breaks = df_by_month$index.date[seq(1, nrow(df_by_month), 12)],
    label = df_by_month$year[seq(1, nrow(df_by_month), 12)]
    )  +
  
  scale_y_continuous(breaks = seq(0, 12, by=2)) +
  
  theme(axis.text.x = element_text(size = rel(0.8))) +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())

ggplotly(p, tooltip = "text") %>% 
  style(hoverinfo = "y", traces = 2)

This year vs. previous years

  • The points show the monthly totals for each year. They are color coded to highlight the current year.

  • The blue line shows the moving average for the monthly fatality rate for the 2015-2020 period, and the grey shaded ribbon shows the 95% confidence band around that average.

  • The black line shows the moving average for the monthly fatality rate for the current year. When this line lies outside the grey ribbon for the blue line, this suggests the difference between this year and previous years is larger than normal variation would predict.

  • We only plot months once the data are complete, so the plot will lag 1-2 months behind the current date.

  • This is an interactive plot: You can hover over points to get the month and year for each point.

# we will only plot after current month has finished

# make sure the factor levels match
this.yr.color = c("lightsteelblue", "black")
names(this.yr.color) <- levels(df_by_month$this.yr)
this.yr.alpha = c(0.5, 1)
names(this.yr.alpha) <- levels(df_by_month$this.yr)

p <- ggplot(data = df_by_month,
            aes(x = mo, y = count)) +
  
  geom_jitter(aes(col = this.yr,
                  alpha = this.yr,
                  text = mon.yr),
              width = 0, height = .1) +
  scale_color_manual(name="Year", 
                     values=this.yr.color) +
  scale_alpha_manual(values=this.yr.alpha) +
  guides(alpha = "none") +
  
  geom_smooth(data = df_by_month %>% filter(year != max(year)),
              color = "lightsteelblue") +
  geom_smooth(data = df_by_month %>% filter(year == max(year)), se=F,
              color = "black") +
  
  scale_x_continuous(breaks = seq(1,12,1), 
                     label = month.abb) +
  
  labs(title = paste0("WA since ", params$startyr, 
                     ":  Monthly totals with moving average"),
       caption = paste("WA since", params$startyr)) +
  xlab("Month") +
  ylab("Number of people killed")


ggplotly(p, tooltip = "text") %>% 
  style(hoverinfo = "y", traces = 3)

Last complete year vs. previous years

  • The points show the monthly totals for each year. They are color coded to highlight the current year.

  • The blue line shows the moving average for the monthly fatality rate for the 2015-2023 period, and the grey shaded ribbon shows the 95% confidence band around that average.

  • The black line shows the moving average for the monthly fatality rate for 2024, the last complete year. When this line lies outside the grey ribbon for the blue line, this suggests the difference between this year and previous years is larger than normal variation would predict.

  • This is an interactive plot: You can hover over points to get the month and year for each point.

# make sure the factor levels match
last.compl.yr.color = c("lightsteelblue", "black")
names(last.compl.yr.color) <- levels(df_by_month$last.compl.yr)
last.compl.yr.alpha = c(0.5, 1)
names(last.compl.yr.alpha) <- levels(df_by_month$last.compl.yr)

p <- ggplot(data = df_by_month %>% filter(year <= last_complete_yr),
            aes(x = mo, y = count)) +
  
  geom_jitter(aes(col = last.compl.yr,
                  alpha = last.compl.yr,
                  text = mon.yr),
              width = 0, height = .1) +
  scale_color_manual(name="Year", 
                     values=last.compl.yr.color) +
  scale_alpha_manual(values=last.compl.yr.alpha) +
  guides(alpha = "none") +
  
  geom_smooth(data = df_by_month %>% filter(year != last_complete_yr),
              color = "lightsteelblue") +
  geom_smooth(data = df_by_month %>% filter(year == last_complete_yr), se=F,
              color = "black") +
  
  scale_x_continuous(breaks = seq(1,12,1), 
                     label = month.abb) +
  
  labs(title = paste0("WA since ", params$startyr, 
                     ":  Monthly totals with moving average"),
       caption = paste("WA since", params$startyr)) +
  xlab("Month") +
  ylab("Number of people killed")


ggplotly(p, tooltip = "text")  %>% 
  style(hoverinfo = "y", traces = 3) # use plotly_json(p) to verify

Annual totals

Cumulative by month

  • The lines show the cumulative total fatalities by month as the year progresses, for each year.

  • We only plot months once the data are complete, so the plot will lag 1-2 months behind the current date.

# plotly doesn't handle the multiple legend properly so we don't use it here

# set up color palette for previous years:
n.yrs <- max(index$year) - params$startyr # num yrs excl this yr
paletteFunc <- colorRampPalette(c('blue', 'yellow', 'red'))
my.colors <- paletteFunc(n.yrs)


df <- df_by_month %>%
  group_by(year) %>%
  mutate(cumulative = cumsum(count),
         mon = factor(mon, levels=month.abb))

# Plot prev yrs separately and specify 2 aes (color, ltyp) to get 2 legends

ggplot(data= df %>% filter(year != max(df$year)),
       aes(x = mon, 
           y = cumulative, 
           color = factor(year),
           group = year)) +
  
  geom_line(size = 1, alpha = .4) +
  geom_point(aes(text = paste('Total =', cumulative, '<br>', 
                              mon, '<br>', year)),
                 size=1, alpha = .3) +
  scale_color_manual(values = my.colors) +

  geom_line(data = df %>% filter(year == max(df$year)),
            aes(x = mon, 
                y = cumulative,
                linetype = factor(year),
                text = paste('Total =', cumulative, '<br>', 
                             mon, '<br>', year)),
            color = "black", size = 2, alpha = 0.7) +
  scale_linetype_manual(name = "This Yr", values = c("solid")) +
  
  labs(title = paste0("WA since ", params$startyr,
                     ":  Cumulative fatalities by Month and Year"),
       x = "Month", 
       y = "Number of people killed",
       caption = paste("WA since", params$startyr),
       color = "Previous Yrs") +
  
  guides(linetype = guide_legend(order = 1),
         color = guide_legend(order = 2)
         )

#ggplotly(p, tooltip = "text")

By year

Calendar year

graphdf.calyr <- homicides %>%
  filter(year >= params$startyr) %>%
  group_by(Year = year) %>%
  summarize(Num = n())

p <- ggplot(graphdf.calyr,
       aes(x = Year, y = Num, 
           fill = Num,
           text = Num)) +
  
  geom_bar(stat = "identity", color="gray20") + 

  scale_fill_gradient(low = "seashell", high = "firebrick",
                      guide = "none") +
  
  scale_x_continuous(breaks = unique(graphdf.calyr$Year)) +
  
  annotate("text", 
           x = graphdf.calyr$Year[nrow(graphdf.calyr)], 
           y = graphdf.calyr$Num[nrow(graphdf.calyr)] + 1, 
           size = 3, label = "YTD") +
  
  labs(title = "People killed by police in WA by Year",
       x = "Calendar year",
       y = "Number killed")

ggplotly(p, tooltip = "text")

Legislative year

We start with the first complete legislative year.

graphdf.legyr <- homicides %>%
  filter(date > as.Date(params$startlegyr)) %>%
  group_by(leg.year) %>%
  summarize(Num = n())

p <- ggplot(graphdf.legyr,
       aes(x = leg.year, y = Num, 
           fill = Num,
           text = Num)) +
  
  geom_bar(stat = "identity", color="gray20") + 

  scale_fill_gradient(low = "seashell", high = "firebrick",
                      guide = "none") +
  
  scale_x_discrete(labels = function(x) 
    stringr::str_wrap(graphdf.legyr$leg.year, width = 8)) +
  
  theme(axis.text.x = element_text(size = 5)) +
  
  annotate("text", 
           x = graphdf.legyr$leg.year[nrow(graphdf.legyr)], 
           y = graphdf.legyr$Num[nrow(graphdf.legyr)] + 1, 
           size = 3, label = "YTD") +
  
  labs(title = "People killed by police in WA by Legislative Year",
       x = "Legislative year",
       y = "Number killed")

ggplotly(p, tooltip = "text")

By cause of death

Here we plot the cumulative totals each year, broken down to show the two leading causes of death.

  • The bars represent totals for each year, divided by cause of death: gunshot, vehicle pursuit and all other causes. A case is classified as a vehicle pursuit death if the cause of death was vehicular accident during an active or recently terminated vehicle pursuit.

  • Note that the current year only reflects cases for the year to date (November 10 2025), so is not strictly comparable with the previous years.

  • This is an interactive plot: You can hover over bar segments to get the exact values for that cause of death in that year.

Calendar year

graphdf.calyr <-  homicides %>%
  filter(year >= params$startyr) %>%
  mutate(
    cod_3 = factor(
      case_when(
        cod == "Gunshot" ~ "Shot", 
        grepl("Active|Terminated", pursuit.type) ~ "Vehicle pursuit",
        TRUE ~ "Other"),
      levels = c("Shot", "Vehicle pursuit", "Other")),
    year = as.character(year)) %>%
  group_by(year, cod_3) %>%
  summarize(n = n()) %>%
  mutate(percent = round(100*n / sum(n), 1))
  
p <- ggplot(graphdf.calyr,
            aes(x = year, y = n,
             fill = cod_3, 
             text = paste0("N=", n, 
                           " (", round(percent),"%)"))
         ) +
  
  geom_bar(stat="identity", alpha=.5, color = "grey",
           position = position_stack(reverse=T)) +
  
  annotate("text", 
           x = graphdf.calyr$year[nrow(graphdf.calyr)], 
           y = sum(graphdf.calyr$n[(nrow(graphdf.calyr)-2):nrow(graphdf.calyr)]) + 1, 
           size = 3, label = "YTD") +
  
  scale_fill_manual(values = c("cadetblue","darkorange3", "goldenrod")) +
  
  labs(title = paste0("Fatalities by Cause of Death and Year"),
       caption = paste("WA since", params$startyr),
       x = "Year",
       y = "Number",
       fill = "Cause of\nDeath")

ggplotly(p, tooltip = "text")

Legislative year

We start with the first complete legislative year.

graphdf.legyr <-  homicides %>%
  filter(date > as.Date(params$startlegyr)) %>%
  mutate(
    cod_3 = factor(
      case_when(
        cod == "Gunshot" ~ "Shot", 
        grepl("Active|Terminated", pursuit.type) ~ "Vehicle pursuit",
        TRUE ~ "Other"),
      levels = c("Shot", "Vehicle pursuit", "Other")),
    year = as.character(year)) %>%
  group_by(leg.year, cod_3) %>%
  summarize(n = n()) %>%
  mutate(percent = round(100*n / sum(n), 1))
  
p <- ggplot(graphdf.legyr,
            aes(x = leg.year, y = n,
                fill = cod_3, 
                text = paste0("N=", n, 
                              " (", round(percent),"%)"))
            ) +
  
  geom_bar(stat="identity", alpha=.5, color = "grey",
           position = position_stack(reverse=T)) +
  
  annotate("text", 
           x = graphdf.legyr$leg.year[nrow(graphdf.legyr)], 
           y = sum(graphdf.legyr$n[(nrow(graphdf.legyr)-2):nrow(graphdf.legyr)]) + 1, 
           size = 3, label = "YTD") +
  
  scale_fill_manual(values = c("cadetblue","darkorange3", "goldenrod")) +
  
  scale_x_discrete(labels = function(x) 
    stringr::str_wrap(unique(graphdf.legyr$leg.year), width = 8)) +
  
  theme(axis.text.x = element_text(size = 5)) +
  
  labs(title = paste0("Fatalities by Cause of Death and Legislative Year"),
       caption = paste("WA since", params$startyr),
       x = "Legislative Year",
       y = "Number",
       fill = "Cause of\nDeath")

ggplotly(p, tooltip = "text")

WA vs. other states

Here we report the annual totals up through the last complete year – 2024 – with data from the MPV project only, since MPV provides the only consistent national data series. This limits incidents to those meeting the MPV inclusion criteria, which includes people killed by police with firearms, tasers, asphyxiation and other uses of force, but excludes most pursuit related fatalities.

Compared to all other states

Population adjusted rate

The number of people killed is represented here as a population-adjusted rate per million residents, which makes it possible to compare states with different sized populations. The raw numbers are given on the next tab.

p <- ggplot(state.rates %>% filter(grepl("Washington|Other", state)), 
       aes(x=factor(year), y=rate, 
           group=state, fill=state,
           text =paste("rate: ", round(rate, 1)))) + 
  geom_col(alpha = 0.7) + #coord_flip() +
  facet_wrap(~state) +
  
  theme(axis.text.x = element_text(size = 6),
        axis.text.y = element_text(size = 8)) +
  
  labs(title = "Rate of persons killed by police: MPV data",
       x="Year", y="Rate per million residents")

ggplotly(p, tooltip = "text")

Number killed and annual percent change

kable(mpv_tab,
      caption = "Persons killed by police: MPV data",
      col.names = c("Year", rep(c("All other states", "WA"), 2)),
      digits = c(0,0,0,1,1),
      align = c("l",rep("r", 4))) %>%
  
  kable_styling(bootstrap_options = c("striped","hover"),
                full_width = F) %>%
  add_header_above(c("", "Number" = 2, "Percent Change" = 2 ))
Persons killed by police: MPV data
Number
Percent Change
Year All other states WA All other states WA
2015 1080 19 NA NA
2016 1038 27 -3.89% 42.1%
2017 1051 40 1.25% 48.1%
2018 1111 27 5.71% -32.5%
2019 1059 40 -4.68% 48.1%
2020 1126 35 6.33% -12.5%
2021 1134 14 0.71% -60.0%
2022 1163 41 2.56% 192.9%
2023 1226 22 5.42% -46.3%
2024 1236 33 0.82% 50.0%

State rankings 2024

Here we report the MPV data by state for the most recent complete year: 2024.

Number killed

  • States are ranked by the the number of persons killed in 2024.

  • The bar for WA State is highlighted with a black border.

  • These are interactive plots: You can hover over bars to get the exact values for the number of persons killed in 2024.

p <- ggplot(data = states.all %>% filter(!grepl("United|Other", state)),
            aes(x=killed2024, y=reorder(state, killed2024), 
                fill = killed2024,
                color = factor(ifelse(state=="Washington", 1, 0)),
                text=paste(state, 
                           "total:", killed2024))) +
              
  geom_col() +
    
  scale_color_manual(values = c("grey", "black")) +
  scale_fill_gradient2(
    low = "blue", 
    mid = "white", 
    high = "red", 
    midpoint = median(states.all$killed2024)) +
  #scale_x_continuous(labels = scales::percent) +
  
  theme(axis.text.y=element_text(size=rel(.7)), legend.position = "none") +
  labs(title = paste("State ranking: Number of persons killed by police in", last_complete_yr),
       x="Number killed",
       y="State")

ggplotly(p, tooltip = "text")

Population-adjusted rate

  • States are ranked by the population adjusted rate of persons killws in 2024: the rate per million state residents.

  • The bar for WA State is highlighted with a black border.

  • These are interactive plots: You can hover over bars to get the exact values for the rate of persons killed in 2024.

p <- ggplot(data = states.all %>% filter(!grepl("United|Other", state)),
            aes(x=ratekilled2024, y=reorder(state, ratekilled2024), 
                fill = ratekilled2024,
                color = factor(ifelse(state=="Washington", 1, 0)),
                text=paste(state, 
                           "total:", round(ratekilled2024, 1)))
            ) +
              
  geom_col() +
    
  scale_color_manual(values = c("grey", "black")) +
  scale_fill_gradient2(
    low = "blue", 
    mid = "white", 
    high = "red", 
    midpoint = median(states.all$ratekilled2024)) +
  #scale_x_continuous(labels = scales::percent) +
  
  theme(axis.text.y=element_text(size=rel(.7)), legend.position = "none") +
  labs(title = paste("State ranking: Population adjusted rate of persons killed by police in", last_complete_yr),
       x="Rate per million residents",
       y="State")

ggplotly(p, tooltip = "text")

Change from previous year

  • States are ranked by the percent change in the number of persons killed from 2023 to 2024.

  • The bar for WA State is highlighted with a black border.

  • These are interactive plots: You can hover over bars to get the exact values for the number of persons killed in 2024 year, and the percent change from the previous year.

df <- states.all %>% 
  filter(!grepl("United|Other", state)) %>%
  select(state, killed2023:killed2024) %>%
  mutate(pct.chg = killed2024/killed2023 -1)

p <- ggplot(data = df,
            aes(x=pct.chg, y=reorder(state, pct.chg), 
                fill = pct.chg,
                color = factor(ifelse(state=="Washington", 1, 0)),
                text=paste0(state, 
                           paste("<br>", "number killed in ", last_complete_yr, ": ", killed2024),
                           paste("<br>", "change from last year: ", scales::percent(pct.chg, acc = 1))))
            ) +
              
  geom_col() +
    
  scale_color_manual(values = c("grey", "black")) +
  scale_fill_gradient2(
    low = "blue", 
    mid = "white", 
    high = "red", 
    midpoint = 0) +
  scale_x_continuous(labels = scales::percent) +
  
  theme(axis.text.y=element_text(size=rel(.7)), legend.position = "none") +
  labs(title = paste("State ranking: % change in number of persons killed by police",
                     last_complete_yr-1, "-", last_complete_yr),
       x="Percent change",
       y="State")

ggplotly(p, tooltip = "text")

Say their names

Name known

Of the 457 persons killed by police, 432 of the victim’s names are known at this time. In the table below “WA-LD” refers to the Washington state legislative district.

NOTE: There are 2 tabs above, one for the names we do know, the other for the names we don’t yet know. Selecting a tab will display the associated table.

homicides %>%
  mutate(date = as.Date(date)) %>%
  arrange(desc(date)) %>%
  #mutate(date = format(as.Date(date), format = "%m/%d/%Y")) %>% can't use format, sorting fails
  filter(name != "Unknown") %>%
  select(name, date, age=age, race, county, `WA-LD`=WA_District, 
         agency, link = url_click) %>%
 
  DT::datatable(rownames = F,
                caption = paste("The Names We Know:  as of", scrape_date),
                filter = 'top',
                escape = FALSE, 
                extensions = 'Buttons', 
                options = list(
                  dom = 'Bfrtip',
                  buttons = c('copy', 'csv', 'excel', 'pdf', 'print')) )

Name Unknown

The remaining 25 of the victim’s names are not known at this time. In the table below “WA-LD” refers to the Washington state legislative district.

homicides %>%
  mutate(date = as.Date(date)) %>%
  arrange(desc(date)) %>%
  filter(name == "Unknown") %>%
  select(name, date, age=age, race, county, `WA-LD`=WA_District, 
         agency, link = url_click) %>%
  arrange(desc(date)) %>%
  DT::datatable(rownames = F,
                caption = paste("The Names We Don't Know:  as of", scrape_date),
                filter = 'top',
                escape = FALSE, 
                extensions = 'Buttons', 
                options = list(
                  dom = 'Bfrtip',
                  buttons = c('copy', 'csv', 'excel', 'pdf', 'print')) )

Appendices

Legislative history

Police accountability and reform has been an active topic in the Washington state legislature since 2018. Changes have been achieved via both citizen initiative and traditional bills.

One of the first major legislative reforms was Initiative 940. I-940 established de-escalation training requirements, independent investigations of all homicides by police and changed the criminal accountability standard from malice to reasonable officer. It passed with over 60% of the statewide vote in the 2018 November general election, becoming WA state law on December 6, 2018. Certain provisions took effect later: amendments by HB 1064 took effect February 4, 2019, and the first Washington Administrative Code (WAC) requirements took effect January 6, 2020. The WAC is reviewed and updated annually.

In the 2021 legislative session (Jan - April) several bills were passed on a range of issues relating to police reform.

  • HB 1054 Established limits on the use of police tactics like neck restraints, canines, tear gas and pursuits, prohibited the use of military equipment, and required police to be identifiable.

  • HB 1088 Required agencies to forward Brady impeachment information for their officers to the local county prosecutor, request Brady information from prosecutors during the hiring process, and report the hiring of officers with prior potential impeachment disclosure to the prosecutor.

  • HB 1267 Established a statewide Office of Independent Investigations to investigate all incidents of police use of deadly force.

  • HB 1089 Established state audits of all independent investigations of police use of deadly force.

  • HB 1310 Established requirements for deescalation and restrictions on the use of force and deadly force.

  • SB 5051 Provided oversight and decertification authority for the WA Criminal Justice Training Commission.

  • SB 5259 Established a statewide police use of force data collection program.

Other important bills passed in 2021 include SB 5066 which established a duty for officers to intervene when their colleagues use excessive force, and HB 1140 which requires that juveniles be provided access to attorneys.

The year these reforms passed the number of people killed by police in Washington dropped by 60%, the largest decline seen in any state. More information on the temporal trends can be found in the section on “Trend over time”.

Some changes have been made to the 2021 reforms in subsequent sessions:

  • In 2022 HB 2037 modified the policy on use of force during Terry Stops allowing force to be used to prevent a person from fleeing.

  • In 2023 SB 5352 modified the policy on vehicular pursuits, reducing the standard of evidence from probable cause to reasonable suspicion, adding some offenses to the list of pursuit-eligible offenses, and relaxing the supervisory authorization requirements.

  • In 2024 Initiative 2113 further modified the statewide pursuit policy, eliminating the specific list of offenses that restricted pursuits to violent felonies, and allowing them for any suspected criminal offense.


Data sources

Where the data come from

This report is based on a locally maintained dataset focused on WA State. The data are updated about once each week, pulling, cleaning and merging data from two active national projects:

We incorporate data from one legacy project:

And the data from another legacy project are preserved in the cases from MPV:

In addition we conduct independent searches for incidents in WA state that these national projects may have missed, using a mix of google alerts and searches of WA-specific sources like medical examiner reports, independent investigation reports, social media, obituaries and public disclosure requests.

The primary data source is MPV, but due to coverage limitations in the MPV project (primarily the exclusion of most pursuit-related fatalities) we augment their data with cases from IncarcerNation, legacy data from Fatal Encounters and locally identified incidents. Cases are linked and de-duplicated across source datasets, and all records in the final merged dataset include the original source case IDs.


For the purposes of this report, we call the resulting dataset the WA local dataset.


Breakdown by source of data

The breakdown of the data by source is shown in the tabs below. Many incidents are included in more than one dataset, some are included only in one, and there are multiple ways to present the coverage of each source and pattern of overlap.

Source coverage

The coverage of each data source can be assessed by the presence of the source ID tags by year, shown below. The columns for each data source show the number of cases with that source ID tag. The “Total Cases” column in the table represents the total cases in that year, not the sum across the data sources. Comparing the number of cases in each of the Data Source columns to each other and the total gives a sense of what fraction of that year’s cases were covered by each source, the overlap across the sources, and how that varies by year.

tab <- homicides %>%
  group_by(Year = as.character(year)) %>%
  summarize(FE = sum(!is.na(feID)),
            IN = sum(!is.na(inID)),
            MPV = sum(!is.na(mpvID)),
            WaPo = sum(!is.na(wapoID)),
            WaLocal = sum(!is.na(waID)),
            Total.Cases = n()
  ) %>%
  mutate(Percent = round(100*Total.Cases/sum(Total.Cases), 1)) %>%

  add_row(Year = "Total", summarise(., across(where(is.numeric), sum)))

tab %>%
  kable(caption = "Source Coverage by Year") %>%
  kable_styling(bootstrap_options = c("striped","hover")) %>%
  add_header_above(header = c(" " = 1, "Data Source" = 5, "De-duplicated yearly totals"=2)) %>%
  row_spec(dim(tab)[1], bold = T)  %>%
  column_spec(which(names(tab)=="Cases"), bold=T) %>%
  column_spec(which(names(tab)=="Percent"), italic=T) %>%

  add_footnote(label = "Percents may not sum to 100 due to rounding",
               notation = "symbol")
Source Coverage by Year
Data Source
De-duplicated yearly totals
Year FE IN MPV WaPo WaLocal Total.Cases Percent
2015 19 0 19 16 1 20 4.4
2016 35 0 27 26 1 36 7.9
2017 51 0 40 38 1 52 11.4
2018 37 0 27 23 1 38 8.3
2019 50 0 40 36 0 50 10.9
2020 53 0 35 31 1 54 11.8
2021 25 25 14 13 0 25 5.5
2022 0 45 41 38 53 53 11.6
2023 0 35 22 22 37 37 8.1
2024 0 51 33 32 55 55 12.0
2025 0 31 16 0 37 37 8.1
Total 270 187 314 275 187 457 100.0
* Percents may not sum to 100 due to rounding
Source overlap by year

Each case in the dataset can also be identified by the number of sources that include it, a direct measure of the overlapping sources of information. The breakdown of source overlap by year is shown below.

tab <- homicides %>% 
  count(source.overlap, Year = as.character(year)) %>% 
  pivot_wider(names_from=source.overlap, values_from=n) %>% 
  mutate(across(where(is.numeric), ~replace_na(.,0))) %>%
  rowwise() %>%
  mutate(Total = sum(c_across(where(is.numeric)))) %>%
  ungroup() %>%
  add_row(Year = "Total", summarise(., across(where(is.numeric), sum)))
  
tab %>%
  kableExtra::kbl(caption = "Breakdown of fatalities by number of data sources and year") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  add_header_above(header = c(" " = 1, "Data Source(s) *" = 4, " " = 1)) %>%
  row_spec(which(tab$Year == "Total"), bold=T) %>%
  add_footnote(label = "Most records in MPV and WA can be found in multiple sources, see other tabs for details on the overlap",
               notation = "symbol")
Breakdown of fatalities by number of data sources and year
Data Source(s) *
Year 1 2 3 4 Total
2015 1 3 16 0 20
2016 1 1 34 0 36
2017 1 2 49 0 52
2018 1 4 33 0 38
2020 1 4 49 0 54
2022 7 6 3 37 53
2023 5 10 1 21 37
2024 9 13 2 31 55
2025 11 10 16 0 37
2019 0 4 46 0 50
2021 0 0 1 24 25
Total 37 57 250 113 457
* Most records in MPV and WA can be found in multiple sources, see other tabs for details on the overlap

Primary source

When MPV includes an incident, that is our starting point for that case. Incidents from the other datasets are incorporated only when they fall outside of MPV’s inclusion criteria. In the table below, we show the primary source of cases by year: all cases covered by MPV are listed in that column, the additional cases contributed from FE (2015-21), IN (2021+) and WA local (2022+) are shown in the other columns.

tab <- homicides %>% 
  mutate(Source = factor(
    case_when(
      !is.na(mpvID) ~ "MPV",
      !is.na(inSource) ~ "IN",
      !is.na(feID) ~ "FE",
      !is.na(waID) ~ "WA local",
      TRUE ~ "other"),
    levels = c("MPV", "FE", "IN", "WA local"))
  ) %>%
  count(Source, Year = as.character(year)) %>% 
  pivot_wider(names_from=Source, values_from=n) %>% 
  mutate(across(where(is.numeric), ~replace_na(.,0))) %>%
  rowwise() %>%
  mutate(Total = sum(c_across(where(is.numeric)))) %>%
  ungroup() %>%
  add_row(Year = "Total", summarise(., across(where(is.numeric), sum)))
  
tab %>%
  kableExtra::kbl(caption = "Primary data source by year") %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  add_header_above(header = c(" " = 1, "Data Source *" = 4, " " = 1)) %>%
  row_spec(which(tab$Year == "Total"), bold=T) %>%
  add_footnote(label = "Most records in MPV and WA can be found in multiple sources, see other tabs for the overlap",
               notation = "symbol")
Primary data source by year
Data Source *
Year MPV FE IN WA local Total
2015 19 0 0 1 20
2016 27 8 0 1 36
2017 40 11 0 1 52
2018 27 10 0 1 38
2019 40 10 0 0 50
2020 35 18 0 1 54
2021 14 11 0 0 25
2022 41 0 1 11 53
2023 22 0 4 11 37
2024 33 0 6 16 55
2025 16 0 5 16 37
Total 314 68 16 59 457
* Most records in MPV and WA can be found in multiple sources, see other tabs for the overlap

Source dataset descriptions

Mapping Police Violence

Data: 2013+

Mapping Police Violence (MPV) aims to establish a comprehensive national open-source dataset of homicides by police, on and off duty. It includes fatal shootings and fatalities caused by tasers, physical beatings, restraint holds, chemical spray, police dog attacks, less-lethal force and vehicular homicides. Vehicular homicides are included in MPV only when the fatalities are directly caused by a police action: intentionally running someone over, and intentional collisions and vehicle disabling during a pursuit that leads to a fatal accident. As they note on their methodology page, these criteria result in the exclusion of most vehicle pursuit-related fatalities. However they also note that they have begun to track these pursuits internally, so their coverage may change in the future.

MPV has incorporated historical data from two legacy projects:

MPV merged and deduplicated the incidents from these two datasets, removed incidents that did not meet their inclusion criteria, added eligible incidents that were missed by both projects, kept the information from both datasets on the included incidents, and is now augmenting all incidents (back through 2013) with additional information, as well as updating with new incidents.

MPV is a project of the Campaign Zero organization. It follows the principles of transparent reproducible research, with a systematic, multi-level review and coding process that is published on their methodology page (recommended reading), and datasets provided in downloadable form to the public.

We download the MPV data from here: https://mappingpoliceviolence.us/s/MPVDatasetDownload.xlsx.


IncarcerNation

Data: 2021+

IncarcerNation (IN) maintains a comprehensive, searchable website listing every fatality that has occurred during any police encounter in the United States, regardless of type, and without judgment. This includes deaths from direct police use of force [gunshots, tasers, K9, and other immediate lethal police action], as well as fatalities linked to police activities and interactions controlled by police that lead to death. These encompass high-speed pursuits (including deaths of drivers, passengers, bystanders, and pedestrians), collisions involving police vehicles, drownings during police chases, falls from heights during pursuit, asphyxiation during restraint, and suicides occurring in the context of police operations, often during SWAT incidents. (taken from their “About Us” page).

IN’s inclusion criteria are therefore much broader than MPV’s, and they are the only actively updating project with coverage equivalent to the legacy Fatal Encounters project. While most of their incidents overlap with MPV, they are the unique source for pursuit-related fatalities.

IN does not make their dataset downloadable for the public, so we manually review and transcribe information only for the cases they list for Washington state. During transcription, duplicate cases, cases from Washington DC and cases that turned out to be non-police related homicides are excluded. Many of the IN cases are also covered by MPV and the local WA project, but when IN is the primary source of information, we note that.


Fatal Encounters

Data: 2000-2021

Fatal Encounters (FE) is a legacy project that sought to establish a comprehensive national open-source dataset of all deaths during encounters with police. This project was active through December 31, 2021, includes records going back to 2000, and produced the largest compilation of persons killed during encounters with police that is publicly available: 31,641 fatalities at the time the project ended. It covers deaths by all causes during a police encounter, including suicides, accidents, killings by off-duty police and vehicular pursuit related fatalities. The vehicular pursuit coverage in FE is broader than MPV, as it includes all fatalities from accidents during a pursuit, so it captures bystanders killed by the fleeing subject.

Legacy FE data are captured by the dataset used in this report in two ways:

  • Cases included in the MPV dataset.

  • Cases excluded by MPV are recovered and included by us. They are used in this report, subject to the exclusions noted in a later section.

We originally downloaded the FE data from their website: https://docs.google.com/spreadsheets/d/1dKmaV_JiWcG8XBoRgP8b4e9Eopkpgt7FL7nyspvzAsE/edit?gid=0#gid=0

We made many corrections to the FE data and harmonized the variables while FE was still updating. The scripts for that can be found on our legacy GitHub repository: https://github.com/nextstepswa/fewapo. We now just read in the cleaned, harmonized data (included in our current GitHub repository).


Washington Post

Data: 2015-2025

The Washington Post Fatal Force (WaPo) dataset is a legacy project that sought to create a national database of fatal shootings by on-duty police. It was actively updating from January 1, 2015 through December 31, 2024. There were 10,429 fatalities recorded at the time the project ended.

  • WaPo historical data has been incorporated by the MPV project into their database, and is integrated into the WA local dataset via MPV.

The WaPo data can be downloaded from their GitHub repository here: https://github.com/washingtonpost/data-police-shootings.


For all of our data sources, it is worth noting that:

  • None include deaths in custody after booking – so all deaths in jails and prisons are excluded.

  • All sources may be missing incidents.

A comparison of the cases found in each dataset is presented in the next section of this report.

There has typically been a 1-2 week lag in MPV updates, but it can sometimes be longer. The date shown in the “most recent data update” tab above is an indication of the current lag. As of this report, the last data updates were:

  • October 31 2025 for Mapping Police Violence
  • November 04 2025 for IncarcerNation
  • November 04 2025 for the WA local data

This report is restricted to the cases that can be classified as homicides by police and vehicular homicides during police pursuits, it excludes cases where the cause of death during the police encounter is ruled a suicide (see the next section for details).


Open-source vs. Official datasets

All of the data sources we draw from are open-source, “unofficial” datasets. The data are not drawn from mandatory government reporting on deaths caused by law enforcement officers because there is no official national data program designed for this purpose that is currently functioning. The open-source datasets rely on cases known/discovered by the respective project teams, primarily identified using a battery of online searches and a mix of automated and manual coding.

In theory, deaths caused by police should also be captured by several official data collection programs:

  • the National Vital Statistics System, which collects death certificates.

  • the Arrest Related Death program, run by the Bureau of Justice Statistics (BJS), ended in 2012.

  • the Supplementary/Expanded Homicide Reports program, run by the the Federal Bureau of Investigation (FBI), based on the Uniform Crime Reporting program.

  • the National Violent Deaths Reporting System, a newer program run by the Centers for Disease Control and Prevention (CDC), all states reporting as of 2018, though reporting is not yet complete for the recently added states. WA State has been reporting from all counties as of 2018; more information can be found here.

  • the National Use of Force reporting program run by the FBI. Qualifying uses of force include any action that resulted in the death or serious bodily injury of a person, or the discharge of a firearm at or in the direction of a person. Agency participation is voluntary, data collection began in 2019. In 2025, 12,035 out of 19,277 federal, state, local, and tribal law enforcement agencies throughout the nation participated and provided use-of-force data. The officers employed by these agencies represent 78% federal, state, local, and tribal sworn officers in the nation. This is below the 80% coverage level required to release national data to the public. For WA, 51 out of 276 agencies in Washington participated, representing 48% of sworn law enforcement officers in the state. Among participating agencies the number reporting use of force ranged from 0 to 3 agencies each month over the last 12 months of data.

Why we don’t use the official data

  • Studies have repeatedly shown that official programs consistently fail to identify about half of the people killed by police.

The most recent study to have replicated this finding was conducted by the Institute for Health Metrics and Evaluation in 2021, and published in the Lancet. You can access the study here, and less technical summaries can be found in the news media. Other studies show similar rates of undercounting in the Arrest Related Death and Supplementary Homicide Reporting systems, one example is here.

The one exception to this is the National Violent Deaths Reporting system. A study from 2016 showed that NVDRS had better coverage of police killings than the other federal sources, and another study from 2015 found that it captured almost all of the people shot and killed by police in the 27 states that were participating in the program at the time – but note that the number used to assess NVDRS coverage was based largely on the number found in open-source datasets. There has been no update since the state coverage reached all 50 states in 2018, and there has been no assessment of its coverage of deaths due to causes other than gunshot. Perhaps most importantly, the 2015 study simply showed that this dataset had comparable coverage to the open-source datasets, not that it was superior.

  • Federal research has also shown that the methodology used by the open-source data sets is effective

A 2019 assessment by the Bureau of Justice Statistics (BJS) concluded that:

“Findings indicate that the open-source methodology alone identifies the majority of law enforcement homicides, but agency surveys aid in identifying deaths by other causes (e.g., accidents, suicides, and natural causes).” BJS 2019

  • Official datasets lack contextual information

The other key benefit to the open-source datasets is that every case includes a link to publicly available documentation that verifies the case and serves as a starting place for additional research. This allows us to identify the law enforcement agency(ies) involved, provides more context and sometimes reveals conflicting narratives as to the events. All of this helps to remind us that each case is a person, not just a statistic.


At this point, it is widely acknowleged that the open-source datasets have the most complete coverage of these cases. That is why we use them here.


That said, it is important to keep in mind that these open-source datasets, too, are not perfect. They will miss cases that have not generated a digital signature that can be found using their search methodologies. So it would be accurate to say that our open-source data provide a lower bound estimate of the number of people killed by police; the true value is likely higher, but it can not be lower.

Exclusions

Cases reported as suicides and coded as “Medical Emergencies” are excluded from the analyses in this report.

Suicides

FE, IN and WA local include some cases classified as “suicides” that occur during an encounter with police. These are not cases of “suicide by cop”, where the victim appears to have provoked the police in order to be killed. They are cases where the victim shoots or otherwise takes their own life. We have excluded these from the analyses in this report, because the report focuses on persons killed by police.

We acknowledge that these cases warrant further assessment. It is not uncommon that officers did shoot at the suspect, but missed or failed to kill them. In addition the classification as “suicide” may not be definitive, if it is based on the narrative provided by law enforcement to the media at the time rather than a subsequent investigation by the local coroner or medical examiner. Finally, even if these are suicides, it is possible that the outcome might have been different if the case had been handled differently, for example, by calling in a crisis intervention team and deescalating effectively.

The excluded case counts and fraction of total cases by year is shown in the table below.

tab <- wa_clean_2015 %>%
  mutate(suicide = if_else(mod=="Suicide", "Suicide", "All other deaths")) %>%
  group_by(Year=year, suicide) %>%
  count() %>%
  pivot_wider(names_from = suicide,
              values_from = n)%>%
  replace_na(list(Suicide=0)) %>%
  mutate(Year = as.character(Year)) %>%
  mutate(Total = sum(across(where(is.numeric))),
         Percent = round(100*Suicide/Total, 1),
         ) %>%
  select(Year, Number=Suicide, Percent) %>%
  bind_rows(data.frame(Year ="Total", 
                       Number = sum(.$Number), 
                       Percent = round(100*sum(.$Number)/nrow(wa_clean_2015), 1)))

tab %>%
  kable(caption = "Cases labeled 'Suicide' by year*",
        col.names = c("year", "Number", "% of Cases")) %>%
  kable_styling(bootstrap_options = c("striped","hover"),
                full_width = F) %>%
  row_spec(dim(tab)[1], bold = T)  %>%
  add_footnote(label = "These cases were excluded from analyses in this report",
               notation = "symbol")
Cases labeled ‘Suicide’ by year*
year Number % of Cases
2015 0 0.0
2016 0 0.0
2017 1 1.9
2018 1 2.4
2019 2 3.7
2020 2 3.6
2021 4 13.8
2022 2 3.6
2023 10 21.3
2024 5 8.3
2025 8 17.8
Total 35 7.0
* These cases were excluded from analyses in this report

Medical Emergencies

There are also a handful of cases where the cause of death is coded as “Medical emergency”. We exclude these cases from this report as well, as they do not meet the definition of “homicide.” But we note that in all of these cases, there was substantial interaction with the police in the period preceding the death, and the person died in police custody. The cases in WA involved such things as lengthy vehicular pursuits, physical restraints, and injection with something to “calm them down” (presumably Ketamine).


What is a homicide?

The deadly force incidents in this report are homicides (including vehicular homicides). A homicide is simply defined as the killing of one person by another. In the context of this report it refers to any encounter with law enforcement officers that results in a fatality. Homicides normally result in a criminal investigation or inquest, but the word does not imply a crime has been committed.

  • The word homicide means only that the death was caused in some way by the officer.

  • It does not not mean the officer’s actions that led to the death were justified, or that they were unjustified.

The law then defines different types of homicides, in order to distinguish levels of intention and criminal culpability. In the U.S., these types and definitions are broadly similar across states, but do vary somewhat in the the how many different types are specified, and what names are used for each type. The classifications for WA State can be found in 9A.32 RCW

The definitions below are taken from a useful online summary that uses simple language, based on California State laws.

Homicide
Homicide is the killing of one person by another. This is a broad term that includes both legal and illegal killings. For example, a soldier may kill another soldier in battle, but that is not a crime. The situation in which the killing happened determines whether it is a crime.

  • Murder is the illegal and intentional killing of another person. Under California Penal Code Section 187, for example, murder is defined as one person killing another person with malice aforethought. Malice is defined as the knowledge and intention or desire to do evil. Malice aforethought is found when one person kills another person with the intention to do so.

    In California, for example, a defendant may be charged with first-degree, second-degree, capital or felony murder.

    • First-degree murder is the most serious and includes capital murder – first-degree murder with “special circumstances” that make the crime even more egregious. These cases can be punishable by life in prison without the possibility of parole, or death.

    • Second-degree murder is murder without premeditation, but with intent that is typically rooted in pre-existing circumstances. The penalty for second-degree murder may be up to 15 years to life in prison in California.

    • Felony murder is a subset of first-degree murder and is charged when a person is killed during the commission of a felony, such as a robbery or rape.

  • Manslaughter is the illegal killing of another person without premeditation, and in some cases without the intent to kill. These cases are treated as less severe crimes than murder. Manslaughter can also be categorized as voluntary or involuntary.

    • Voluntary manslaughter occurs when a person kills another without premeditation, typically in the heat of passion. The provocation must be such that a reasonable person under the same circumstances would have acted the same way. Penalties for voluntary manslaughter include up to 11 years in prison in California.

    • Involuntary manslaughter is when a person is killed by actions that involve a wanton disregard for life by another. Involuntary manslaughter is committed without premeditation and without the true intent to kill, but the death of another person still occurs as a result. Penalties for involuntary manslaughter include up to four years in prison in California.

    • Vehicular manslaughter occurs when a person dies in a car accident due to another driver’s gross negligence or even simple negligence, in certain circumstances.


Public Access

This report follows the principles of transparent, reproducible science. All of the scripts, data and software are open source and freely available to the public, online.


The scripts needed to scrape the data and reproduce this report are posted on our public GitHub Repository.


The software used to produce this report comes from the open-source R project. You can view the code in the report itself by clicking the Code buttons in the right margin, or you can download all of the scripts from the repository.

  • If you find a bug in our code, please let us know by posting it as an issue in the repository (note: you’ll need a GitHub account – they’re free, just follow the instructions at the link).

  • If you have a question about the methodology, or the data, or the topic in general, please start a thread on the repository discussions page.

  • If you want to get involved, please email us at Next Steps Washington


: : : :