The data I am working with is from the Stanford Open Policing Project. This data is a collaborative initiative aimed at analyzing police interactions and practices across the United States, but for the purpose of this project I am focusing on the data from Philadelphia . I want to use data visualizations to see any trends in these interactions as well as any bias in these interactions.

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.5.0     ✔ purrr   1.0.1
## ✔ tibble  3.1.8     ✔ dplyr   1.1.0
## ✔ tidyr   1.3.0     ✔ stringr 1.5.0
## ✔ readr   2.1.3     ✔ forcats 1.0.0
## Warning: package 'ggplot2' was built under R version 4.2.3
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(lubridate)
## 
## Attaching package: 'lubridate'
## 
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(lutz)
## Warning: package 'lutz' was built under R version 4.2.3
library(suncalc)
## Warning: package 'suncalc' was built under R version 4.2.3
library(splines)

data_path <- "C:\\Users\\stola\\Data Vis\\pa_philadelphia_2020_04_01.csv"

stops <- read.csv(data_path)


population_2017 <- tibble(
  subject_race = c(
    "asian/pacific islander", "black", "hispanic", "other/unknown","white"
  ),
  num_people = c(110864, 648846, 221777, 39858, 548312)
) %>% 
  mutate(subject_race = as.factor(subject_race))

center_lat <- 39.9525839
center_lng <- -75.1652215
colnames(stops)
##  [1] "raw_row_number"            "date"                     
##  [3] "time"                      "location"                 
##  [5] "lat"                       "lng"                      
##  [7] "district"                  "service_area"             
##  [9] "subject_age"               "subject_race"             
## [11] "subject_sex"               "type"                     
## [13] "arrest_made"               "outcome"                  
## [15] "contraband_found"          "frisk_performed"          
## [17] "search_conducted"          "search_person"            
## [19] "search_vehicle"            "raw_race"                 
## [21] "raw_individual_contraband" "raw_vehicle_contraband"
nrow(stops)
## [1] 1865096
stops %>% 
  select(type) %>% 
  head(10) 
##          type
## 1  pedestrian
## 2  pedestrian
## 3  pedestrian
## 4  pedestrian
## 5   vehicular
## 6   vehicular
## 7   vehicular
## 8  pedestrian
## 9   vehicular
## 10 pedestrian
stops <- stops %>%
  mutate(date = ymd(date))

stops <- stops %>%
  mutate(subject_race = if_else(subject_race %in% c("other", "unknown"), "other/unknown", subject_race))

stop_counts_year <- stops %>%
  mutate(year = year(date)) %>% 
  count(year)

stop_counts_race_year <- stops %>% 
  count(year = year(date), subject_race)

Plot 1

ggplot(stop_counts_race_year, aes(x = year, y = n, color = subject_race)) +
  geom_point() +
  geom_line() +
  scale_y_continuous(labels = scales::comma) +
  labs(title = "", 
       x = "", y = "") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1") +
  theme(axis.line = element_blank(),
        axis.text.x = element_text(),
        axis.text.y = element_text(),
        axis.ticks = element_blank(),
        axis.title.x = element_text(),
        axis.title.y = element_text(),
        panel.grid.major = element_blank(),  
        panel.grid.minor = element_blank()) 

The first plot is a simple line graph of police stops by year. However there is no title or axis labels, so there is no way to tell what this plot is representing.

Plot 2

ggplot(stop_counts_race_year, aes(x = year, y = n, color = subject_race, linetype = subject_race)) +
  geom_point() +
  geom_line() +
  scale_y_continuous(labels = scales::comma) +
  labs(title = "Traffic Stops by Year and Subject Race", 
       x = "Year", y = "Number of Stops",
       color = "Subject Race") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1") +
  guides(linetype = FALSE) +
  theme(axis.line = element_blank(),
        axis.text.x = element_text(),
        axis.text.y = element_text(),
        axis.ticks = element_blank(),
        axis.title.x = element_text(),
        axis.title.y = element_text(),
        panel.grid.major = element_blank(),  # Remove major grid lines
        panel.grid.minor = element_blank())  # Remove minor grid lines
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

From Plot 1 to Plot 2: Instead of differentiating race by only color, race is now differentiated by line type as well. This makes the plot not only more visually appealing but easier to understand, as differentiating between these different line types and colors is easier than just differentiating between the colors. I also added a title, and axes labels, which makes the purpose of this graph much clearer and easier to understand.

Plot 3

library(plotly)
## Warning: package 'plotly' was built under R version 4.2.3
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
plotly_plot1 <- plot_ly(data = stop_counts_race_year, x = ~year, y = ~n, color = ~subject_race, 
                        linetype = ~subject_race, size = ~n, symbol = ~subject_race,
                        type = "scatter", mode = "lines+markers") %>%
  layout(title = "Traffic Stops by Year and Subject Race",
         xaxis = list(title = "Year", showgrid = FALSE), 
         yaxis = list(title = "Number of Stops", showgrid = FALSE),  
         legend = list(title = "Subject Race"),
         showlegend = TRUE,
         hovermode = "closest")

plotly_plot1
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

From Plot 2 to Plot 3: I added line markers of different shapes that correspond to different races. Doing so makes identifying the different races much easier in the plot, especially for those who are color blind. There is now also a hover feature which displays the year and number of arrests when hovering over each point on the plot.

Plot 4

plotly_plot <- plot_ly(data = stop_counts_race_year, x = ~year, y = ~n, color = ~subject_race, 
                       linetype = ~subject_race, size = ~n, symbol = ~subject_race,
                       type = "scatter", mode = "lines+markers") %>%
  layout(title = "Traffic Stops by Year and Subject Race",
         xaxis = list(title = "Year",showgrid = TRUE),
         yaxis = list(title = "Number of Stops",showgrid = TRUE),
         legend = list(title = "Subject Race"),
         showlegend = TRUE,
         hovermode = "closest") %>%
  add_markers(marker = list(size = 10), showlegend = FALSE) %>%
  add_lines(line = list(width = 3, dash = c("solid", "dash", "dot", "dashdot", "longdash")),  # Corrected syntax
            showlegend = FALSE,
            frame = ~year) %>%  
  animation_opts(frame = 500)  

print(plotly_plot)
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding markers to mode; otherwise symbol would have no effect.
## Adding lines to mode; otherwise linetype would have no effect.
## Adding lines to mode; otherwise linetype would have no effect.
## Adding lines to mode; otherwise linetype would have no effect.
## Adding lines to mode; otherwise linetype would have no effect.
## Adding lines to mode; otherwise linetype would have no effect.
## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.
## Warning in p$x$data[firstFrame] <- p$x$frames[[1]]$data: number of items to
## replace is not a multiple of replacement length

From Plot 3 to Plot 4: I added an animation that highlights the changes made throughout the years 2014-2018.I also decreased the size of the markers, as the other and Asian lines are very close together. Finally, I added grid lines to make reading the plot easier.

Overall, I would pick the final plot to convey the disparities in police stops by race from 2014-2015. It is the clearest and most readable of the four plots, with helpful tools to make understanding the data easier.