Public
Edited
Jun 2, 2023
Insert cell
Insert cell
sleepWaves()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function addBackgroundGradient(svg) {
var grad = svg.append("defs").append("linearGradient").attr("id", "linear");
grad.append("stop").attr("offset", "0%").attr("stop-color", "#39334A");
grad.append("stop").attr("offset", "100%").attr("stop-color", "#424C77");

svg
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "url(#linear)");
}
Insert cell
colorScale = d3
.scaleOrdinal()
.domain(["Deep", "Core", "REM", "Awake"])
.range(["#678AB3", "#729AC1", "#87B8E8", "#FBA76D"])
Insert cell
opacityScale = d3
.scaleOrdinal()
.domain(["Deep", "Core", "REM", "Awake"])
.range([0.5, 0.7, 0.8, 1.0])
Insert cell
Insert cell
function addGlow(svg) {
var filter = svg.selectAll("defs").append("filter").attr("id", "glow");
filter
.append("feGaussianBlur")
.attr("stdDeviation", "1")
.attr("result", "coloredBlur");
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode").attr("in", "coloredBlur");
feMerge.append("feMergeNode").attr("in", "SourceGraphic");
}
Insert cell
function sleepWaves() {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

addBackgroundGradient(svg);
addGlow(svg);

const gradients = svg
.append("g")
.selectAll("linearGradient")
.data(d3.group(lineData, (d) => d.date))
.join("linearGradient")
.attr("id", ([date]) => "gradientColorId" + date)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("x2", width)
.selectAll("stop")
.data(([, group]) => group)
.join("stop")
.attr("offset", (d) => xScale(d.time) / width)
.attr("stop-color", (d) => colorScale(d.category))
.attr("stop-opacity", (d) => opacityScale(d.category));

const area = d3
.area()
.curve(d3.curveBasis)
.x((d) => xScale(d.time))
.y0((d) => yScale(d.y0))
.y1((d) => yScale(d.y1));

const path = svg
.selectAll("path")
.data(d3.group(lineData, (d) => d.date))
.join("path")
.attr("fill", ([date]) => "url(#gradientColorId" + date + ")")
.attr("d", ([, group]) => area(group))
.style("filter", "url(#glow)");

return svg.node();
}
Insert cell
Insert cell
simpleSleepWaves = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])

addBackgroundGradient(svg);
const line = d3.line()
.curve(d3.curveBasis)
.x(d => xScale(d.time))
.y(d => yScale(d.y));
const path = svg.append("g")
.selectAll("path")
.data(d3.group(lineData, d => d.date))
.join("path")
.attr("stroke", "white")
.attr("fill", "none")
.attr("d", ([, group]) => line(group));

return svg.node();
}
Insert cell
ribbons = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

addBackgroundGradient(svg);

const area = d3
.area()
.curve(d3.curveBasis)
.x((d) => xScale(d.time))
.y0(d => yScale(d.y0))
.y1((d) => yScale(d.y1));

const path = svg
.append("g")
.selectAll("path")
.data(d3.group(lineData, (d) => d.date))
.join("path")
.attr("fill", "white")
.attr("d", ([, group]) => area(group));

return svg.node();
}
Insert cell
ribbonsVariableOpacity = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

addBackgroundGradient(svg);

const gradients = svg
.append("g")
.selectAll("linearGradient")
.data(d3.group(lineData, (d) => d.date))
.join("linearGradient")
.attr("id", ([date, ]) => "gradientId" + date)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("x2", width)
.selectAll("stop")
.data(([, group]) => group)
.join("stop")
.attr("offset", d => xScale(d.time) / width)
.attr("stop-color", d => "white")
.attr("stop-opacity", d => opacityScale(d.category));

const area = d3
.area()
.curve(d3.curveBasis)
.x((d) => xScale(d.time))
.y0(d => yScale(d.y0))
.y1((d) => yScale(d.y1));

const path = svg
.selectAll("path")
.data(d3.group(lineData, (d) => d.date))
.join("path")
.attr("fill", ([date, ]) => "url(#gradientId" + date + ")")
.attr("d", ([, group]) => area(group));

return svg.node();
}
Insert cell
ribbonsBlue = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

addBackgroundGradient(svg);
addGlow(svg);

const gradients = svg
.append("g")
.selectAll("linearGradient")
.data(d3.group(lineData, (d) => d.date))
.join("linearGradient")
.attr("id", ([date, ]) => "gradientColorId2" + date)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("x2", width)
.selectAll("stop")
.data(([, group]) => group)
.join("stop")
.attr("offset", d => xScale(d.time) / width)
.attr("stop-color", "#87B8E8")
.attr("stop-opacity", d => opacityScale(d.category));

