Published
Edited
Apr 14, 2020
3 forks
4 stars
Insert cell
md`
# Animated Line Graph
Animation https://bl.ocks.org/mbostock/5649592
Google stock price. Data: Yahoo Finance
`
Insert cell
viewof dataSelector = radio( {
title: 'Select the data to be plotted',
options: [
{ label: 'Initial', value: 'data' },
{ label: 'Alternate', value: 'data1' },
],
value: 'data'
} );
Insert cell
dataSelector
Insert cell
bool_func= { var v
if(dataSelector == 'data')
{return data}
else{} return data1 }
Insert cell
chart = {
const svg = d3.select(DOM.svg(width, height))
.style("-webkit-tap-highlight-color", "transparent")
.style("overflow", "visible");

svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", line).call(transition);

const tooltip = svg.append("g");

svg.on("touchmove mousemove", function() {
const {date, value} = bisect(d3.mouse(this)[0]);

tooltip
.attr("transform", `translate(${x(date)},${y(value)})`)
.call(callout, `${value.toLocaleString(undefined, {style: "currency", currency: "USD"})}
${date.toLocaleString(undefined, {month: "short", day: "numeric", year: "numeric"})}`);
});

svg.on("touchend mouseleave", () => tooltip.call(callout, null));

return svg.node();
}
Insert cell
height = 500
Insert cell
margin = ({top:20, right:30, bottom:30, left:40})
Insert cell
x = d3.scaleTime()
.domain(d3.extent(bool_func, d => d.date))
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(bool_func, d=> d.value)]).nice()
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 200).tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
Insert cell
function transition(path) {
path.transition()
.duration(7500)
.attrTween("stroke-dasharray", tweenDash)
.on("end", () => { d3.select(this).call(transition); });
}
Insert cell
function tweenDash() {
const l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) { return i(t) };
}
Insert cell
callout = (g, value) => {
if (!value) return g.style("display", "none");

g
.style("display", null)
.style("pointer-events", "none")
.style("font", "10px sans-serif");

const path = g.selectAll("path")
.data([null])
.join("path")
.attr("fill", "white")
.attr("stroke", "black");

const text = g.selectAll("text")
.data([null])
.join("text")
.call(text => text
.selectAll("tspan")
.data((value + "").split(/\n/))
.join("tspan")
.attr("x", 0)
.attr("y", (d, i) => `${i * 1.1}em`)
.style("font-weight", (_, i) => i ? null : "bold")
.text(d => d));

const {x, y, width: w, height: h} = text.node().getBBox();

text.attr("transform", `translate(${-w / 2},${15 - y})`);
path.attr("d", `M${-w / 2 - 10},5H-5l5,-5l5,5H${w / 2 + 10}v${h + 20}h-${w + 20}z`);
}
Insert cell
bisect = {
const bisect = d3.bisector(d => d.date).left;
return mx => {
const date = x.invert(mx);
const index = bisect(data, date, 1);
const a = data[index - 1];
const b = data[index];
return date - a.date > b.date - date ? b : a;
};
}
Insert cell
line = d3.line()
.defined(d => !isNaN(d.value))
.x(d => x(d.date))
.y(d => y(d.value))
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
function updateData () {
var data = dataSelector === 'data1' ? data: data1;
y.domain( d3.extent( dataSelector, datapoint => datapoint.value ) )
x.domain( d3.extent( dataSelector, datapoint => datapoint.date ) )
var path = d3.select( '.chart__line' )
.transition()
.duration( 500 )
.attr( 'd', line( data ) );
}
Insert cell
data = Object.assign((d3.csvParse(await FileAttachment("GOOG - GOOG.csv").text(), d3.autoType)).map(({date, close}) => ({date, value: close})), {y: "$ Close"})
Insert cell
data1=Object.assign((d3.csvParse(await FileAttachment("NQ=F - NQ=F (1).csv").text(), d3.autoType)).map(({date, close}) => ({date, value: close})), {y: "$ Close"})
Insert cell
d3 = require('d3@5')
Insert cell
import { radio } from '@jashkenas/inputs';
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