Published
Edited
Apr 30, 2019
1 fork
9 stars
Insert cell
md`# Animated transition of y-axis scales`
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.select(DOM.svg(width, height));
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
// Add an x-axis label.
svg.append("text")
.attr("class", "x axislabel")
.attr("text-anchor", "end")
.attr("x", width - margin.right)
.attr("y", height - margin.bottom/4)
.text("date");

// Add an y-axis label.
svg.append("text")
.attr("class", "x axislabel")
.attr("text-anchor", "end")
.attr("x", -margin.top)
.attr("y", margin.left/4)
.text("monthly customer consumption (kWh)")
.attr('transform','rotate(-90)');
let keygroup = svg.append('g')
.attr('class', 'keygroup')
.attr('width', 200)
.attr("transform", `translate(${margin.left*2},${height*0.5 - margin.bottom - 40})`);
let keyItems = keygroup.selectAll('g.keyItem')
.data(['1st quartile','Median','3rd quartile'])
.enter().append('g').attr('class','keyItem')
.attr("transform", (d,i) => `translate(0,${-20*i})`);
let keyItemClasses = ['q1Line','medianLine','q3Line'];
keyItems.append("text")
.attr("class", "yearlabel")
.attr("text-anchor", "start")
.attr("x",30)
.text(d => d);
keyItems.append('path')
.attr('class',(d,i) => keyItemClasses[i])
.attr('d', 'M 4 -5 L 10 -6 L 15 -4 L 20 -6')
.attr("fill", 'none');


let korea = svg.append('g')
.attr("class", "korea benchmarkline")
.datum(120);
korea.append('line')
.attr('x1', margin.left).attr('x2',width-margin.right)
.attr('y1', d => y(d)).attr('y2', d => y(d))
.attr('stroke-width',1).attr('stroke-dasharray',5).attr('stroke','#222')
korea.append('text')
.attr('x', width-margin.right)
.attr('text-anchor','end')
.attr('y', d=>y(d)).attr('dy',-10)
.text("median monthly consumption in S. Korea");
let de = svg.append('g')
.attr("class", "germany benchmarkline")
.datum(264);
de.append('line')
.attr('x1', margin.left).attr('x2',width-margin.right)
.attr('y1', d => y(d)).attr('y2', d => y(d))
.attr('stroke-width',1).attr('stroke-dasharray',5).attr('stroke','#222')
de.append('text')
.attr('x', width-margin.right)
.attr('text-anchor','end')
.attr('y', d => y(d)).attr('dy',-10)
.text("median monthly consumption in Germany");
let kenya = svg.append('g')
.attr("class", "kenya trendline")
.datum(data)
.call(kenyalines);
kenya.append('text')
.attr('x', width-margin.right)
.attr('text-anchor','end')
.attr('y', y(data[60][1])).attr('dy',-10)
.text("Monthly consumption in Kenya");
svg.node().update = () => {
let newLimit = (y.domain()[1] === 150) ? 300 : 150;
y.domain([0,newLimit]);
svg.selectAll("line")
.transition().duration(500)
.attr('y1', d=>y(d)).attr('y2', d=>y(d))
svg.selectAll(".benchmarkline text")
.transition().duration(500)
.attr('y', d=>y(d));
svg.select(".trendline text")
.transition().duration(500)
.attr('y', y(data[60][1]));
svg.select("g.kenya")
.transition().duration(500)
.call(kenyalines);
svg.selectAll(".y.axis")
.transition().duration(500)
.call(yAxis);
}

return svg.node();
}
Insert cell
kenyalines = g => {
if (g.select('path').node() === null) {
g.append('path').classed('medianLine',true)
.attr("d", medianLine);
g.append('path').classed('q1Line',true)
.attr("d", q1Line);
g.append('path').classed('q3Line',true)
.attr("d", q3Line);
}
else {
g.select('.medianLine').attr("d", medianLine);
g.select('.q1Line').attr("d", q1Line);
g.select('.q3Line').attr("d", q3Line);
}
return g;
}
Insert cell
y = d3.scaleLinear()
.domain([0, 300])
.range([height - margin.bottom, margin.top])
Insert cell
import {margin,height} from "@vigorousnorth/band-chart/2"

Insert cell
x = d3.scaleTime()
.domain([monthParse("1/10"),monthParse("1/16")])
.range([margin.left, width - margin.right-10])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(g => g.append("text")
.attr("text-anchor", "end")
.attr("font-weight", "bold")
.text("Year") )
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %Y")).ticks(width/120).tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.attr("class", 'y axis')
.call(d3.axisLeft(y));
Insert cell
drawLines = g => { g.append('path').classed('medianLine',true)
.attr("d", medianLine);
g.append('path').classed('qLine',true)
.attr("d", q1Line);
g.append('path').classed('qLine',true)
.attr("d", q3Line);
}
Insert cell
medianLine = d3.line()
.x(d => x(d[0]))
.y(d => y(d[2]))
Insert cell
q1Line = d3.line()
.x(d => x(d[0]))
.y(d => y(d[3]))
Insert cell
q3Line = d3.line()
.x(d => x(d[0]))
.y(d => y(d[1]))
Insert cell
Insert cell
monthParse = d3.timeParse("%m/%y")
Insert cell
html`<style>
line.benchmarkline {stroke: 1px solid black; stroke-dasharray:2}

path.medianLine {stroke: #111; fill: none;}

path.q1Line, path.q3Line {stroke: #555; fill: none; }
path.q1Line {stroke-dasharray:1}
path.q3Line {stroke-dasharray:2,1}
</style>`
Insert cell
d3 = require("d3@5")
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