Public
Edited
Oct 28, 2022
Importers
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
height: 300,
y: {
label: 'Count of Incidents by Date'
},
marks: [
Plot.dot(incidents.filter(after2017), Plot.dodgeY(Plot.groupX({y: 'count'}, {x: "date", r: 3, fill: '#000'})))
],
caption: 'Count of incidents by date shows a large surge during the BLM protetst in 2020.'
})
Insert cell
Insert cell
tidyByCategory = {
const returnArray = [];
incidents.filter(after2017).forEach(incident => {
incident.categories?.forEach(category => {
incident.category = category;
returnArray.push(incident)
})
})
return returnArray
}
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
height: 250,
y: {
label: "Count of Incidents by Date",
},
marks: [
Plot.dot(
selectCity,
Plot.dodgeY({
x: "date",
r: 3,
fill: "#000",
href: 'slug',
target: "_blank",
title: 'title'
})
)
],
caption: "Click on a circle to see open a link to the specific incident."
})
Insert cell
Insert cell
yearChart = Plot.plot({
x: { tickFormat: t => d3.timeFormat('%Y')(t), interval: d3.timeYear },
y: { grid: true, label: '↑ Incidents' },
marks: [
Plot.rectY(incidents, Plot.binX(
{ y: 'count' },
{ x: 'date', thresholds: d3.timeYear, filter: after2017 }
)),
Plot.text(incidents, Plot.binX(
{
y: 'count',
text: 'count',
},
{
x: 'date',
thresholds: d3.timeYear,
filter: after2017,
dy: 8,
dx: 3,
textAnchor: 'start',
fill: 'white',
}
))
]
})
Insert cell
Insert cell
Plot.plot({
x: { tickFormat: d3.timeFormat('%b'), interval: d3.timeMonth },
y: { grid: true, label: '↑ Incidents' },
marks: [
Plot.rectY(incidents, Plot.binX(
{ y: 'count' },
{ x: 'date', thresholds: d3.timeMonth, filter: during2020 }
)),
Plot.text(incidents, Plot.binX(
{
y: 'count',
text: 'count',
},
{
x: 'date',
thresholds: d3.timeMonth,
filter: during2020,
dy: -8,
dx: 3,
textAnchor: 'start',
fill: 'black',
}
))
]
})
Insert cell
Insert cell
blmProtestDateRange = [new Date(Date.UTC(2020, 4, 25)), new Date(Date.UTC(2020, 7, 26))]
Insert cell
topCities = {
const inDateRange = incidents.filter(d => (
d.tags?.includes('Black Lives Matter') &&
d.tags?.includes('protest') &&
d.date > blmProtestDateRange[0] &&
d.date < blmProtestDateRange[1]
))
const byCity = Array.from(d3.group(inDateRange, d => d.city))
return byCity.sort((a, b) => b[1].length - a[1].length).slice(0, 5)
}
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.barX(incidentsByCity, {
x: "num_incidents",
y: "city",
title: d => `${d.city} - ${d.num_incidents} incidents`,
sort: { y: "x", reverse: true }
}),
Plot.ruleX([0])
],
marginLeft: 200
})
Insert cell
db
SELECT concat(city, ', ', state) as city
, count(*)::int as num_incidents
FROM incidents
GROUP BY 1
ORDER BY 2 DESC
LIMIT 10
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
incidents = (await FileAttachment("incidents.csv").csv({typed: true})).map(d => ({
...d,
tags: d.tags?.split(', '),
categories: d.categories?.split(', ')
}))
Insert cell
Insert cell
db = DuckDBClient.of({
incidents: FileAttachment("incidents.csv")
})
Insert cell
Insert cell
USPFT = async (params) => {
const params_ = new URLSearchParams([
...Object.entries(params),
['limit', QUERY_LIMIT],
])
const response = await fetch(`https://pressfreedomtracker.us/api/edge/incidents/?${params_.toString()}`)
const incidents = await response.json()
return incidents
.map(d => ({
...d,
date: d3.timeParse('%Y-%m-%d')(d.date)
}))
}
Insert cell
Insert cell
Insert cell
Insert cell
after2017 = inc => inc.date.getUTCFullYear() >= 2017
Insert cell
during2020 = inc => inc.date > new Date(Date.UTC(2020, 0, 1)) && inc.date < new Date(Date.UTC(2020, 11, 31))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more