const area = d3
.area()
.curve(d3.curveBasis)
.x((d) => xScale(d.time))
.y0(d => yScale(d.y0))
.y1((d) => yScale(d.y1));

const path = svg
.selectAll("path")
.data(d3.group(lineData, (d) => d.date))
.join("path")
.attr("fill", ([date, ]) => "url(#gradientColorId2" + date + ")")
.attr("d", ([, group]) => area(group))
.style("filter", "url(#glow)");

return svg.node();
}
Insert cell
Insert cell
Plot.plot({
width: 600,
height: 800,
fill: "blue",
inset: 100,
x: {label: null, ticks: "none"},
y: {label: null, ticks: "none", insetTop: 3, insetBottom: 3},
fy: {padding: 0.0, ticks: "none", label: null},
facet: {
data: simpleLineData,
y: "date",
},
marks: [
Plot.frame({ fill: "#424C77", strokeWidth: 0.5}),
Plot.line(
simpleLineData, {x: "time", y: "y", curve: "basis", "stroke": "#D5E8FD"})
]
})
Insert cell
Plot.plot({
width: 1000,
height: 500,
inset: 75,
fill: "blue",
x: {label: null, ticks: "none", insetRight: 3, insetLeft: 3},
y: {label: null, ticks: "none", reverse: true},
fx: {padding: 0.0, ticks: "none", label: null},
facet: {
data: simpleLineData,
x: "date",
},
marks: [
Plot.frame({ fill: "#424C77", strokeWidth: 0.5}),
Plot.line(
simpleLineData, {y: "time", x: "y", curve: "basis", "stroke": "#D5E8FD"})
]
})
Insert cell
simpleLineData = makeSimpleLineData(data)
Insert cell
function makeSimpleLineData(data) {
const lineData = [];
for (let i = 0; i < data.length; ++i) {
if (data[i].date.month == 1) {
const yValue = calculateSimpleY(data[i].category, data[i].duration);
lineData.push({
date: data[i].date,
time: data[i].relStart,
y: yValue,
category: data[i].category
});
lineData.push({
date: data[i].date,
time: data[i].relStart + data[i].duration,
y: yValue,
category: data[i].category
});
}
}
return lineData;
}
Insert cell
function calculateSimpleY(category) {
if (category == "Awake") {
return 0.8;
} else if (category == "REM") {
return 0.6;
} else if (category == "Core") {
return 0.4;
} else if (category == "Deep") {
return 0.2;
}
}
Insert cell
Insert cell
margin = ({ top: 20, right: 0.1 * width, bottom: 20, left: 0.1 * width })
Insert cell
height = width
Insert cell
xScale = d3
.scaleLinear()
.domain([d3.min(lineData, (d) => d.time), d3.max(lineData, (d) => d.time)])
.range([margin.left, width - margin.right])
Insert cell
yScale = d3
.scaleLinear()
.domain([d3.min(lineData, (d) => d.y0), d3.max(lineData, (d) => d.y1)])
.range([margin.top, height - margin.bottom])
Insert cell
function calculateGlobalY(category) {
if (category == "Awake") {
return 0.1;
} else if (category == "REM") {
return 0.3;
} else if (category == "Core") {
return 0.5;
} else if (category == "Deep") {
return 0.8;
}
}
Insert cell
function calculateUpperY(category) {
if (category == "Awake") {
return 0.05;
} else if (category == "REM") {
return 0.4;
} else if (category == "Core") {
return 0.5;
} else if (category == "Deep") {
return 0.65
}
}
Insert cell
function calculateLowerY(category) {
if (category == "Awake") {
return 0.2;
} else if (category == "REM") {
return 0.5;
} else if (category == "Core") {
return 0.6;
} else if (category == "Deep") {
return 0.95;
}
}
Insert cell
function makeLineData(data) {
const lineData = [];
let day = data[0].day;
let dayIndex = 0;
for (let i = 0; i < data.length; ++i) {
if (data[i].date.month == 1) {
if (data[i].date.day != day) {
dayIndex += 1;
day = data[i].date.day;
}
const yValue = calculateGlobalY(data[i].category) + dayIndex;
const y0 = calculateLowerY(data[i].category) + dayIndex;
const y1 = calculateUpperY(data[i].category) + dayIndex;
lineData.push({
date: data[i].date,
time: data[i].relStart,
y: yValue,
y0: y0,
y1: y1,
category: data[i].category
});
lineData.push({
date: data[i].date,
time: data[i].relStart + data[i].duration,
y: yValue,
y0: y0,
y1: y1,
category: data[i].category
});
}
}
return lineData;
}
Insert cell
lineData = makeLineData(data);
Insert cell
import {data} from "@cydneyn/sleep-data-processing"
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