Notebooks 2.0 is here.

Published
Edited
Nov 18, 2019
2 forks
3 stars
Insert cell
Insert cell
chart = {
// Initialize svg
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
// .style("background-color", "#eee");

// Append the grid lines on X axis
svg.append("g")
.attr("class", "grid")
.attr("transform", `translate(${x.bandwidth()/2}, ${height - margin.bottom})`)
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)

// Append the bars
svg.append("g")
.selectAll("g")
.data(series)
.enter().append("g")
.attr("fill", d => color(d.key))
.attr("data-legend", d => d.key)
// .attr("class", d => color(d.key))
.selectAll("rect")
.data(d => d)
.enter().append("rect")
// .attr("class", d => color(d.key))
.attr("width", x.bandwidth)
.attr("x", d => x(d.data.hour))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))

// Append line chart for SOC
svg.append("path")
.datum(line_series)
.attr("fill", "none")
.attr("stroke", "orange")
.attr("stroke-width", 2.5)
// .attr("stroke-linejoin", "round")
// .attr("stroke-linecap", "round")
.attr("d", line);
// Append the X-axis
svg.append("g")
.call(xAxis);

// Append the Y-axis
let y_axis = svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.attr("id", "y-axis")
.attr("class", "y axis")
.call(yAxis)
// Replace 0 tick on y-axis with -
y_axis.selectAll("g.tick")
.filter( d => d == 0)
.select("text")
.text("-");
// Y label
svg.append("g")
.attr("transform", `translate(${margin.left/2}, ${(height - margin.top)/2})`)
.attr("class", "y-axis-label")
.append("text")
.attr("transform", "rotate(-90)")
.text("mW");
// Append X-axis label
svg.append("text")
.attr("class", "x-axis-label")
.attr("transform", `translate(${width/2}, ${height - margin.top})`)
.style("text-anchor", "middle")
.text("Hour of the day")
// Line chart legend
svg.append('rect')
.attr('x', width - margin.right)
.attr('y', margin.top)
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', 'orange')
.style('stroke', 'orange');

svg.append('text')
.attr("class", "legend-text")
.attr('x', width - margin.right + legendRectSize + legendSpacing)
.attr('y', margin.top + legendRectSize)
.text('SOC');

// Bar chart legends
const legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', (d, i) => {
let legendHeight = legendRectSize + legendSpacing;
let x = width - margin.right;
let y = (i+1) * legendHeight + margin.top;
return `translate(${x}, ${y})`;
});

legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);

legend.append('text')
.attr("class", "legend-text")
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize)
.text(d => d);

// Return generated svg
return svg.node();
}
Insert cell
html`
<style>
.grid line {
stroke: lightgrey;
stroke-opacity: .4;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.x-axis-label, .y-axis-label {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
g.green-bar {
fill: #007f00;
}
g.blue-bar {
fill: royalblue;
}
g.striped-bar {
mask: url(#mask-stripe);
}
.legend-text {
font-size: 12px;
// font-weight: bold;
}
</style>
`
Insert cell
legendSpacing = 5
Insert cell
legendRectSize = 10
Insert cell
legend_auto = d3Legend
.legendColor()
.scale(color)
.labels(color.domain())
Insert cell
bar_colors = d3.schemePuBu[5]
Insert cell
// color = d3.scaleOrdinal(d3.schemeCategory10);
color = d3.scaleOrdinal()
.domain(series.map(d => d.key))
// .range(["green-bar", "blue-bar", "striped-bar green-bar", "striped-bar blue-bar"])
// .range(["#7f0000", "#007f00", "#00007f", "#7f7f7f"])
.range(bar_colors)
.unknown("#ccc");
Insert cell
line = d3.line()
.defined(d => !isNaN(d.SOC))
.x(d => x(d.hour))
.y(d => y(d.SOC));
Insert cell
// Function to produce gridlines in y-axis
make_x_gridlines = () => d3.axisBottom(x);
Insert cell
formatNumber = d3.format("(.0f")
Insert cell
// yAxis = g => g
// .attr("transform", `translate(${margin.left},0)`)
// .attr("id", "y-axis")
// .call(d3.axisLeft(y).ticks(null, "s"))
// .call(g => g.selectAll(".domain").remove())
yAxis = d3.axisLeft(y).ticks(null, "s").tickFormat(formatNumber)
Insert cell
y = d3.scaleLinear()
.domain([d3.min(series, d => d3.min(d, d => d[0])), d3.max(series, d => d3.max(d, d => d[1]))])
.rangeRound([height - margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom + 10})`)
.call(d3.axisBottom(x).tickSize(0))
.call(g => g.selectAll(".domain").remove())
Insert cell
x = d3.scaleBand()
.domain(data.map(d => d.hour))
.rangeRound([margin.left, width - margin.right])
.padding(0.2)
Insert cell
height = 500
Insert cell
margin = ({top: 5, right: 80, bottom: 50, left: 30})
Insert cell
line_series = data.map( d => { return { hour: d.hour, SOC: d.SOC }; } );
Insert cell
series = d3.stack().keys(Object.keys(data[0]).slice(2)).offset(d3.stackOffsetDiverging)(data)
Insert cell
data = (await
// d3.csv("https://gist.githubusercontent.com/sashtur/3ce40c067f2d3423a1094a7a7a59836a/raw/a42ba490a0b13558d22575cf34470fa924c3e797/gistfile1.txt", d3.autoType)
d3.json("https://gist.githubusercontent.com/sashtur/dc0a3353d24048d17e4974b97960c4f0/raw/d688ff57f79afa4c7635c6219862aa6e95488bf3/stacked%2520bar%25202", d3.autoType)
)
Insert cell
d3 = require("d3@5")
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
d3Legend = require('d3-svg-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