Published
Edited
Feb 21, 2022
Insert cell
Insert cell
Insert cell
dataset = d3.csvParse(await FileAttachment("data.csv").text(), rowConverter);
Insert cell
rowConverter = (row) => {
// Modify code here for row conversion
const form = d3.timeParse("%Y-%m-%d");
return {date:form(row['date']),hours_of_sleep: +(row['hours_of_sleep'])};
}
Insert cell
w = 600
Insert cell
h = 500
Insert cell
makeChart()
Insert cell
function makeChart() {
// sort by date ascending
dataset.sort((a, b) => a.date - b.date);

console.log(dataset);

//padding

let xAxisOff = 18.1; // based on the height of the <g> element
let yAxisOff = 20; //based on the width of the <g> element

let xMaxPad = 10;
let yMaxPad = 4;

let xMinPad = yAxisOff;
let yMinPad = xAxisOff;
const numDaysSlider = html`
<input id="numDaysSlider" type="range" min="1" max="7" value="7"></input>
`;

const daysText = html`
<span id="daysText">7</span>
`;

const svg = d3.create("svg").attr("width", w).attr("height", h);

let key = (d) => d.date;

let endDate = new Date(d3.max(dataset, (d) => d.date));
endDate.setDate(endDate.getDate() + 1);

//Create scales
const xScale = d3
.scaleTime()
.domain([d3.min(dataset, (d) => d.date), endDate])
.rangeRound([80, w - 80]);
const yScale = d3
.scaleLinear()
.domain([12, 0])
.rangeRound([20, h - 20]);
let cScale = d3.scaleLinear().domain([0, 12]).range(["red", "orange"]);

const xAxis = d3.axisBottom(xScale);
xAxis.ticks(7, "%a");
const yAxis = d3.axisLeft(yScale);

const xAxisGroup = svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(0, ${h - 20})`)
.call(xAxis);

const yAxisGroup = svg
.append("g")
.attr("class", "axis-left")
.attr("transform", `translate(80,0)`)
.call(yAxis);

svg
.selectAll("rect")
.data(dataset, key)
.enter()
.append("rect")
.attr("x", (d) => xScale(d.date))
.attr("y", (d) => yScale(d.hours_of_sleep) - yMinPad)
.attr("width", barWidth(7))
.attr("height", (d) => h - yScale(d.hours_of_sleep))
.attr("fill", (d) => cScale(d.hours_of_sleep));

function barWidth(numBars) {
return (w - (xMinPad + xMaxPad)) / numBars;
}

function updateGraph() {
const numDays = +numDaysSlider.value;
daysText.innerText = numDays;

const subSection = dataset.slice(7 - numDays, 7);

var newData = dataset.slice(7 - numDays, 7);

const axScale = d3
.scaleTime()
.domain([d3.min(subSection, (d) => d.date), endDate])
.rangeRound([80, w - 80]);

const ayScale = d3
.scaleLinear()
.domain([12, 0])
.rangeRound([20, h - 20]);

svg
.selectAll("rect")
.data(subSection, (d) => d.date)
.join(
(enter) =>
enter
.append("rect")
.attr("x", (d) => xScale(d.date) + 800)
.attr("y", (d) => h - yScale(d.hours_of_sleep) - 20)
.attr("width", (w - 160) / numDays)
.attr("height", (d) => yScale(d.hours_of_sleep))
.attr("fill", (d) => cScale(d.hours_of_sleep)),
(update) =>
update
.transition()
.attr("x", (d) => axScale(d.date))
.attr("width", (w - 160) / numDays),
(exit) => exit.transition().attr("x", (d) => xScale(d.date) - 800)
);

//var bars = svg.selectAll("rect").data(newData, key);
//bars
// .enter()
// .append("rect")
// .attr("x", (d) => -1 * barWidth(numDays))
// .attr("y", (d) => h - yScale(d.hours_of_sleep) - yMinPad)
// .attr("height", (d) => yScale(d.hours_of_sleep))
// .attr("fill", (d) => cScale(d.hours_of_sleep))
// .merge(bars)
// .transition("barsIn")
// .duration(500)
// .attr("x", (d) => xScale(d.date))
// .attr("width", barWidth(numDays));
//bars
// .exit()
// .transition("barsOut")
// .duration(500)
// .attr("x", (d) => -1 * barWidth(numDays))
// .remove();

xAxisGroup.transition("xAxis").duration(500).call(xAxis);

const axAxis = d3.axisBottom(axScale);
axAxis.ticks(numDays, "%a");
const ayAxis = d3.axisLeft(ayScale);

xAxisGroup.call(axAxis);
yAxisGroup.call(ayAxis);
}

numDaysSlider.addEventListener("input", updateGraph);

return html`
<h1>Sleep</h1>
<label>Days to Show</label>
${numDaysSlider}
${daysText}

<div id='chart'>
${svg.node()}
</div>
<!-- add any necessary HTML here, either directly or using the pattern
set by numDaysSlider & daysText
-->
`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3@7")
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