Help SleepChart dv.view

I am trying to adapt this external script code - Sono-2/Sono2 at main · lucasbcgeo/Sono-2 (github.com) - so it can fetch the values present in the notes and, depending on the number of days from START to END, it will display in x the data that are collected and calculated by the script but on a larger scale. For example:

When I create a weekly note and execute the standard code block below with the weekly range of notes to be searched, it will display a chart with Daily Rating (from 0 to 10), the time I went to bed and woke up, the amount of sleep, and the sleep rating. What I would like to do is to use this same script for monthly, quarterly, and annual notes but in X, instead of showing the data by day, show it by week or by month. For instance, in the monthly view, each x will represent 1 week. It will need to show that in week 1, I slept an average number of hours per day, went to bed on average at a certain time each day, and so on with the rest of the information. The only thing needed would be to sum up the data values and construct an average weekly/day, monthly/day, etc.

dataviewjs
const configsono = {
func: window.renderChart,
START: "2024-01-28",(here i use templater)
END: "2024-02-03", (here i use templater)
await dv.view("Dispensa/Script/Sono", configsono)

Context: Data that exists in every Daily Note within the folder Journey/Daily Notes.

const ratingData = pages.notadoDia;const 
sleepStart = pages.sleepStart;
const sleepEnd = pages.sleepEnd; 
const sleepRatingData = pages.notadoSono;

notadoDia
sleepStart
sleepEnd
notadoSono

You’re not showing the actual query doing the calculations, but in theory lets assume it looks something like the following:

```dataview
TABLE sum(rows.sleepHours), average(rows.startingToSleep), average(rows.dailyRating)
GROUP BY file.day
```

In this scenario what you would do is simply to change the GROUP BY clause, or add another clause related to not grouping by day, by week or by month.

Is too big hehe =) I wrote the repository github link with calculations. But i can write here!

This the script:

//Y - A X I S   D A T A

let pages = dv
    .pages('"Jornada/Notas Diárias"')
    .where(p => {
        
        let dateOfFile = dv.date(p.file.name);

        
        return dateOfFile >= dv.date(input.START) && dateOfFile <= dv.date(input.END);
    })
    .sort(p => p.file.name);





const ratingData = pages.notadoDia;
const sleepStart = pages.sleepStart;
const sleepEnd = pages.sleepEnd;
const sleepRatingData = pages.notadoSono;


// went to bed       /    wake-up
// HH:mm 24h



const sleepStartStop = sleepStart.values.map((value, index) => {
	return [value, sleepEnd.values[index]];
});

const sleepStartStopNumber = sleepStart.values.map((value, index) => {
    let startHours = parseInt(value.split(':')[0]);
    let startMinutes = parseInt(value.split(':')[1]);
    let endHours = parseInt(sleepEnd.values[index].split(':')[0]);
    let endMinutes = parseInt(sleepEnd.values[index].split(':')[1]);

    // Converte horas e minutos em formato decimal
    let startDecimal = startHours + startMinutes / 60;
    let endDecimal = endHours + endMinutes / 60;

    // Ajusta o horário de início se for após as 20h para refletir como valor negativo no gráfico
    if (startHours > 20) {
        startDecimal -= 24;
    }

    return [startDecimal, endDecimal];
});

// Sleep Duration 

let sleepDurationData = sleepStart.values.map((startValue, index) => {
    // Extrai horas e minutos do horário de início
    let [startHour, startMinute] = startValue.split(':').map(Number);
    let startMinutesTotal = startHour * 60 + startMinute;

    // Extrai horas e minutos do horário de fim
    let endValue = sleepEnd.values[index];
    let [endHour, endMinute] = endValue.split(':').map(Number);
    let endMinutesTotal = endHour * 60 + endMinute;

    // Ajusta para quando o sono passa da meia-noite
    if (endMinutesTotal < startMinutesTotal) {
        endMinutesTotal += 24 * 60; // Adiciona um dia (em minutos) ao momento de término
    }

    // Calcula a duração total em minutos e depois converte para horas decimais
    let durationMinutes = endMinutesTotal - startMinutesTotal;
    let durationHoursDecimal = durationMinutes / 60;

    return durationHoursDecimal; // Retorna a duração em horas decimais
});



// Label X data config
//      ->                        X                      <-


let timeDate = pages
  .map(p => {
    // Assume que p.file.name é uma string que representa uma data no formato "YYYY-MM-DD"
    // Utiliza a expressão de data para converter o nome do arquivo em uma data
    let dateOfFile = dv.date(p.file.name);

    // Verifica se a data é válida
    if (dateOfFile) {
        // Retorna um objeto que inclui tanto a data (para ordenação) quanto a representação formatada da data
        return {
            date: dateOfFile,
            formattedDate: dateOfFile.toFormat("ccc") // Formata a data como o nome do dia da semana abreviado
        };
    } else {
        return null;
    }
  })
  .filter(item => item !== null) // Filtra itens nulos (datas inválidas)
  .sort((a, b) => a.date - b.date) // Ordena as datas do mais antigo para o mais novo
  .map(item => item.formattedDate); // Mapeia os objetos para a representação formatada da data




