Public
Edited
Feb 13, 2023
Paused
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
uri = buildURI("p2ww-25u5")
Insert cell
raw_data = (await fetch(uri)).json()
Insert cell
viewof aq_data = aq.from(raw_data).view({height:150})
Insert cell
Insert cell
groupcodes = new Set(["19", "20", "21", "22", "23", "24", "25"])
Insert cell
Insert cell
viewof filtered = aq_data
.filter(aq.escape(d => groupcodes.has(d.groupcode)))
.derive({
year: d => op.parse_date(d.year),
unemp: d => op.parse_float(d.civilianlaborforceunempl)
})
.select('year', 'groupcode', 'populationgroup', 'unemp')
.view({height: 150})
Insert cell
Insert cell
linedata = filtered
.groupby('populationgroup')
.orderby('year')
.rollup({values: d => op.array_agg(op.row_object('year', 'unemp'))})
.objects()
Insert cell
Insert cell
Insert cell
Insert cell
totalWidth = width
Insert cell
totalHeight = 500
Insert cell
margin = ({top: 30, bottom: 20, left: 40, right: 30})
Insert cell
visWidth = totalWidth - margin.left - margin.right
Insert cell
visHeight = totalHeight - margin.top - margin.bottom
Insert cell
Insert cell
Insert cell
domains = filtered.rollup({
x: d => [op.min(d.year), op.max(d.year)], // [min, max] domain array
y: d => [op.min(d.unemp), op.max(d.unemp)], // [min, max] domain array
groups: d => op.array_agg_distinct(d.populationgroup) // array of unique values
})
.objects()[0]
Insert cell
test_x = d3.scaleTime()
.domain(domains.x)
.range([0, visWidth]);
Insert cell
visualizeTicks(test_x)
Insert cell
test_y = d3.scaleLinear()
.domain(domains.y).nice()
.range([visHeight, 0]);
Insert cell
visualizeTicks(test_y)
Insert cell
test_color = d3.scaleOrdinal()
.domain(domains.groups)
.range(d3.schemeTableau10);
Insert cell
Swatches(test_color)
Insert cell
Insert cell
Insert cell
{
// set up outer svg container
const svg = d3.create('svg')
.attr('width', totalWidth).attr('height', totalHeight);

// set up scales
const x = d3.scaleTime()
.domain(domains.x)
.range([0, visWidth]);
const y = d3.scaleLinear()
.domain(domains.y).nice()
.range([visHeight, 0]);

const color = d3.scaleOrdinal()
.domain(domains.groups)
.range(d3.schemeTableau10);

// set up path generator
const line = d3.line()
.x(d => x(d.year))
.y(d => y(d.unemp));
// set up svg group for chart
const g = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`);

// set up axes
const xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat('%Y'));
const yAxis = d3.axisLeft(y);

// configure x-axis and label
g.append('g')
.attr('transform', `translate(0, ${visHeight})`)
.call(xAxis);

// configure y-axis and label
g.append('g').call(yAxis)
.append('text')
.attr('fill', 'black')
.attr('text-anchor', 'start')
.attr('dominant-baseline', 'hanging')
.attr('font-weight', 'bold')
.attr('y', -margin.top + 5)
.attr('x', -margin.left)
.text('Unemployment %');

// draw mark for each element in data
g.append("g")
.attr("fill", "none")
.attr("stroke-width", 1.5)
.selectAll("path")
.data(linedata)
.join("path")
.attr("d", d => line(d.values))
.attr('stroke', d => color(d.populationgroup));
return svg.node();
}
Insert cell
Insert cell
{
// set up outer svg container
const svg = d3.create('svg')
.attr('width', totalWidth).attr('height', totalHeight);

// set up scales
const x = d3.scaleTime()
.domain(domains.x)
.range([0, visWidth]);
// NEW: scaleBand for separate rows in small multiple view
const row = d3.scaleBand()
.domain(domains.groups) // one row for each line
.range([0, visHeight])
.paddingInner(0.25);
const y = d3.scaleLinear()
.domain(domains.y).nice()
.range([row.bandwidth(), 0]); // each y is height of a row

const color = d3.scaleOrdinal()
.domain(domains.groups)
.range(d3.schemeTableau10);
// set up path generator
const area = d3.area()
.x(d => x(d.year))
.y1(d => y(d.unemp))
.y0(d => y(0));

// set up svg group for the chart
const g = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`);

// NEW set up svg groups for each row
const rows = g.append('g')
.selectAll('g')
.data(linedata)
.join('g')
.attr('transform', d => `translate(0, ${row(d.populationgroup)})`)
.attr('fill', d => color(d.populationgroup))

// set up axes
const xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat('%Y'));
const yAxis = d3.axisLeft(y).ticks(5);

// configure x-axis and label
g.append('g')
.attr('transform', `translate(0, ${visHeight})`)
.call(xAxis);

// configure y-axis and label
// each row will have its own y-axis
rows.append('g')
.attr('class', 'y-axis') // apply a class so that we can select it later
.call(yAxis)
.call(g => g.select('.domain').remove()); // remove the axis line

rows.append('text')
.text(d => d.populationgroup)
.attr('font-size', 12)
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('y', -5)
.attr('x', 5);
g.select('.y-axis')
.append('text')
.attr('fill', 'black')
.attr('text-anchor', 'start')
.attr('dominant-baseline', 'middle')
.attr('y', 7)
.attr('x', 5)
.text('Unemployment %');

// append path to each group
rows.append('path')
.attr('d', d => area(d.values));
return svg.node();
}
Insert cell
Insert cell
Insert cell
import {aq, op} from "@uwdata/arquero"
Insert cell
d3 = require("d3@7")
Insert cell
import {visualizeTicks} from "@d3/continuous-scales"
Insert cell
import {procedure} from "@weiglemc/cs725-s22-d3-intro-bar-chart"
Insert cell
import {Legend, Swatches} from "@d3/color-legend"
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