Published
Edited
Jul 17, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

viewof b = html`<button class="f6 dim bw1 ba ph3 pv2 mb2 pointer cm-border--dark-orange fw5">Toggle state data</button>`
Insert cell
Insert cell
Insert cell

drawComparisonChart = ele => {
const svg = ele
.append("svg")
.style("height", chart_height + "px")
.style("width", chart_width + "px");
// negative area missing values
svg.append("path")
.datum(d => d.values.filter(areaNeg.defined()))
.attr("fill", "white")
.attr("d", areaNeg)
// missing values positive area
svg.append("path")
.datum(d => d.values.filter(areaPos.defined()))
.attr("fill", "white")
.attr("d", areaPos)
// negative area
svg.append("path")
.datum(d => d.values)
.attr("fill", d => '#05A0C4')
.style("opacity", .80)
.attr("d", d3.area()
.curve(d3.curveStep)
.x(d => x(timeParser(d.date)))
.y0(y(height))
.y1(d => y(Math.min(0,d.perc_change))))
// positive area
svg.append("path")
.datum(d => d.values)
.attr("fill", 'white')
// .attr("d", areaPos)
.attr("d", d3.area()
.curve(d3.curveStep)
.x(d => x(timeParser(d.date)))
.y0(y(height))
.y1(d => y(Math.max(0,d.perc_change))))
// STATE DATA
// Line
if (toggle) {
svg.append("path")
.data(by_type_data)
.datum(d => d.values)
.attr("stroke", "#F4A045")
.attr('stroke-width', 2)
.attr('stroke-opacity', 1)
.attr('fill', 'none')
.attr("d", d3.line()
.curve(d3.curveLinear)
.x(d => x(timeParser(d.date)))
.y(d => y(d.perc_change)))
}
// Axes
svg.append("g").call(xAxis)
.select('.domain').remove();
svg.append("g").call(yAxis)
.select('.domain').remove();
// Axis labels, title
svg.append('text').call(chartTitle);

// line for shelter in place order
svg.append('line')
.style('stroke', '#8D6A9F')
.style('stroke-width', 1)
.style('stroke-dasharray', '6,3')
.style('opacity', 0.7)
.attr("x1", x(timeParser("2020-03-19")))
.attr("y1", margin.top + 5)
.attr("x2", x(timeParser("2020-03-19")))
.attr("y2", 185)
// dummy y axis
svg.append('line')
.style('stroke', '#C4C4C4')
.style('stroke-width', .75)
.attr("x1", x(timeParser("2020-02-15")))
.attr("y1", margin.top + 5)
.attr("x2", x(timeParser("2020-02-15")))
.attr("y2", 185)

// baseline
svg.append('line')
.style('stroke', '#C4C4C4')
.style('stroke-width', 0.75)
.attr("x1", x(timeParser('2020-02-15')))
.attr("y1", y(0))
.attr("x2", x(timeParser('2020-07-05')))
.attr("y2", y(0))

}
Insert cell
// generator for negative area
// null values are considered missing data
areaNeg = d3.area()
.curve(d3.curveStep)
.defined(d => d.perc_change != null)
.x(d => x(timeParser(d.date)))
.y0(y(height))
.y1(d => y(Math.min(0,d.perc_change)))
Insert cell
Insert cell
Insert cell
Insert cell
chart_width = 350;
Insert cell
Insert cell
Insert cell
Insert cell
tickFormatter = d3.timeFormat('%b');
Insert cell
timeParser = d3.timeParse('%Y-%m-%d');
Insert cell
Insert cell
yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y)
.ticks(6)
.tickFormat(d => d + '%'))
.call(g => g.selectAll('.tick:nth-of-type(3) text')
.style('font-size', '10px')
.text(`baseline`))
.call(g => g.selectAll('.tick line')
.style('display', 'none'))
Insert cell
xLabel = ele =>
ele
.text("date")
.attr("x", (x.range()[1] - x.range()[0]) / 2)
.attr("y", chart_height - margin.bottom + 35)
.style('font-size', '14px')
Insert cell
Insert cell
chartTitle = ele =>
ele
.text(d => d.key.charAt(0).toUpperCase() + d.key.slice(1))
.attr("transform", `translate(5, 12)`)
.style("text-anchor", "start")
.style('font-size', '14 px')
.style('font-weight', '600')
Insert cell
Insert cell
// trying with missing values as null
counties_data_nulls = FileAttachment("data_mob_google_counties_longer_NAs@1.json").json()
Insert cell
filtered_counties_nulls = counties_data_nulls.filter(d => d.county == county)
Insert cell
by_type_counties_data_nulls = d3
.nest()
.key(d => d.category)
.entries(filtered_counties_nulls)
Insert cell
ca_data = FileAttachment("data_mob_google_ca_longer.json").json()
// each object has: date, category, perc_change
Insert cell
Insert cell
counties_data = FileAttachment("data_mob_google_counties_longer.json").json()
// each object has: county, date, category, perc_change
Insert cell
filtered_counties = counties_data.filter(d => d.county == county)
Insert cell
by_type_counties_data = d3
.nest()
.key(d => d.category)
.entries(filtered_counties)
Insert cell
Insert cell
Insert cell
height = 500
Insert cell
margin = ({ top: 25, right: 10, bottom: 30, left: 50 })
Insert cell
Insert cell
Insert cell
embedStyles = html`<style>
.chart-container {
display:inline-block;
}
.underline {
text-decoration: underline;
}
.ul-purple {
border-bottom-style: dashed;
border-color: rgba(141, 106, 159, 0.7);
border-width: .15rem;
}
.ul-orange {
border-bottom-style: solid;
border-color: rgba( 244, 160, 69, 0.75);
border-width: .15rem;
}
</style>`
Insert cell
// allStyles = html`<style>
// @import url('https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,300;0,400;0,700;1,200;1,300;1,400;1,700&display=swap');
// body {
// font-family: Overpass, serif;
// }
// .chart-container {
// display:inline-block;
// }
// .underline {
// text-decoration: underline;
// }
// .ul-purple {
// border-bottom-style: dashed;
// border-color: rgba(141, 106, 159, 0.7);
// border-width: .15rem;
// }
// .ul-blue {
// // border-bottom-style: solid;
// // border-color: rgba(0, 0, 255, 0.2);
// // border-width: .15rem;
// background-color: rgba(0, 0, 255, 0.2);
// }
// .ul-red {
// // border-bottom-style: solid;
// // border-color: rgba(255, 0, 0, 0.2);
// // border-width: .15rem;
// background-color: rgba(255, 0, 0, 0.2);
// }
// .ul-orange {
// border-bottom-style: solid;
// border-color: rgba( 244, 160, 69, 0.75);
// border-width: .15rem;
// }
// button {
// border: 2px solid #F4A045;
// }
// button#btn-toggle {
// border: 2px solid #F4A045;
// padding: 0.5rem;
// }
// </style>`
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