//








// Config Chart


const chartData = {
	beginAtZero: true,

	data: {
		labels: timeDate,
		datasets: [
			{
				yAxisID: 'A',
				type: 'line',
				label: '🔟 Rate- 📅',
				data: ratingData.values,
				borderColor: ['rgb(255, 99, 132)'],
				borderWidth: 1,
				bestFit: true,
			},
			{
				yAxisID: 'A',
				type: 'line',
				label: ' ⌛ Dur -💤',
				data: sleepDurationData,
				borderColor: ['rgb(54, 162, 235)'],
				borderWidth: 1,
				bestFit: true,
			},
			{
				yAxisID: 'A',
				type: 'line',
				label: '🔟 Rt -💤',
				data: sleepRatingData.values,
				borderColor: ['rgb(255, 206, 86)'],
				borderWidth: 1,
				bestFit: true,
			},
			{
				yAxisID: 'B',
				type: 'bar',
				label: '🛌 Bed - 🕥/⏰ Wakeup- 🕝',
				data: sleepStartStopNumber,
				backgroundColor: ['rgb(153, 102, 255, 0.2)'],
				borderColor: ['rgb(153, 102, 255, 1)'],
				bestFit: true,
				borderWidth: { top: 0, bottom: 0, right: 0, left: 2 },
			},
		],
	},
	options: {
		//Explicações de options até scales abaixo //
		plugins: {
			title: {
				display: true,
				text: 'Sleep',
				font: {
                    size: 24,
                },
                padding: {
                    top: 10,
                    bottom: 30 // Ajusta o padding conforme necessário para o layout
                }
            },			  
			tooltip: {
				callbacks: {
					label: function(context) {
						if (context.dataset.label === '🛌 Bed - 🕥/⏰ Wakeup- 🕝') {
							let value = context.raw;
							const formatTime = (time) => {
								let hours = Math.floor(time);
								let minutes = Math.floor((time - hours) * 60);
								hours = hours < 0 ? 24 + hours : hours;
								return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
							};
	
							const startTime = formatTime(value[0]);
							const endTime = formatTime(value[1]);
							return `🛌 Bed - 🕥 ${startTime}\n⏰ Wakeup- 🕝 ${endTime}`;
						} 
						// Se o dataset for "Horas de sono", mostra horas e minutos literalmente
						else if (context.dataset.label === '⌛Dur -💤') {
							let totalMinutes = context.raw * 60; // Converte horas em minutos
							let hours = Math.floor(totalMinutes / 60);
							let minutes = Math.floor(totalMinutes % 60); // Usa Math.floor para evitar arredondamento
							return `${context.dataset.label}: ${hours}h ${minutes}m`;
						} 
						// 
						else {
							return `${context.dataset.label}: ${context.formattedValue}`;
						}	
					}
				}
			}
		},
		scales: {
			A: {
				type: 'linear',
				position: 'right',
				beginAtZero: true,
				min: 0,
				max: 10,
				title: {
					display: true,
					text: '🔟 📅/💤 or ⌛ - 💤', // Título para a escala 
					font: {
						size: 20 // Ajuste o tamanho da fonte conforme necessário
					}
				}
			},
			B: {
				type: 'linear',
				position: 'left',
				max: 13,
				min: -3,
				title: {
					display: true,
					text: '⌛💤 and 🕥🛌/⏰', // Título para a escala B
					font: {
						size: 20 // Ajuste o tamanho da fonte conforme necessário
					}
				},
				ticks: {
					fontSize: 40,
					count: 17,
					maxTicksLimit: 20,
					callback: function (value, index, ticks) {
						if (value < 0) {
							value = 24 + value;
						}
						let minutes = value * 60;
						let hours = Math.floor(minutes / 60);
						minutes = minutes % 60;
		
						if (minutes < 10) {
							minutes = '0' + minutes;
						}
						if (hours < 10) {
							hours = '0' + hours;
						}
		
						return hours + ':' + minutes;
					},
				},
			},
			x: {
				ticks: {
					maxRotation: 0,
					minRotation: 0,
				},
			},
		},
	},	
};


input.func(chartData, dv.container);

I see no easy way to transform that script into what you want. I’m not sure what to suggest for the way forward, but I’m thinking that my previous post could be a possible path forward.

To re-iterate, if you make a table which displays what you want to chart on a daily basis, with some simple but custom way to transform that into a chart. Which shouldn’t be too hard using any of the charting plugins, like Obsidian charts.

When you’ve got that table displaying the correct values with one row per day, it should be a simple conversion to transform that table into delivering the weekly, monthly or yearly results.

Doing this with your current setup, I’ve not got the time nor energy to even try fathoming what’s happening behind the scenes of that script. Sorry…

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.