Published unlisted
Edited
Aug 26, 2020
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", `0 0 ${width} ${height}`)
.attr("class", "svg-content")

// Drawing axes
svg.append("g")
.attr("class", "axis")
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(xAxis);

svg.append("g")
.attr("class", "axis")
.attr('transform', `translate(${margin.left}, 0)`)
.call(yAxis)
// adds a label to the Y axis
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", - margin.top)
.attr("y", 16)
.style("text-anchor", "end")
.text("Closing Price");

// Drawing lines
const lines = svg.selectAll("lines")
.data(slices)
.enter()
.append("g")

lines.append("path")
.attr("class", d => `line-${d.num}`)
.attr("fill", "none")
.attr("stroke-width", 2)
.attr("d", d => line(d.values));

// Adding series label at the end of each line
lines.append("text")
.attr("class","series-label")
// datum bypasses the data-join process altogether (enter/update/exit)
// https://ils.unc.edu/~gotz/D3joins/ // data-join visualization
.datum(d => {
return {
id: d.id,
value: d.values[d.values.length - 1]};
})
.attr("transform", d => {
return `translate( ${(xScale(d.value.date))}, ${(yScale(d.value.price))})`;})
.attr("x", 20)
.attr("y", 5)
.text(d => d.id);
// Adding a color square to each series-label
lines.append("rect")
.datum(d => {
return {value: d.values[d.values.length - 1]};
})
.attr("transform", d => {
return `translate( ${xScale(d.value.date)}, ${yScale(d.value.price)})`;})
.attr("x", 5)
.attr("y", -5)
.attr("width", 10)
.attr("height", 10)
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dataset = (d3.csvParse(await FileAttachment("stock_data_08-2020@1.csv").text()))
Insert cell
timeConv = d3.timeParse("%Y-%m-%d")
Insert cell
Insert cell
slices = dataset.columns.slice(1).map((id,idx) => {
return {
id: id,
num: idx,
values: dataset.map(d => {
return {
date: timeConv(d.date),
price: +d[id]
};
})
};
})
Insert cell
Insert cell
xScaleMinMax = d3.extent(dataset, d => timeConv(d.date))
Insert cell
yScaleMax = d3.max(slices, column => {
return d3.max(column.values, d => {
return d.price
});
})
Insert cell
xScale = d3.scaleTime()
.domain(xScaleMinMax)
.range([margin.left + 20, width - margin.right])
Insert cell
yScale = d3.scaleLinear()
.domain([0, yScaleMax + 20])
.range([height - margin.bottom, margin.top])
Insert cell
Insert cell
xAxis = d3.axisBottom()
// calculates the ticks to a unit of time aligned with the calendar
.ticks(d3.timeMonth.every(1)) // change .every(2) to display every other month
.tickFormat(d3.timeFormat('%b %Y')) // formats the date
.scale(xScale)
Insert cell
Insert cell
yAxis = d3.axisLeft()
.ticks(10) // spread the ticks by 10 units
.tickFormat(d3.format('$'))
.scale(yScale)
Insert cell
Insert cell
Insert cell
line = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.price))
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more