Published
Edited
Sep 16, 2020
4 stars
Insert cell
Insert cell
Insert cell
chart = {
//three panels per row
const panels_per_row = 3;
const panel_width = (width - (margin * 3))/panels_per_row;
const height = margin + ((panel_width + margin) * (parseInt(grouped_data.length/4)+1));
const x_labels = d3.scaleBand()
.domain(["-24", "-12", "+3", "+6", "+9", "12", "24", "36", "48"])
.range([0, panel_width])
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
let terms = d3.set(grouped_data[0].chart_data, d => d.term).values();
const y_max = d3.max(grouped_data, d => d3.max(d.chart_data, m => m.value));
const y_min = d3.min(grouped_data, d => d3.min(d.chart_data, m => m.value));
const start_x = margin;
const start_y = 80 + margin;
const x_scale = d3.scaleBand().domain(terms).range([0,panel_width]);
const y_scale = d3.scaleLinear().domain([y_min,y_max]).range([panel_width - start_y - margin,0]);
const line = d3.line()
.x(d => x_scale(d.term))
.y(d => y_scale(d.value))
// .curve(d3.curveMonotoneX)
const area = d3.area()
.x(d => x_scale(d.term))
.y0(d => y_scale(0))
.y1(d => y_scale(d.value));
//join
var my_group = svg.selectAll('.chart_group')
.data(grouped_data, d => d.id)
.join(function(group){
var enter = group.append("g").attr("class","chart_group");
enter.append("rect").attr("class","group_rect");
enter.append("text").attr("class","group_text");
// enter.append("text").attr("class","axis_text");
enter.append("g").attr("class","sub_chart_group");
return enter;
});;
position_group_elements(my_group);
//join
var sub_group = my_group.select(".sub_chart_group").selectAll('.sub_chart_elements_group')
.data(d => [d.chart_data])
.join(function(group){
var enter = group.append("g").attr("class","sub_chart_elements_group");
enter.append("path").attr("class","chart_line");
enter.append("path").attr("class","chart_area");
return enter;
});;
sub_group.select(".chart_line")
.attr("d", line)
.attr("fill","none")
.attr("stroke",function(d){
d.color = "steelblue"
return d.color;
})
.attr("stroke-width",8)
.attr("transform","translate(" + start_x + "," + start_y + ")")
.call(transition)
sub_group.select(".chart_area")
.attr("d", area)
.attr("stroke","none")
.attr("fill",d => d.color)
.attr("fill-opacity",0.2)
.attr("transform","translate(" + start_x + "," + start_y + ")");

function position_group_elements(my_group){
//position rectangle
my_group.select(".group_rect")
.attr("x", function(d,i){
//two groups per row so
var position = i % panels_per_row;
d.x_pos = (position * (panel_width + margin)) + margin;
d.y_pos = (parseInt(i/panels_per_row) * (panel_width + margin)) + margin;
return d.x_pos;
})
.attr("y", d => d.y_pos)
.attr("fill","white")
.attr("stroke","#333333")
.attr("stroke-width",0.5)
.attr("rx",2)
.attr("ry",2)
.attr("width",panel_width)
.attr("height",panel_width);
//then position text
my_group.select(".group_text")
.attr("x", d => (panel_width/2) + d.x_pos)
.attr("y", d => 35 + d.y_pos)
.attr("text-anchor","middle")
.attr("font-weight","bold")
.attr("fill", "#B35959")
.attr("font-family","Arial")
.text(d => d.id);
// axis labels
my_group.select(".sub_chart_group")
.call(d3.axisBottom(x_labels).tickSize(0))
.selectAll("text")
.attr("transform", "translate(0,215)") // This controls the vertical position of the Axis
.style("fill", "#B35959")
//then position sub groups
my_group.select(".sub_chart_group")
.attr("id",d => d.id)
.attr("transform", d => "translate(" + d.x_pos + "," + d.y_pos + ")");
};

return svg.node();
}
Insert cell
width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
Insert cell
margin = 20;
Insert cell
data = d3.csvParse(await FileAttachment("data.csv").text(), d3.autoType)
Insert cell
grouped_data = d3.nest()
.key(d => d.code) // this is what we'll group by
.entries(data) // based on our data
.map(function(group) {
return {
id: group.key,
chart_data: group.values
}});
Insert cell
function tweenDash() {
const l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) { return i(t) };
}
Insert cell
function transition(path) {
path.transition()
.duration(7500)
.attrTween("stroke-dasharray", tweenDash)
.on("end", () => { d3.select(this).call(transition); });
}
Insert cell
d3 = require("d3@5")
Insert cell
terms = d3.set(grouped_data[0].chart_data, d => d.term).values()
Insert cell
x_labels = d3.scaleBand().domain(["-24", "-12", "+3", "+6", "+9", "12", "24", "36", "48"])
Insert cell
x_labels.domain()
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