Our team is developing an interactive map that identifies potential instances of police use-of-force across the United States of America for Human Rights First, an independent advocacy and action organization. Here is a little the non-profit from their website:
Human Rights First is an independent advocacy and action organization that challenges America to live up to its ideals. We believe American leadership is essential in the global struggle for human rights, so we press the U.S. government and private companies to respect human rights and the rule of law. When they fail, we step in to demand reform, accountability and justice. Around the world, we work where we can best harness American influence to secure core freedoms. We know it is not enough to expose and protest injustice, so we create the political environment and policy solutions necessary to ensure consistent respect for human rights. Whether we are protecting refugees, combating torture, or defending persecuted minorities, we focus not on making a point, but on making a difference. For almost 40 years, we've built bipartisan coalitions and teamed up with frontline activists and lawyers to tackle global challenges that demand American leadership. Human Rights First is a non-profit, nonpartisan international human rights organization based in New York, Washington D.C., Houston, and Los Angeles.
Nic Lehman | MariaPaula Trujillo | Khwanchai Phaipha | Idong Essien | Dondre' Jordan | Santiago Berniz | Jason Long |
---|---|---|---|---|---|---|
Web Developer | Web Developer | Web Developer | Web Developer | Data Scientist | Data Scientist | TPL |
-
How to get started working with this repo
-
See TPL about
.env
file configurationREACT_APP_BACKENDURL = "HEROKU_DEPLOYMENT_URL" REACT_APP_MAPBOX_TOKEN = "MAPBOX_GL_TOKEN"
-
-
Where each portion is deployed
- FE: Deployed on AWS Amplify
- BE: Deployed in Heroku
- DS: Deployed on AWS Elastic Beanstalk
- List the tech stack used
- ReactJS
- MapBoxGL, React-Map-GL, Supercluster, Use-Supercluster (map)
- amCharts (charts)
- React-Query, Axios (fetches server data)
- Styled-Components
- User can see clusters of incidents on a map that breaks apart as they scroll in so that they can see more specifically where each incident in the cluster occurred.
- User is able to click on a data point within the map and view more details including date, description, tags, and sources.
- User can view charts by state or by use of force tags to see where incidents are more prevelant and what type of force is most commonly used.
- N/A
-
DS backend scrapes and shapes data
-
Web BE gets data from DS backend through a cron job and updates Web Database
-
Web FE can use endpoints to fetch an incident by or all incidents (currently we are only fetching all incidents at once)
-
Describe the file hierarchy and where to find things
-
FE specific file hierarchy
-
src >> index.js >>
App()
-
NavBar
on all pages -
Switch / Routes for all page view components
-
Important Page Views:
path='/'
--><MapView/>
path='/charts-by-state'
--><BarChartView/>
path='/charts-by-force'
--><PieChartView/>
-
<ReactQueryDevtools
--> devDependency only (won't show in production) -
ChartsNavBar
displayed on Map, Bar, and Pie Charts to switch between chart views
-
-
src >> components >>
-
📂
Map
📂-
MapView.js
--> renders both the container for the Map and an incidents viewer side-by-side on the page-
ChartsNavBar.js
gives users the option of what chart to view -
MapContainer.js
-
MapContainer renders the MapboxGL Map as well as the ClusterMarkers that represent underlying data points
-
ClusterMarkers.js
- cluster markers can add
incidentsOfInterest
to state - size of cluster is calculated using weird formula -- this could be improved so that as the data set gets larger we don't have to continually update this function
${10 + (pointCount / points.length) * 600}px
- the clusters are offset to the left and vertically to center the circle properly
- the value we want to pass to the offsets is negative (1/2 of the width or height) pixels
offsetLeft={-(10 + (pointCount / points.length) * 600) / 2}
<--> same as offsetTop
- cluster markers can add
-
-
IncidentsViewer.js
- IF there are no
incidentsOfInterest
, we display a message explaining to the users they can click on a cluster to view the incident data - If there are
incidentsOfInterest
, we map through all the relevant incident data and display underlying incident info for the user to explore to the right of the map
- IF there are no
-
-
-
📂
bar_chart
📂-
BarChartView.js
--> renders the container for displaying a bar chart that totals incidents by state-
ChartsNavBar.js
gives users the option of what chart to view -
BarChartContainer.js
-
fetches incident data using custom react-query
useIncidents()
query_hook and renders the actual bar graph -
calls
useBarChartData()
in utils >> helpers to format data in a way that the amCharts barChart components expects and store that value in abar_data
component- takes in a
limit
which is the largest number of incidents per state that will NOT be returned (i.e: 0 --> must be 1 incident in that state for it to show up in the bar graph) - limit could be manipulated by state to dynamically update the chart
- takes in a
-
IF there is incident data, we expect useBarChartData() to work correctly, and we will have data for the bar chart to use --> Pass
bar_data
to<BarChart />
-
if not, we don't want the bar chart to error out so we display a "loading.."
<div>
-
BarChart.js
- amChart component that uses the data we passed in ... expects an array of objects
- see
xy_chart.data = data.data;
-
-
-
-
📂
pie_chart
📂-
PieChartView.js
--> renders the container for displaying a pie chart that totals incidents by type-of-force tags provided by our DS backend-
ChartsNavBar.js
gives users the option of what chart to view -
PieChartContainer.js
-
renders
<PieChart>
in a very similar way as the bar chart -
we call
usePieChartData()
from the utils >> helpers folder which also takes a lower limit like useBarChartData -
limit could be manipulated by state to dynamically update the chart
-
PieChart.js
- amChart component that uses the data we passed in ... expects an array of objects
- see
pie_chart.data = data.data
-
-
-
-
- Clusterized the data points on the map
- Added 2 amChart components to display data in different visually appealing ways
- Filter on map no longer functional
-
Incidents
https://hrf-c-api.herokuapp.com/incidents/showallincidents
--> returns an array of all incident objectshttps://hrf-c-api.herokuapp.com/incidents/incident/:incident_id
--> returns single incident object if the incident_id passed in is valid
-
Interactive Api Documentation using Swagger Docs
-
Search/filter capability not functional
-
Many data points list an incorrect lat,long of 0,0
- Map currently filters these out
- Charts currently use this data
-
Lots of ugly scroll bars
-
IncidentsViewer
stays at scrolled position when switching between cluster- recreate this by --> clicking cluster with more than 50 incidents ... scrolling down the incident viewer ... clicking on another cluster with more than 5 incidents --> incident viewer will stay at the bottom instead of resetting to the top
- map/chart filter functionality
- Pass cluster data directly to bar and pie charts for added interaction
- queries for incidents including specific tag / geographical(state) data
- A filter on the dashboard to distinguish public approval of police use of force using NLP to create a sentiment analysis.
- Add a predict route to receive input data from a user to classify a type of use of force, as defined by the National Institute of Justice: Police Use-of-Force Continuum.
Who to contact for further support. Include at least two names. They can use the contributors list above to get in contact with you, or find you on slack.