Public
Edited
Feb 19
Importers
Insert cell
Insert cell
dataset
Insert cell
Insert cell
Insert cell
boroughToMonthToInjuries = d3.rollups(
dataset,
// for all of the collisions in the same borough and month,
// get the sum of the number of injuries
collisions => d3.sum(collisions, c => c.injured),
// group by borough
d => d.borough,
// then group by month
// d3.timeMonth rounds the date down to the first of the month
d => d3.timeMonth(d.date)
)
Insert cell
Insert cell
dataByBorough = boroughToMonthToInjuries
.map(([borough, months]) => ({
borough: borough,
counts: months
.map(([date, injuries]) => ({date, injuries}))
.sort((a, b) => d3.ascending(a.date, b.date))
}))
Insert cell
Insert cell
margin = ({top: 30, right: 30, bottom: 20, left: 40})
Insert cell
width
Insert cell
height = 500
Insert cell
Insert cell
brooklyn = dataByBorough[0].counts
Insert cell
monthExtent = [brooklyn[0].date, brooklyn[brooklyn.length - 1].date]
Insert cell
x = d3.scaleTime()
.domain(monthExtent)
.range([margin.left, width - margin.right])
Insert cell
Insert cell
maxInjuries = d3.max(
dataByBorough,
boroughCounts => d3.max(boroughCounts.counts, month => month.injuries)
)
Insert cell
y = d3.scaleLinear()
.domain([0, maxInjuries]).nice()
.range([height - margin.bottom, margin.top])
Insert cell
Insert cell
boroughs = dataByBorough.map(d => d.borough)
Insert cell
color = d3.scaleOrdinal()
.domain(boroughs)
.range(d3.schemeTableau10)
Insert cell
Insert cell
dataByBorough[0].counts[0]
Insert cell
line = d3.line()
.x(d => x(d.date))
.y(d => y(d.injuries))
Insert cell
Insert cell
line(dataByBorough[0].counts)
Insert cell
Insert cell
xAxis = d3.axisBottom(x)
// show the full month name in the tick marks
.tickFormat(d3.timeFormat('%B'))
Insert cell
yAxis = d3.axisLeft(y)
Insert cell
Insert cell
swatches({color})
Insert cell
multiLine = {
// set up
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height);
// draw axes
svg.append('g')
// move x-axis to the bottom
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(xAxis);
svg.append('g')
.attr('transform', `translate(${margin.left})`)
.call(yAxis)
.call(g => g.select('.domain').remove())
// add axis label
.append('text')
.attr('fill', 'black')
.attr('text-anchor', 'start')
.attr('dominant-baseline', 'hanging')
.attr('font-weight', 'bold')
.attr('y', 5)
.attr('x', 0)
.text('Collision Injuries, 2019');
/* Draw the lines in linesGroup.

- Create one path for each element in dataByBorough.
- Use the line generator to set the "d" attribute.
- Use the color scale to set the "stroke" attribute.
- Set the "fill" attribute to none.
- Set the "stroke-width" attribute to to 2.
When you are setting the attributes
.attr('foo', d => ...)
remember that d is an object that looks like this:
{
borough: "BROOKLYN",
counts: [
{date: 2019-01-01T00:00, injuries: 968},
{date: 2019-02-01T00:00, injuries: 857},
...
]
}
*/
const linesGroup = svg.append('g');

linesGroup
.selectAll('path')
.data(dataByBorough)
.join('path')
.attr('stroke', d => color(d.borough))
.attr('fill', 'none')
.attr('stroke-width', 2)
.attr('d', d => line(d.counts));
return svg.node();
}
Insert cell
Insert cell
Insert cell
injuriesByMonthAndBorough = d3.rollup(
dataset,
// get the total number of injuries in the collisions array
collisions => d3.sum(collisions, d => d.injured),
// group by month first
d => d3.timeMonth(d.date),
// then by borough
d => d.borough
)
Insert cell
Insert cell
Array.from(injuriesByMonthAndBorough)[0]
Insert cell
Insert cell
stack = d3.stack()
.keys(boroughs)
// define how to get the value for a given borough
.value(([month, boroughtToCount], borough) => boroughtToCount.get(borough))
.order(d3.stackOrderDescending)
// .offset(d3.stackOffsetExpand)
Insert cell
Insert cell
stacked = stack(injuriesByMonthAndBorough)
Insert cell
Insert cell
stacked[1][0]
Insert cell
Insert cell
myArray = {
const numbers = [1, 2, 3];
numbers.message = "hello";
return numbers;
}
Insert cell
myArray[0]
Insert cell
myArray.message
Insert cell
Insert cell
stacked[1]
Insert cell
stacked[1].key
Insert cell
Insert cell
stacked[1][0]
Insert cell
stacked[1][0].data
Insert cell
Insert cell
margin
Insert cell
width
Insert cell
height
Insert cell
Insert cell
x
Insert cell
color
Insert cell
Insert cell
injuriesByMonthAndBorough
Insert cell
stacked
Insert cell
d3.max(injuriesByMonthAndBorough.values(), d => d3.sum(d.values()))
Insert cell
maxTotalInjuries = d3.max(stacked, layer => d3.max(layer, d => d[1]))
Insert cell
yStacked = d3.scaleLinear()
.domain([0, maxTotalInjuries]).nice()
// .domain([0, 1])
.range([height - margin.bottom, margin.top])
Insert cell
Insert cell
stacked[1][0]
Insert cell
area = d3.area()
.x(d => x(d.data[0]))
.y1(d => yStacked(d[1]))
.y0(d => yStacked(d[0]))
Insert cell
Insert cell
Insert cell
stackedArea = {
// set up
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height);
// axes
const xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat('%B'))
const yAxis = d3.axisLeft(yStacked);
svg.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(xAxis)
.call(g => g.selectAll('.domain').remove());
svg.append('g')
.attr('transform', `translate(${margin.left})`)
.call(yAxis)
.call(g => g.selectAll('.domain').remove())
.append('text')
.attr('fill', 'black')
.attr('text-anchor', 'start')
.attr('dominant-baseline', 'hanging')
.attr('font-weight', 'bold')
.attr('y', 5)
.attr('x', 0)
.text('Collision Injuries, 2019');
/* Draw the areas in areasGroup.
Create one path for each element in stacked.
- Use the area generator to set the "d" attribute.
- Use the color scale to set the "fill" attribute.

When you are setting the attributes
.attr('foo', d => ...)
remember that d is the data array for one layer.
The borough for that layer is in d.key
*/
const areasGroup = svg.append('g');
areasGroup.selectAll('path')
.data(stacked)
.join('path')
.attr('fill', layer => color(layer.key))
.attr('d', layer => area(layer))
// .attr('d', area)
return svg.node();
}
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