From 7452909a82e4cb4c835f0c1021913c8a08d95785 Mon Sep 17 00:00:00 2001 From: William Harvey Date: Sun, 21 Jun 2020 17:27:30 -0400 Subject: [PATCH 01/47] Remove some useless comments (for ex. function headers) --- polydodo/src/d3/bar_chart/initBarChart.js | 5 ---- polydodo/src/d3/bar_chart/legend.js | 16 +------------ polydodo/src/d3/bar_chart/stages-charts.js | 13 +++++----- polydodo/src/d3/bar_chart/transition.js | 24 +++++++++---------- .../src/d3/spectrogram/initSpectrogram.js | 20 +++++++++------- polydodo/src/d3/spectrogram/legend.js | 10 -------- 6 files changed, 29 insertions(+), 59 deletions(-) diff --git a/polydodo/src/d3/bar_chart/initBarChart.js b/polydodo/src/d3/bar_chart/initBarChart.js index bf565a05..53300aa7 100644 --- a/polydodo/src/d3/bar_chart/initBarChart.js +++ b/polydodo/src/d3/bar_chart/initBarChart.js @@ -35,9 +35,7 @@ const initializeBarChart = async (svg, height, useTransitions = true) => { const { xAxis, yAxis } = initializeAxes(x, y); const gBarChart = createDrawingGroup(svg, MARGIN); - /***** Chargement des données *****/ const data = await d3.csv(barChartData); - /***** Prétraitement des données *****/ var totalTimeStamp = data.length; var tooltip = tip().attr('class', 'd3-tip').offset([-10, 0]); @@ -55,7 +53,6 @@ const initializeBarChart = async (svg, height, useTransitions = true) => { domainX(x, data); domainY(y, STATES_ORDERED); - /***** Création du graphique Stacked bar chart *****/ createStackedBarChart(gBarChart, sources, x, color, tooltip, barHeight); if (useTransitions) { var gSecondBarChart = svg.append('g').attr('transform', 'translate(' + MARGIN.LEFT + ',' + (2 * MARGIN.TOP + barHeight) + ')'); @@ -89,7 +86,6 @@ const initializeBarChart = async (svg, height, useTransitions = true) => { //get tick d3.selectAll('.tick').select('text').style('font-weight', 540); - /***** Création de l'infobulle *****/ tooltip.html(function (d) { return getToolTipText.call(this, d); }); @@ -100,7 +96,6 @@ const initializeBarChart = async (svg, height, useTransitions = true) => { }); svg.call(tipStacked); - /***** Création de la légende *****/ barLegend(svg, STATES, color); }; diff --git a/polydodo/src/d3/bar_chart/legend.js b/polydodo/src/d3/bar_chart/legend.js index 6201b8d0..889b9de3 100644 --- a/polydodo/src/d3/bar_chart/legend.js +++ b/polydodo/src/d3/bar_chart/legend.js @@ -1,14 +1,3 @@ -/** - * Fichier permettant de générer la légende et de gérer les interactions de celle-ci. - */ - -/** - * Crée une légende à partir de la source. - * - * @param svg L'élément SVG à utiliser pour créer la légende. - * @param sources Données triées par nom de rue et par date. - * @param color Échelle de 10 couleurs. - */ export const barLegend = (svg, states, color) => { var size = 20; @@ -29,10 +18,7 @@ export const barLegend = (svg, states, color) => { .style('fill', function (d, i) { return color(i); }) - .attr('transform', 'translate(' + 100 + ',' + 0 + ')') - .on('click', function (d) { - //displayLine(d3.select(this), color(d)); - }); + .attr("transform", "translate(" + 100 + "," + 0 + ")"); svg .selectAll('names') diff --git a/polydodo/src/d3/bar_chart/stages-charts.js b/polydodo/src/d3/bar_chart/stages-charts.js index 0d2b26ef..681ced7a 100644 --- a/polydodo/src/d3/bar_chart/stages-charts.js +++ b/polydodo/src/d3/bar_chart/stages-charts.js @@ -3,8 +3,7 @@ import { addZero, getDurationString, getDurationSecondString, getDurationStringH import { TRANSITION_TIME_MS } from '../constants'; export const createStackedBarChart = (g, sources, x, color, tip, height) => { - //Creating all the parts of the stacked bar chart - g.selectAll('.rect') + g.selectAll(".rect") .data(sources) .enter() .append('rect') @@ -79,7 +78,6 @@ export const createSmallStackedBarChart = (g, pourcentageData, data, name, total var text = stackedBar.append('text').attr('class', 'pourcentage'); - //hours text .append('tspan') .text((d) => getDurationStringHM(d.value * totalTimeStamp * 30)) @@ -97,7 +95,6 @@ export const createSmallStackedBarChart = (g, pourcentageData, data, name, total .attr('font-size', '25px') .attr('font-weight', 15); - //pourcentage text .append('tspan') .text((d) => d.value * 100 + '%') @@ -115,7 +112,6 @@ export const createSmallStackedBarChart = (g, pourcentageData, data, name, total .attr('font-size', '20px') .attr('font-weight', 10); - //create stackedbar axes createStagesDurationAxes(data, xAxis, width); g.append('g') @@ -127,6 +123,9 @@ export const createSmallStackedBarChart = (g, pourcentageData, data, name, total .selectAll('text') .style('font-size', '18px'); - //label - g.append('text').attr('class', 'label-sleepType').attr('x', 0).attr('y', -15).text(name); + g.append("text") + .attr("class", "label-sleepType") + .attr("x", 0) + .attr("y", -15) + .text(name); }; diff --git a/polydodo/src/d3/bar_chart/transition.js b/polydodo/src/d3/bar_chart/transition.js index 35742b79..fb62ecc3 100644 --- a/polydodo/src/d3/bar_chart/transition.js +++ b/polydodo/src/d3/bar_chart/transition.js @@ -32,15 +32,6 @@ export const addTransitions = ( fifthCallback = fifthTransition(gThirdBarChart, sources, xAxis, width, barHeight, totalTimeStamp, color); }; -/** - * Réalise une transition entre les données actuellement utilisées et les nouvelles qui doivent être utilisées. - * - * @param g Le groupe SVG dans lequel le graphique à bulles est dessiné. - * @param data Les nouvelles données à utiliser. - * @param x L'échelle pour l'axe X. - * @param y L'échelle pour l'axe Y. - * @param r L'échelle pour le rayon des cercles. - */ const firstTransition = (g, xAxis, yAxis, height, color) => () => { g.selectAll('.y.axis').remove(); @@ -66,16 +57,23 @@ const firstTransition = (g, xAxis, yAxis, height, color) => () => { .attr('y', (d) => height * d.stage) .attr('height', height); - //Move X axes - g.select('.x.axis') + g.select(".x.axis") .transition() .attr('transform', 'translate(0,' + height * 5 + ')') .duration(2000) .call(xAxis); }; -//second data vizualisation -const secondTransition = (g, data, firstIndexes, totalStagePortion, width, height, xAxis, tip) => () => { +const secondTransition = ( + g, + data, + firstIndexes, + totalStagePortion, + width, + height, + xAxis, + tip +) => () => { createStagesDurationAxes(data, xAxis, width); g.select('.x.axis').transition().duration(500).call(xAxis); diff --git a/polydodo/src/d3/spectrogram/initSpectrogram.js b/polydodo/src/d3/spectrogram/initSpectrogram.js index 12068b56..9fd040ed 100644 --- a/polydodo/src/d3/spectrogram/initSpectrogram.js +++ b/polydodo/src/d3/spectrogram/initSpectrogram.js @@ -8,16 +8,13 @@ import { createSpectrgramChart, getToolTipText } from './stages-charts'; import { FREQUENCY_BINS } from './constants'; export const initSpectrogram = (g, node, width, height, margin) => { - /**** Interpolateur de couleurs ****/ var colorInterpolator = d3.interpolatePlasma; - /***** Échelles *****/ var x = d3.scaleLinear().range([0, width]); var y = d3.scaleBand().range([height, 0]); var yColor = d3.scaleLinear().range(y.range()); var yAxisScale = d3.scaleLinear().range(y.range()); - /****** Axes *******/ var xAxis = d3.axisBottom(x).tickFormat((d) => `${d}h`); var yAxis = d3.axisLeft(yAxisScale).ticks(5, 's'); @@ -25,8 +22,6 @@ export const initSpectrogram = (g, node, width, height, margin) => { var spectrogram = g.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); var gLegend = g.append('g').attr('transform', 'translate(' + (margin.left + width) + ',' + margin.top + ')'); - /***** Chargement des données *****/ - /***** Prétraitement des données *****/ var color = d3.scaleSequential().interpolator(colorInterpolator); var tooltip = tip().attr('class', 'd3-tip').offset([-10, 0]); @@ -47,8 +42,17 @@ export const initSpectrogram = (g, node, width, height, margin) => { domainX(x, data, node); domainY(y, yAxisScale, frequencies); - // /***** Création du graphique Stacked bar chart *****/ - createSpectrgramChart(spectrogram, sources, x, y, color, tooltip, height, width, margin); + createSpectrgramChart( + spectrogram, + sources, + x, + y, + color, + tooltip, + height, + width, + margin + ); // Axes spectrogram @@ -61,12 +65,10 @@ export const initSpectrogram = (g, node, width, height, margin) => { spectrogram.append('g').attr('class', 'y axis').call(yAxis).selectAll('text').style('font-size', '18px'); - // /***** Création de l'infobulle *****/ tooltip.html(function (d) { return getToolTipText.call(this, d); }); g.call(tooltip); - // /***** Création de la légende *****/ legend(gLegend, color, yColor, height, margin.right); }; diff --git a/polydodo/src/d3/spectrogram/legend.js b/polydodo/src/d3/spectrogram/legend.js index eba3b4d3..e9c72108 100644 --- a/polydodo/src/d3/spectrogram/legend.js +++ b/polydodo/src/d3/spectrogram/legend.js @@ -1,15 +1,5 @@ import * as d3 from 'd3'; -/** - * Fichier permettant de générer la légende et de gérer les interactions de celle-ci. - */ - -/** - * Crée une légende à partir de la source. - * - * @param svg L'élément SVG à utiliser pour créer la légende. - * @param color L'échelle de couleurs. - */ export const legend = (svg, color, y, height, width) => { var interpolate = d3.interpolate(color.domain()[0], color.domain()[1]); From 1e688c33ec7f84332d27f5823c89a934b53f9217 Mon Sep 17 00:00:00 2001 From: William Harvey Date: Sun, 21 Jun 2020 20:49:27 -0400 Subject: [PATCH 02/47] Extract csv read from d3 to a react custom hook --- polydodo/src/assets/data/time2.csv | 896 ------------------ polydodo/src/components/d3component.js | 14 +- polydodo/src/d3/bar_chart/barChart.js | 10 +- polydodo/src/d3/bar_chart/initBarChart.js | 50 +- polydodo/src/d3/hypnogram/hypnogram.js | 93 +- polydodo/src/d3/spectrogram/spectrogram.js | 8 +- polydodo/src/hooks/api_hooks.js | 13 + polydodo/src/views/performance/performance.js | 152 ++- .../views/sleep_analysis/sleep_analysis.js | 154 ++- .../stacked_bar_chart_scrollytelling.js | 24 +- 10 files changed, 340 insertions(+), 1074 deletions(-) delete mode 100644 polydodo/src/assets/data/time2.csv create mode 100644 polydodo/src/hooks/api_hooks.js diff --git a/polydodo/src/assets/data/time2.csv b/polydodo/src/assets/data/time2.csv deleted file mode 100644 index cd0b07ec..00000000 --- a/polydodo/src/assets/data/time2.csv +++ /dev/null @@ -1,896 +0,0 @@ -timestamp,sleep_stage -611902200,2 -611902230,2 -611902260,2 -611902290,2 -611902320,2 -611902350,2 -611902380,2 -611902410,2 -611902440,2 -611902470,2 -611902500,2 -611902530,2 -611902560,2 -611902590,2 -611902620,2 -611902650,2 -611902680,2 -611902710,2 -611902740,2 -611902770,2 -611902800,2 -611902830,2 -611902860,2 -611902890,2 -611902920,2 -611902950,2 -611902980,2 -611903010,2 -611903040,2 -611903070,2 -611903100,4 -611903130,4 -611903160,4 -611903190,4 -611903220,4 -611903250,4 -611903280,4 -611903310,4 -611903340,4 -611903370,4 -611903400,4 -611903430,4 -611903460,4 -611903490,4 -611903520,4 -611903550,4 -611903580,4 -611903610,4 -611903640,4 -611903670,4 -611903700,4 -611903730,4 -611903760,4 -611903790,4 -611903820,4 -611903850,4 -611903880,4 -611903910,1 -611903940,2 -611903970,1 -611904000,2 -611904030,2 -611904060,2 -611904090,2 -611904120,2 -611904150,2 -611904180,2 -611904210,2 -611904240,2 -611904270,2 -611904300,2 -611904330,2 -611904360,2 -611904390,2 -611904420,2 -611904450,2 -611904480,2 -611904510,2 -611904540,2 -611904570,2 -611904600,2 -611904630,2 -611904660,2 -611904690,2 -611904720,2 -611904750,2 -611904780,2 -611904810,2 -611904840,2 -611904870,2 -611904900,2 -611904930,2 -611904960,2 -611904990,2 -611905020,2 -611905050,2 -611905080,2 -611905110,2 -611905140,3 -611905170,3 -611905200,3 -611905230,2 -611905260,3 -611905290,3 -611905320,3 -611905350,3 -611905380,3 -611905410,3 -611905440,3 -611905470,3 -611905500,3 -611905530,3 -611905560,3 -611905590,3 -611905620,3 -611905650,2 -611905680,2 -611905710,2 -611905740,2 -611905770,2 -611905800,2 -611905830,2 -611905860,2 -611905890,2 -611905920,2 -611905950,2 -611905980,2 -611906010,2 -611906040,2 -611906070,1 -611906100,2 -611906130,2 -611906160,2 -611906190,2 -611906220,2 -611906250,2 -611906280,2 -611906310,2 -611906340,2 -611906370,2 -611906400,2 -611906430,2 -611906460,2 -611906490,2 -611906520,0 -611906550,0 -611906580,0 -611906610,0 -611906640,0 -611906670,0 -611906700,0 -611906730,0 -611906760,0 -611906790,0 -611906820,0 -611906850,0 -611906880,0 -611906910,0 -611906940,0 -611906970,0 -611907000,1 -611907030,2 -611907060,2 -611907090,2 -611907120,2 -611907150,2 -611907180,2 -611907210,2 -611907240,2 -611907270,2 -611907300,2 -611907330,2 -611907360,2 -611907390,2 -611907420,2 -611907450,2 -611907480,2 -611907510,2 -611907540,2 -611907570,2 -611907600,2 -611907630,2 -611907660,2 -611907690,2 -611907720,2 -611907750,2 -611907780,2 -611907810,2 -611907840,2 -611907870,2 -611907900,2 -611907930,2 -611907960,2 -611907990,2 -611908020,2 -611908050,2 -611908080,2 -611908110,2 -611908140,2 -611908170,2 -611908200,2 -611908230,2 -611908260,2 -611908290,2 -611908320,2 -611908350,2 -611908380,2 -611908410,2 -611908440,2 -611908470,2 -611908500,2 -611908530,2 -611908560,2 -611908590,2 -611908620,2 -611908650,2 -611908680,2 -611908710,2 -611908740,2 -611908770,2 -611908800,2 -611908830,2 -611908860,2 -611908890,2 -611908920,2 -611908950,0 -611908980,1 -611909010,2 -611909040,2 -611909070,2 -611909100,0 -611909130,0 -611909160,1 -611909190,2 -611909220,2 -611909250,2 -611909280,2 -611909310,2 -611909340,2 -611909370,2 -611909400,2 -611909430,2 -611909460,2 -611909490,2 -611909520,2 -611909550,2 -611909580,2 -611909610,2 -611909640,4 -611909670,4 -611909700,4 -611909730,4 -611909760,4 -611909790,4 -611909820,4 -611909850,4 -611909880,4 -611909910,4 -611909940,4 -611909970,4 -611910000,4 -611910030,4 -611910060,4 -611910090,4 -611910120,4 -611910150,4 -611910180,4 -611910210,4 -611910240,4 -611910270,4 -611910300,4 -611910330,4 -611910360,4 -611910390,4 -611910420,4 -611910450,4 -611910480,4 -611910510,4 -611910540,4 -611910570,4 -611910600,4 -611910630,4 -611910660,4 -611910690,4 -611910720,4 -611910750,4 -611910780,4 -611910810,4 -611910840,4 -611910870,4 -611910900,4 -611910930,4 -611910960,4 -611910990,4 -611911020,4 -611911050,4 -611911080,4 -611911110,4 -611911140,4 -611911170,4 -611911200,4 -611911230,4 -611911260,4 -611911290,4 -611911320,4 -611911350,4 -611911380,4 -611911410,2 -611911440,2 -611911470,2 -611911500,2 -611911530,2 -611911560,2 -611911590,2 -611911620,2 -611911650,2 -611911680,2 -611911710,2 -611911740,2 -611911770,2 -611911800,2 -611911830,2 -611911860,2 -611911890,2 -611911920,2 -611911950,2 -611911980,2 -611912010,2 -611912040,2 -611912070,2 -611912100,2 -611912130,2 -611912160,2 -611912190,2 -611912220,2 -611912250,2 -611912280,2 -611912310,2 -611912340,2 -611912370,3 -611912400,3 -611912430,2 -611912460,2 -611912490,2 -611912520,2 -611912550,2 -611912580,2 -611912610,2 -611912640,2 -611912670,2 -611912700,2 -611912730,2 -611912760,2 -611912790,2 -611912820,2 -611912850,2 -611912880,2 -611912910,2 -611912940,2 -611912970,2 -611913000,2 -611913030,2 -611913060,2 -611913090,3 -611913120,2 -611913150,3 -611913180,2 -611913210,3 -611913240,3 -611913270,3 -611913300,3 -611913330,3 -611913360,2 -611913390,2 -611913420,2 -611913450,1 -611913480,2 -611913510,2 -611913540,2 -611913570,2 -611913600,2 -611913630,2 -611913660,2 -611913690,2 -611913720,2 -611913750,2 -611913780,2 -611913810,2 -611913840,2 -611913870,2 -611913900,2 -611913930,2 -611913960,2 -611913990,3 -611914020,2 -611914050,3 -611914080,2 -611914110,3 -611914140,3 -611914170,3 -611914200,3 -611914230,3 -611914260,3 -611914290,3 -611914320,3 -611914350,3 -611914380,3 -611914410,3 -611914440,3 -611914470,3 -611914500,3 -611914530,3 -611914560,3 -611914590,3 -611914620,3 -611914650,3 -611914680,3 -611914710,3 -611914740,3 -611914770,3 -611914800,3 -611914830,3 -611914860,3 -611914890,3 -611914920,3 -611914950,3 -611914980,3 -611915010,3 -611915040,3 -611915070,3 -611915100,3 -611915130,3 -611915160,3 -611915190,0 -611915220,0 -611915250,0 -611915280,0 -611915310,0 -611915340,1 -611915370,1 -611915400,2 -611915430,2 -611915460,2 -611915490,2 -611915520,2 -611915550,1 -611915580,2 -611915610,2 -611915640,1 -611915670,1 -611915700,2 -611915730,2 -611915760,2 -611915790,2 -611915820,4 -611915850,4 -611915880,4 -611915910,4 -611915940,4 -611915970,4 -611916000,4 -611916030,4 -611916060,4 -611916090,4 -611916120,4 -611916150,4 -611916180,4 -611916210,4 -611916240,4 -611916270,4 -611916300,4 -611916330,4 -611916360,4 -611916390,4 -611916420,4 -611916450,4 -611916480,4 -611916510,4 -611916540,4 -611916570,4 -611916600,4 -611916630,4 -611916660,4 -611916690,4 -611916720,4 -611916750,4 -611916780,4 -611916810,4 -611916840,4 -611916870,4 -611916900,4 -611916930,4 -611916960,4 -611916990,4 -611917020,4 -611917050,4 -611917080,4 -611917110,4 -611917140,4 -611917170,4 -611917200,4 -611917230,4 -611917260,4 -611917290,4 -611917320,2 -611917350,2 -611917380,2 -611917410,2 -611917440,2 -611917470,2 -611917500,2 -611917530,2 -611917560,2 -611917590,2 -611917620,2 -611917650,2 -611917680,2 -611917710,2 -611917740,2 -611917770,2 -611917800,2 -611917830,2 -611917860,2 -611917890,2 -611917920,2 -611917950,2 -611917980,2 -611918010,2 -611918040,2 -611918070,2 -611918100,2 -611918130,2 -611918160,2 -611918190,2 -611918220,2 -611918250,2 -611918280,2 -611918310,2 -611918340,2 -611918370,2 -611918400,2 -611918430,2 -611918460,2 -611918490,2 -611918520,2 -611918550,0 -611918580,0 -611918610,0 -611918640,0 -611918670,0 -611918700,0 -611918730,1 -611918760,1 -611918790,1 -611918820,0 -611918850,0 -611918880,1 -611918910,1 -611918940,0 -611918970,0 -611919000,1 -611919030,2 -611919060,2 -611919090,2 -611919120,2 -611919150,2 -611919180,2 -611919210,2 -611919240,2 -611919270,2 -611919300,2 -611919330,2 -611919360,2 -611919390,2 -611919420,1 -611919450,1 -611919480,2 -611919510,2 -611919540,2 -611919570,2 -611919600,2 -611919630,2 -611919660,2 -611919690,2 -611919720,2 -611919750,2 -611919780,2 -611919810,2 -611919840,2 -611919870,2 -611919900,2 -611919930,2 -611919960,2 -611919990,2 -611920020,2 -611920050,2 -611920080,2 -611920110,2 -611920140,2 -611920170,2 -611920200,2 -611920230,2 -611920260,2 -611920290,2 -611920320,2 -611920350,2 -611920380,2 -611920410,2 -611920440,3 -611920470,2 -611920500,3 -611920530,3 -611920560,3 -611920590,3 -611920620,3 -611920650,0 -611920680,0 -611920710,1 -611920740,0 -611920770,1 -611920800,2 -611920830,2 -611920860,2 -611920890,2 -611920920,2 -611920950,2 -611920980,1 -611921010,2 -611921040,4 -611921070,4 -611921100,4 -611921130,4 -611921160,4 -611921190,4 -611921220,4 -611921250,4 -611921280,4 -611921310,4 -611921340,4 -611921370,4 -611921400,4 -611921430,4 -611921460,4 -611921490,4 -611921520,4 -611921550,4 -611921580,4 -611921610,4 -611921640,4 -611921670,4 -611921700,4 -611921730,4 -611921760,4 -611921790,4 -611921820,4 -611921850,4 -611921880,4 -611921910,4 -611921940,4 -611921970,4 -611922000,4 -611922030,4 -611922060,4 -611922090,4 -611922120,4 -611922150,4 -611922180,4 -611922210,4 -611922240,4 -611922270,4 -611922300,4 -611922330,4 -611922360,4 -611922390,4 -611922420,4 -611922450,4 -611922480,4 -611922510,4 -611922540,4 -611922570,4 -611922600,4 -611922630,4 -611922660,4 -611922690,4 -611922720,4 -611922750,4 -611922780,4 -611922810,4 -611922840,4 -611922870,4 -611922900,4 -611922930,4 -611922960,4 -611922990,4 -611923020,4 -611923050,4 -611923080,4 -611923110,4 -611923140,4 -611923170,4 -611923200,4 -611923230,4 -611923260,4 -611923290,2 -611923320,2 -611923350,0 -611923380,0 -611923410,0 -611923440,0 -611923470,0 -611923500,0 -611923530,0 -611923560,0 -611923590,0 -611923620,0 -611923650,0 -611923680,1 -611923710,2 -611923740,2 -611923770,1 -611923800,2 -611923830,2 -611923860,2 -611923890,2 -611923920,2 -611923950,2 -611923980,2 -611924010,2 -611924040,2 -611924070,2 -611924100,2 -611924130,2 -611924160,2 -611924190,2 -611924220,2 -611924250,2 -611924280,1 -611924310,1 -611924340,2 -611924370,2 -611924400,2 -611924430,2 -611924460,2 -611924490,2 -611924520,2 -611924550,2 -611924580,2 -611924610,2 -611924640,2 -611924670,2 -611924700,2 -611924730,2 -611924760,2 -611924790,2 -611924820,2 -611924850,2 -611924880,1 -611924910,2 -611924940,2 -611924970,1 -611925000,1 -611925030,2 -611925060,2 -611925090,2 -611925120,0 -611925150,0 -611925180,1 -611925210,0 -611925240,1 -611925270,2 -611925300,2 -611925330,1 -611925360,2 -611925390,0 -611925420,1 -611925450,4 -611925480,4 -611925510,4 -611925540,4 -611925570,4 -611925600,4 -611925630,4 -611925660,4 -611925690,0 -611925720,4 -611925750,4 -611925780,4 -611925810,1 -611925840,1 -611925870,1 -611925900,1 -611925930,1 -611925960,2 -611925990,1 -611926020,0 -611926050,1 -611926080,2 -611926110,1 -611926140,1 -611926170,0 -611926200,1 -611926230,4 -611926260,4 -611926290,4 -611926320,4 -611926350,4 -611926380,4 -611926410,4 -611926440,4 -611926470,4 -611926500,4 -611926530,4 -611926560,4 -611926590,4 -611926620,4 -611926650,4 -611926680,4 -611926710,4 -611926740,4 -611926770,4 -611926800,4 -611926830,4 -611926860,4 -611926890,4 -611926920,4 -611926950,4 -611926980,4 -611927010,4 -611927040,4 -611927070,4 -611927100,4 -611927130,4 -611927160,4 -611927190,4 -611927220,0 -611927250,4 -611927280,4 -611927310,4 -611927340,0 -611927370,0 -611927400,0 -611927430,0 -611927460,0 -611927490,0 -611927520,0 -611927550,0 -611927580,0 -611927610,0 -611927640,0 -611927670,0 -611927700,0 -611927730,0 -611927760,0 -611927790,0 -611927820,0 -611927850,0 -611927880,0 -611927910,0 -611927940,0 -611927970,0 -611928000,0 -611928030,0 -611928060,0 -611928090,0 -611928120,0 -611928150,0 -611928180,0 -611928210,0 -611928240,0 -611928270,0 -611928300,0 -611928330,0 -611928360,0 -611928390,0 -611928420,0 -611928450,0 -611928480,0 -611928510,0 -611928540,0 -611928570,0 -611928600,0 -611928630,0 -611928660,0 -611928690,0 -611928720,0 -611928750,0 -611928780,0 -611928810,0 -611928840,0 -611928870,0 -611928900,0 -611928930,0 -611928960,0 -611928990,0 -611929020,0 diff --git a/polydodo/src/components/d3component.js b/polydodo/src/components/d3component.js index 2e740cea..c8855a95 100644 --- a/polydodo/src/components/d3component.js +++ b/polydodo/src/components/d3component.js @@ -1,9 +1,17 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef } from "react"; +import PropTypes from "prop-types"; -const D3Component = React.memo(({ callback }) => { +const D3Component = React.memo(({ callback, data }) => { const ref = useRef(); - useEffect(() => callback(ref.current)); + useEffect(() => { + callback(ref.current, data); + }); return ; }); +D3Component.propTypes = { + callback: PropTypes.func.isRequired, + data: PropTypes.any.isRequired, +}; + export default D3Component; diff --git a/polydodo/src/d3/bar_chart/barChart.js b/polydodo/src/d3/bar_chart/barChart.js index 5d655530..07a46c7f 100644 --- a/polydodo/src/d3/bar_chart/barChart.js +++ b/polydodo/src/d3/bar_chart/barChart.js @@ -1,12 +1,12 @@ -import * as d3 from 'd3'; -import initializeBarChart from './initBarChart'; -import { CANVAS_WIDTH, CANVAS_HEIGHT, HEIGHT } from './constants'; +import * as d3 from "d3"; +import initializeBarChart from "./initBarChart"; +import { CANVAS_WIDTH, CANVAS_HEIGHT } from "./constants"; -const createBarChart = async (containerNode) => { +const createBarChart = async (containerNode, data) => { const svg = d3.select(containerNode); svg.attr('width', CANVAS_WIDTH).attr('height', CANVAS_HEIGHT); - await initializeBarChart(svg, HEIGHT); + await initializeBarChart(svg, data); }; export default createBarChart; diff --git a/polydodo/src/d3/bar_chart/initBarChart.js b/polydodo/src/d3/bar_chart/initBarChart.js index 53300aa7..bf59a5be 100644 --- a/polydodo/src/d3/bar_chart/initBarChart.js +++ b/polydodo/src/d3/bar_chart/initBarChart.js @@ -1,18 +1,31 @@ -import * as d3 from 'd3'; -import tip from 'd3-tip'; -import _ from 'lodash'; - -import barChartData from 'assets/data/hypnogram.csv'; -import { createColorScale, domainX, domainY, convertSource, createSources, calculateStagesPortion, findFirstStageIndex } from './preproc'; -import { barLegend } from './legend'; -import { createStackedBarChart, getToolTipText, getStackedToolTipText } from './stages-charts'; -import { addTransitions } from './transition'; -import { STATES_ORDERED, WIDTH, MARGIN } from './constants'; -import { STATES } from '../constants'; - -const initializeScales = (height) => { +import * as d3 from "d3"; +import tip from "d3-tip"; +import _ from "lodash"; + +import { + createColorScale, + domainX, + domainY, + convertSource, + createSources, + calculateStagesPortion, + findFirstStageIndex, +} from "./preproc"; +import { barLegend } from "./legend"; +import { + createStackedBarChart, + getToolTipText, + getStackedToolTipText, +} from "./stages-charts"; +import { addTransitions } from "./transition"; +import { STATES_ORDERED, WIDTH, HEIGHT, MARGIN } from "./constants"; +import { STATES } from "../constants"; + +const initializeScales = () => { const x = d3.scaleTime().range([0, WIDTH]); - const y = d3.scaleOrdinal().range(_.range(0, height + 1, height / STATES.length)); + const y = d3 + .scaleOrdinal() + .range(_.range(0, HEIGHT + 1, HEIGHT / STATES.length)); return { x, y }; }; @@ -28,14 +41,15 @@ const createDrawingGroup = (svg, { LEFT, TOP }) => { return svg.append('g').attr('transform', `translate(${LEFT}, ${TOP})`); }; -const initializeBarChart = async (svg, height, useTransitions = true) => { - const barHeight = Math.round(useTransitions ? height / STATES.length : height); +const initializeBarChart = async (svg, data, useTransitions = true) => { + const barHeight = Math.round( + useTransitions ? HEIGHT / STATES.length : HEIGHT + ); - const { x, y } = initializeScales(height); + const { x, y } = initializeScales(); const { xAxis, yAxis } = initializeAxes(x, y); const gBarChart = createDrawingGroup(svg, MARGIN); - const data = await d3.csv(barChartData); var totalTimeStamp = data.length; var tooltip = tip().attr('class', 'd3-tip').offset([-10, 0]); diff --git a/polydodo/src/d3/hypnogram/hypnogram.js b/polydodo/src/d3/hypnogram/hypnogram.js index e0a031df..7e624f6b 100644 --- a/polydodo/src/d3/hypnogram/hypnogram.js +++ b/polydodo/src/d3/hypnogram/hypnogram.js @@ -1,16 +1,23 @@ -import * as d3 from 'd3'; -import _ from 'lodash'; - -import hypnogramDataSleepEDF from 'assets/data/hypnogram.csv'; -import hypnogramDataPredicted from 'assets/data/hypnogram-predicted.csv'; -import hypnogramDataElectrophysiologist from 'assets/data/hypnogram-electrophysiologist.csv'; -import hypnogramDataOpenBCIElectrophysiologist from 'assets/data/hypnogram-openbci-electrophysiologist.csv'; -import hypnogramDataPredictedOpenBCI from 'assets/data/hypnogram-openbci-predicted.csv'; - -import { parseTimestampToDate, convertValuesToLabels, convertSources, domainX, domainY, domainColor } from './preproc'; -import { createLine, createHypnogramChart, createAxes, createTitle, createLegend } from './line-charts'; -import { createMouseOver } from './mouse-over'; -import { STATES } from '../constants'; +import * as d3 from "d3"; +import _ from "lodash"; + +import { + parseTimestampToDate, + convertValuesToLabels, + convertSources, + domainX, + domainY, + domainColor, +} from "./preproc"; +import { + createLine, + createHypnogramChart, + createAxes, + createTitle, + createLegend, +} from "./line-charts"; +import { createMouseOver } from "./mouse-over"; +import { STATES } from "../constants"; const initializeScales = ({ width, height }) => { const x = d3.scaleTime().range([0, width]); @@ -56,42 +63,40 @@ const createHypnogram = (containerNode, data, chartTitle, hypnogramNames, compar const g = createDrawingGroup(svg, dimensions, margin); const line = createLine(x, y); - Promise.all(data.map((hypnoData) => d3.csv(hypnoData))).then((data) => { - parseTimestampToDate(data); - convertValuesToLabels(data); - data = convertSources(data, hypnogramNames); - - domainX(x, data); - domainY(y, sleepLabels); - const colorDomain = domainColor(data, comparativeColors); - - const g_chart = createHypnogramChart(g, data, line, colorDomain); - createMouseOver(g_chart, x, y, data, margin, dimensions, colorDomain); - createAxes(g, xAxis, yAxis, dimensions, margin); - createTitle(g, chartTitle, dimensions, margin); - createLegend(g, hypnogramNames, comparativeColors, dimensions, margin); - }); -}; + parseTimestampToDate(data); + convertValuesToLabels(data); + data = convertSources(data, hypnogramNames); -export const createSingleHypnogram = (containerNode) => { - const data = [hypnogramDataSleepEDF]; - const chartTitle = 'Hypnogram'; - const hypnogramNames = ['Classifier']; - const comparativeColors = ['#006aff']; + domainX(x, data); + domainY(y, sleepLabels); + const colorDomain = domainColor(data, comparativeColors); - createHypnogram(containerNode, data, chartTitle, hypnogramNames, comparativeColors); + const g_chart = createHypnogramChart(g, data, line, colorDomain); + createMouseOver(g_chart, x, y, data, margin, dimensions, colorDomain); + createAxes(g, xAxis, yAxis, dimensions, margin); + createTitle(g, chartTitle, dimensions, margin); + createLegend(g, hypnogramNames, comparativeColors, dimensions, margin); }; -export const createComparativeHypnogram = (containerNode, hypnogramNames) => { - let data = []; - if (_.isEqual(hypnogramNames, ['Classifier', 'Sleep-EDF'])) { - data = [hypnogramDataPredicted, hypnogramDataSleepEDF]; - } else if (_.isEqual(hypnogramNames, ['Classifier', 'Electrophysiologist'])) { - data = [hypnogramDataPredictedOpenBCI, hypnogramDataOpenBCIElectrophysiologist]; - } else if (_.isEqual(hypnogramNames, ['Electrophysiologist', 'Sleep-EDF'])) { - data = [hypnogramDataElectrophysiologist, hypnogramDataSleepEDF]; - } +export const createSingleHypnogram = (containerNode, data) => { + const chartTitle = "Hypnogram"; + const hypnogramNames = ["Classifier"]; + const comparativeColors = ["#006aff"]; + + createHypnogram( + containerNode, + data, + chartTitle, + hypnogramNames, + comparativeColors + ); +}; +export const createComparativeHypnogram = ( + containerNode, + data, + hypnogramNames +) => { const chartTitle = `Agreement between ${hypnogramNames[0]} and ${hypnogramNames[1]}`; const colors = { Classifier: '#efce31', diff --git a/polydodo/src/d3/spectrogram/spectrogram.js b/polydodo/src/d3/spectrogram/spectrogram.js index 875031ad..b342dbe9 100644 --- a/polydodo/src/d3/spectrogram/spectrogram.js +++ b/polydodo/src/d3/spectrogram/spectrogram.js @@ -2,7 +2,7 @@ import * as d3 from 'd3'; import { initSpectrogram } from './initSpectrogram'; import initializeBarChart from '../bar_chart/initBarChart'; -const createSpectrogram = (containerNode) => { +const createSpectrogram = (containerNode, data) => { const margin = { top: 100, right: 200, @@ -37,9 +37,9 @@ const createSpectrogram = (containerNode) => { .attr('width', canvasWidth) .attr('height', spectroCanvasHeight); - initializeBarChart(barChart, barHeight, false); - initSpectrogram(spectrogramFPZ, 'Fpz_Cz', width, spectroHeight, margin); - initSpectrogram(spectrogramPZ, 'Pz_Oz', width, spectroHeight, margin); + initializeBarChart(barChart, data, false); + initSpectrogram(spectrogramFPZ, "Fpz_Cz", width, spectroHeight, margin); + initSpectrogram(spectrogramPZ, "Pz_Oz", width, spectroHeight, margin); }; export default createSpectrogram; diff --git a/polydodo/src/hooks/api_hooks.js b/polydodo/src/hooks/api_hooks.js new file mode 100644 index 00000000..17fe2de9 --- /dev/null +++ b/polydodo/src/hooks/api_hooks.js @@ -0,0 +1,13 @@ +import { useEffect, useState } from "react"; +import { csv } from "d3"; + +export const useCSVData = (path) => { + const [data, setData] = useState(null); + useEffect(() => { + (async () => { + const receivedData = await csv(path); + setData(receivedData); + })(); + }, [path]); + return data; +}; diff --git a/polydodo/src/views/performance/performance.js b/polydodo/src/views/performance/performance.js index fc4b1ebb..acddce8a 100644 --- a/polydodo/src/views/performance/performance.js +++ b/polydodo/src/views/performance/performance.js @@ -7,38 +7,53 @@ import WIPWarning from '../../components/wip_warning'; import Footer from '../../components/footer/footer'; import D3Component from '../../components/d3component'; -import text from './text.json'; -import { createComparativeHypnogram } from 'd3/hypnogram/hypnogram'; +import text from "./text.json"; +import { createComparativeHypnogram } from "d3/hypnogram/hypnogram"; +import { useCSVData } from "../../hooks/api_hooks"; -const ClassificationReport = ({ rows }) => { - return ( - - - - - - - - - - - - {rows.map((row, i) => { - return ( - - - {row.slice(1).map((el, j) => ( - - ))} - - ); - })} - -
Precision (%)Recall (%)F1-Score (%)Support
{row[0]}{el}
- ); -}; +import hypnogramDataSleepEDF from "assets/data/hypnogram.csv"; +import hypnogramDataPredicted from "assets/data/hypnogram-predicted.csv"; +import hypnogramDataElectrophysiologist from "assets/data/hypnogram-electrophysiologist.csv"; +import hypnogramDataOpenBCIElectrophysiologist from "assets/data/hypnogram-openbci-electrophysiologist.csv"; +import hypnogramDataPredictedOpenBCI from "assets/data/hypnogram-openbci-predicted.csv"; + +const ClassificationReport = ({ rows }) => ( + + + + + + + + + + + + {rows.map((row, i) => { + return ( + + + {row.slice(1).map((el, j) => ( + + ))} + + ); + })} + +
Precision (%)Recall (%)F1-Score (%)Support
{row[0]}{el}
+); const Performance = () => { + const csvDataSleepEDF = useCSVData(hypnogramDataSleepEDF); + const csvDataPredicted = useCSVData(hypnogramDataPredicted); + const csvDataElectrophysiologist = useCSVData( + hypnogramDataElectrophysiologist + ); + const csvDataOpenBCIElectrophysiologist = useCSVData( + hypnogramDataOpenBCIElectrophysiologist + ); + const csvDataPredictedOpenBCI = useCSVData(hypnogramDataPredictedOpenBCI); + return (
@@ -78,39 +93,74 @@ const Performance = () => {

Classifier's accuracy according to Sleep-EDF

- createComparativeHypnogram(svg, ['Classifier', 'Sleep-EDF'])} /> + {csvDataPredicted && csvDataSleepEDF ? ( + + createComparativeHypnogram(svg, data, ["Classifier", "Sleep-EDF"]) + } + data={[csvDataPredicted, csvDataSleepEDF]} + /> + ) : ( + "..." + )} -

Classifier's accuracy according to the electrophysiologist

- createComparativeHypnogram(svg, ['Classifier', 'Electrophysiologist'])} /> +

+ Classifier's accuracy according to the electrophysiologist +

+ {csvDataPredictedOpenBCI && csvDataOpenBCIElectrophysiologist ? ( + + createComparativeHypnogram(svg, data, [ + "Classifier", + "Electrophysiologist", + ]) + } + data={[csvDataPredictedOpenBCI, csvDataOpenBCIElectrophysiologist]} + /> + ) : ( + "..." + )}

Electrophysiologist and Sleep-EDF's agreement

- createComparativeHypnogram(svg, ['Electrophysiologist', 'Sleep-EDF'])} /> + {csvDataElectrophysiologist && csvDataSleepEDF ? ( + + createComparativeHypnogram(svg, data, [ + "Electrophysiologist", + "Sleep-EDF", + ]) + } + data={[csvDataElectrophysiologist, csvDataSleepEDF]} + /> + ) : ( + "..." + )} diff --git a/polydodo/src/views/sleep_analysis/sleep_analysis.js b/polydodo/src/views/sleep_analysis/sleep_analysis.js index 749a46d0..3d55ad75 100644 --- a/polydodo/src/views/sleep_analysis/sleep_analysis.js +++ b/polydodo/src/views/sleep_analysis/sleep_analysis.js @@ -1,6 +1,6 @@ -import React from 'react'; -import { Container, Row, Button } from 'reactstrap'; -import { Link } from 'react-router-dom'; +import React from "react"; +import { Container, Row, Button } from "reactstrap"; +import { Link } from "react-router-dom"; import Navbar from '../../components/navbar/navbar'; import Header from '../../components/header'; @@ -10,11 +10,16 @@ import WIPWarning from '../../components/wip_warning'; import { createSingleHypnogram } from '../../d3/hypnogram/hypnogram'; -import text from './text.json'; -import createSpectrogram from '../../d3/spectrogram/spectrogram'; -import StackedBarChartScrollyTelling from './stacked_bar_chart_scrollytelling'; +import text from "./text.json"; +import createSpectrogram from "../../d3/spectrogram/spectrogram"; +import StackedBarChartScrollyTelling from "./stacked_bar_chart_scrollytelling"; +import { useCSVData } from "../../hooks/api_hooks"; + +import hypnogramDataSleepEDF from "assets/data/hypnogram.csv"; const SleepAnalysis = () => { + const csvDataSleepEDF = useCSVData(hypnogramDataSleepEDF); + return (
@@ -30,85 +35,138 @@ const SleepAnalysis = () => {

- Of course, we are analyzing only one night of sleep so it is therefore tricky to draw general conclusions about your sleep. It is however + Of course, we are analyzing only one night of sleep so it is therefore + tricky to draw general conclusions about your sleep. It is however fascinating to see how your night was.

Without further ado, this is what was your night of sleep:

- We have seen that sleep can be decomposed in mainly two stages, whereas REM and NREM, and that we can observe different stage proportions - across age, gender and different sleep disorders. We’ve also defined other measures of your sleep architecture, such as your sleep latency, - efficiency and total sleep time. In order to improve your sleep hygiene, many elements can be considered: + We have seen that sleep can be decomposed in mainly two stages, + whereas REM and NREM, and that we can observe different stage + proportions across age, gender and different sleep disorders. We’ve + also defined other measures of your sleep architecture, such as your + sleep latency, efficiency and total sleep time. In order to improve + your sleep hygiene, many elements can be considered:

  • - Alimentation: having a balanced diet and avoiding sources of caffeine can have a positive impact on one’s sleep. Chocolate, soft drink, - tea and decaffeinated coffee are unexpected sources of caffeine. + Alimentation: having a balanced diet and avoiding sources of + caffeine can have a positive impact on one’s sleep. Chocolate, soft + drink, tea and decaffeinated coffee are unexpected sources of + caffeine. +
  • +
  • + Routine: going to sleep about at the same time, in a darkened and + quiet environment.
  • Routine: going to sleep about at the same time, in a darkened and quiet environment.

- Although we’ve looked at many aspects of your night’s sleep, we haven’t properly looked at your sleep dynamics, whereas how your sleep + Although we’ve looked at many aspects of your night’s sleep, we + haven’t properly looked at your sleep dynamics, whereas how your sleep evolves overnight.

Hypnogram

- A hypnogram allows you to visually inspect the evolution of your night, through time. The vertical axis represents how hard it is to wake - up, namely the sleep deepness. We see that REM is one of the lightest sleep stages (along with N1), because we unknowingly wake up from that - stage. Those short periods of arousal often last no longer than 15 seconds, are followed by a lighter sleep stage, and cannot be remembered - the next morning. If they are too frequent, they can affect your sleep quality. [5] We can see that, throughout the night, stages follow - about the same pattern, whereas we go from NREM (either N1, N2 and N3) and then to REM, and so on. We call those sleep cycles, and those - typically range from four to six, each one lasting from 90 to 110 minutes. Another commonly looked at measurement is the time between sleep - onset and the first REM epoch, namely REM latency, which corresponds to 20 minutes. + A hypnogram allows you to visually inspect the evolution of your + night, through time. The vertical axis represents how hard it is to + wake up, namely the sleep deepness. We see that REM is one of the + lightest sleep stages (along with N1), because we unknowingly wake up + from that stage. Those short periods of arousal often last no longer + than 15 seconds, are followed by a lighter sleep stage, and cannot be + remembered the next morning. If they are too frequent, they can affect + your sleep quality. [5] We can see that, throughout the night, stages + follow about the same pattern, whereas we go from NREM (either N1, N2 + and N3) and then to REM, and so on. We call those sleep cycles, and + those typically range from four to six, each one lasting from 90 to + 110 minutes. Another commonly looked at measurement is the time + between sleep onset and the first REM epoch, namely REM latency, which + corresponds to 20 minutes.

- + {csvDataSleepEDF ? ( + + ) : ( + "..." + )}

- Sleep cycles take place in a broader process, named the circadian rhythm. It is the one that regulates our wake and sleep cycles over a 24 - hours period. + Sleep cycles take place in a broader process, named the circadian + rhythm. It is the one that regulates our wake and sleep cycles over a + 24 hours period.

- You’ve been able to visualize and inspect your night of sleep, which we’ve classified only based on your EEG recordings. In a sleep lab, - electrophysiology technicians generally look at your EEG, EOG and submental EMG, and then manually classify each epoch of 30 seconds that - compose your night. By looking at your EEG recordings, we can see some patterns that can help electrophysiology technicians, and our + You’ve been able to visualize and inspect your night of sleep, which + we’ve classified only based on your EEG recordings. In a sleep lab, + electrophysiology technicians generally look at your EEG, EOG and + submental EMG, and then manually classify each epoch of 30 seconds + that compose your night. By looking at your EEG recordings, we can see + some patterns that can help electrophysiology technicians, and our classifier, discriminate sleep stages throughout the night.

Spectrogram

- Above, we can see the same chart from the first visualization, which represents your sleep stages through the night. Below it, there are - spectrograms of both your EEG channels. Spectrograms can be viewed as if we took all of your nights signal, we’ve separated it in contiguous - 30 seconds chunks, stacked then horizontally and to which we’ve applied the fast fourier transform. We then have, for each 30 seconds epoch, - the corresponding amplitudes for each frequency that makes up the signal, hence the spectra. We then converted the scale to logarithmic, to - better see the differences in the spectrums. We then speak of signal power instead of signal amplitude, because we look at the spectrums in - a logarithmic scale. + Above, we can see the same chart from the first visualization, which + represents your sleep stages through the night. Below it, there are + spectrograms of both your EEG channels. Spectrograms can be viewed as + if we took all of your nights signal, we’ve separated it in contiguous + 30 seconds chunks, stacked then horizontally and to which we’ve + applied the fast fourier transform. We then have, for each 30 seconds + epoch, the corresponding amplitudes for each frequency that makes up + the signal, hence the spectra. We then converted the scale to + logarithmic, to better see the differences in the spectrums. We then + speak of signal power instead of signal amplitude, because we look at + the spectrums in a logarithmic scale.

How to read it?

- Red therefore means that in that 30 seconds time frame, that particular frequency had a big amplitude. Green means that you had that - frequency with a lower amplitude. Dark blue means that you didn’t have that frequency in the signal. + Red therefore means that in that 30 seconds time frame, that + particular frequency had a big amplitude. Green means that you had + that frequency with a lower amplitude. Dark blue means that you didn’t + have that frequency in the signal.

- To get a better understanding at how spectrograms work, you can check out - - {' '} - this visualization{' '} + To get a better understanding at how spectrograms work, you can check + out + + {" "} + this visualization{" "} that decomposes sound frequency from your microphone.

- + {csvDataSleepEDF ? ( + + ) : ( + "..." + )}

- Generally, when talking about brain waves, we group certain frequencies together into bands. There are overall five frequency bands, where - each has a general associated behaviour, or state of mind. We will cover those when looking at time frames corresponding to each sleep - stage. + Generally, when talking about brain waves, we group certain + frequencies together into bands. There are overall five frequency + bands, where each has a general associated behaviour, or state of + mind. We will cover those when looking at time frames corresponding to + each sleep stage.

- We can associate wake stages with low-amplitude activity in the 15 to 60 Hz frequency range, called the beta band. By slowly falling asleep, - the signal frequencies tend to decrease into the 4 to 8 Hz range, or the theta band, and to have larger amplitudes. These characteristics - are associated with N1. N2 stage has the same characteristics, and also includes sleep spindles. They last only a few seconds and are a - large oscillation in the 10 to 15 hz band. Because they do not occur during all of the 30 seconds period, they cannot be seen here. Stage - N3, also called slow wave sleep, is characterized by slower waves between 0.5 and 4 Hz, known as the delta range, with large amplitudes. REM - stage has the same characteristics as Wake stage, whereas there are low voltage high frequency activity. + We can associate wake stages with low-amplitude activity in the 15 to + 60 Hz frequency range, called the beta band. By slowly falling asleep, + the signal frequencies tend to decrease into the 4 to 8 Hz range, or + the theta band, and to have larger amplitudes. These characteristics + are associated with N1. N2 stage has the same characteristics, and + also includes sleep spindles. They last only a few seconds and are a + large oscillation in the 10 to 15 hz band. Because they do not occur + during all of the 30 seconds period, they cannot be seen here. Stage + N3, also called slow wave sleep, is characterized by slower waves + between 0.5 and 4 Hz, known as the delta range, with large amplitudes.{" "} + REM stage has the same characteristics as Wake stage, whereas there + are low voltage high frequency activity.

Wanna know how accurate this data is?