javascriptchart.jsmarkdowndataviewobsidian

Chart.js Problem: Is there any way to convert data from a markdown table into a chart?


I am using Obsidian to take my notes, it is an application that allows writing notes in markdown format and using plugins from the community (like chrome store extensions). So I installed two plugins called Dataview (allows embedding dataviewjs code blocks) and Obsidian Chart (supports integrating Dataview to draw charts). These two plugins come together so I can use Chart.js like this:

test:: First Test
mark:: 6

```dataviewjs
const data = dv.current()

const chartData = {
    type: 'bar',
    data: {
        labels: [data.test],
        datasets: [{
            label: 'Grades',
            data: [data.mark],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)'
            ],
            borderWidth: 1
        }]
    }
}

window.renderChart(chartData, this.container);```

The above code block will render the following chart. Returning to the main problem, I now create a data table of sleep information as follows:

|   | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| Bedtime | 09.30 | 22 | 22.30 | 21.45 | 23 | 22 | 21 |
| Wake up | 05.45 | 06.30 | 22 | 5.30 | 5.45 | 5 | 7 |
| Sleep duration | 5 | 7 | 7.5 | 8 | 6.5 | 7 | 5 |

THANKS IN ADVANCE!!!

I'm trying to access the data cells of the rows: Bedtime, Wakeup and Sleep duration to represent them in a chart like this. That's all!


Solution

  • Well I'm no Obsidian expert, or of the plugins out there, but if you check the documentation of the "Obsidian Charts" you can see, that the basic table-chart connection works (link of the documentation). Simply name the the table ^tableName. And create the chart with:

    type: bar
    id: ^tableName
    layout: rows
    width: 80%
    beginAtZero: true
    

    This would generate this chart:
    Screenshot chart creation-plugin

    But I think for the specific chart you are after, will need some coding, since as far as I can see the plugin does support all chartjs features.

    That said, if I would have to solve this, I would use dataviewjs to create javascript, that loades the table and builds the chart.

    Here a short documented Demo, explaining how to approach this:
    (This is just a partial demo, and should be optimized)

    ```dataviewjs
    
    // Generate the labels, from the html table
    let labels = [].map.call(document.body.querySelectorAll('table.table-editor thead th'), 
        (x) => x.innerText).filter( x=> x.replace(/\n|\t|\s/gi, '') != '');
    
    // Get the table, from the html table
    let htmlTable = document.body.querySelector('table tbody')
    let rows = [].map.call(htmlTable.querySelectorAll('tr'), x => x)
    let data = '1'.repeat(2).split('').map( x => []);
    let colsLength = [].map.call(rows[0].querySelectorAll('td'), x =>  x).length;
    
    // creating the data form needed for floating bar charts: [ [start, end], ...]
    for(let cIdx = 1; cIdx < 8; cIdx++){
        data.push([])
        for(let rowIdx = 0; rowIdx < 2; rowIdx++){
            let cols = [].map.call(rows[rowIdx].querySelectorAll('td'), x =>  moment(x.innerText, 'hh:mm'));
            data[cIdx - 1].push(cols[cIdx] );
        }
    
    }
    
    // chartjs config
    let chartConfig = {
        type: 'bar',
        data: {
            labels: labels,
            datasets: [{
                label: '',
                data: data,
                borderWidth: 1
            }]
        },
       options:{
            scales: {
                y: {
                    min: moment('00:00:00', 'hh:mm'),
                    max: moment('23:59:59', 'hh:mm'),
                    ticks: {
                    stepSize: 60,
                    beginAtZero: false,
                    },
                    type: 'time',
                    time:{
                        minutes: 'hh:mm'
                    }
                }
            }
        }
    };
    
    window.renderChart(chartConfig, this.container);
    
    ```
    

    this should generate a chart like this:
    screenshot obsidian-generated Chart

    Info: to create the missing lines from your image, you would simply have to add two line dataset to the chartConfig variable, as in this official example.

    btw: while building this demo, i noticed that the plugins or Obsidian, is abit buggy, so the rendering can vary or produce errors, but a simple restart of the application/plugins, fixes sometimes the problems.