Insert cell
Insert cell
taserUseAgeChart = md`
#### Police Taser use against children age 17 and under in England and Wales, 2018-19

<figcaption>Graph shows total count. Metropolitan Police's count has been truncated for readability. No force-specific data is available for Staffordshire, Warwickshire, West Mercia, Norfolk and Suffolk.</figcaption>

<div style='margin-left: ${graph.margin.left - 1}px'>${legend}</div>
${chart}
`
Insert cell
legend = swatches({
color: d3.scaleOrdinal(["Under 11 years old", "11-17 years old"], [colours.primary, colours.primary50])
})
Insert cell
chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

// The bars themselves
svg
.append("g")
.selectAll("g")
.data(series)
.join("g")
// Each indivdual bar
.attr("fill", d => d.key === "u11" ? colours.primary : colours.primary50)
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d => x(d[0]))
.attr("y", (d, i) => y(d.data.force))
.attr("width", d => x(d[1]) - x(d[0]))
.attr("height", y.bandwidth())

// Text for under 12s
svg
.append("g")
.selectAll("g")
.data(series)
.join("g")
.attr("fill", colours.primary)
.attr("text-anchor", "start")
.attr("font-family", graph.font)
.attr("font-size", graph.fontSize)
.selectAll("text")
.data(d => d)
.join("text")
.filter((d) => d[0] !== 0)
.attr("x", d => x(d[0]))
.attr("y", (d, i) => {
return y(d.data.force) + y.bandwidth() / 2
})
.attr("dy", "0.35em")
.attr("dx", 5)
.text(d => d[0])
// Text for total
svg
.append("g")
.attr("fill", colours.primary50)
.attr("text-anchor", "start")
.attr("font-family", graph.font)
.attr("font-size", graph.fontSize)
.selectAll("text")
.data(ageLeaderboard)
.join("text")
.filter((d) => d.total !== 0)
.attr("x", d => x(d.total))
.attr("y", (d, i) => {
return y(d.force) + y.bandwidth() / 2
})
.attr("dy", "0.35em")
.attr("dx", 4)
.text(d => d.total)
.call(text => text.filter(d => d.total > 150)
.text(d => d.total + " →")
.attr("x", width - 10)
.attr("fill", "white")
.attr("text-anchor", "end"));

// Draw axes
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);

return svg.node()
}
Insert cell
x = d3
.scaleLinear()
.domain([0, 155])
.range([graph.margin.left, width - graph.margin.right])
Insert cell
y = d3
.scaleBand()
.domain(ageLeaderboard.map(d => d.force))
.rangeRound([graph.margin.top, height - graph.margin.bottom])
.padding(0.1)
Insert cell
xAxis = g =>
g
.attr("transform", `translate(0,${graph.margin.top})`)
.call(d3.axisTop(x).ticks(width / 80, ageLeaderboard.format))
.call(g => g.select(".domain").remove())
Insert cell
yAxis = g =>
g
.attr("transform", `translate(${graph.margin.left},0)`)
.call(d3.axisLeft(y).tickSizeOuter(0))
.attr("font-size", graph.fontSize)
Insert cell
height = Math.ceil((ageLeaderboard.length + 1) * graph.barHeight) + graph.margin.top + graph.margin.bottom
Insert cell
// This object provides the data in the form needed for stacked bars
series = d3
.stack()
.keys(['u11', 'a11_18'])(ageLeaderboard)
.map(d => (d.forEach(v => (v.key = d.key)), d))
Insert cell
Insert cell
getAgeStats = (forceName) => {
let forceStats = taserByAge.filter((f) => f["Police Force"] === forceName)
let under11 = forceStats.find((f) => f.variable === "0-11").value
let under18 = forceStats.find((f) => f.variable === "11-17").value
return {
force: forceName,
u11: under11,
a11_18: under18,
u18: under11 + under18
}
}
Insert cell
getAgeStats("Greater Manchester")
Insert cell
ageLeaderboard = forces.map((f) => {
let stats = getAgeStats(f)
return {
force: f,
total: stats.u18,
u11: stats.u11,
a11_18: stats.a11_18
}
}).filter((f) => f.total != 0)
.sort((a, b) => b.total - a.total)
Insert cell
childrenPerFTE2019 = (force = false) => {
let total = getAgeStats(force).u18
let officers = officerFTETotalByYear(2019, force)
let formatted = d3.format(".2")(total * 100 / officers)
return formatted
}
Insert cell
childrenPerFTE2019('Greater Manchester')
Insert cell
forces.map((f) => {
let fte = childrenPerFTE2019(f)
return {
force: f,
fte: fte
}
}).sort((a, b) => b.fte - a.fte)
Insert cell
Insert cell
Insert cell
import { swatches } from "@d3/color-legend"
Insert cell
import {colours, d3, graph, forces, officerFTETotalByYear} from '@resistancelab/resistance-lab-defaults'
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more