notebook

都内でWEB系エンジニアやってます。

Obsidian Chartsでコンディションや日ごろの状態をグラフ化する

Obsidianで使えるプラグインObsidian Chartsを使って、DailyNoteで記録した体調数値などの数値データをグラフ化し、時系列で変化が分かるようにした

これによって、振り返りの際に数値の変化がわかりやすくなり「このときこういう感じだったな」というのを思い出しやすくなった

Obsidian Charts

phibr0/obsidian-charts: Charts - Obsidian Plugin | Create editable, interactive and animated Charts in Obsidian via Chart.js

github.com

Obsidian上で数値データをグラフ化して表示するプラグイン

このプラグインを使うことで、何かしらのデータをもとにObsidian上でもグラフ表示ができる

中身でグラフ化する部分に関してはChart.jsを使っているので渡すオプションの値など詳しく知りたい場合はChart.jsのドキュメントも参考にできる

Chart.js | Chart.js

www.chartjs.org

今回はこのプラグインとDataviewプラグインを組み合わせてDailyNoteで継続的に記録した数値データをグラフに変換した

なお、プラグインのインストール方法については公式読めば分かるので割愛する

Daily Noteの例

前提として、Daily Noteに以下のように記録をつけていく(必要な部分だけ抜き出している)

---
date: 2023-03-26
week: 2023-W12
score: 80
facilitate: 1
meeting: 2
---

Dataviewプラグインとの連携

Dataview Integration - Obsidian Charts

charts.phibr0.de

dataviewjswindow.renderChart(data, element);と記述することでグラフをレンダリングできる

dataには渡すデータを、elementにはthis.containerを指定する

dataの中身を変えて複数のグラフを描画することも可能

Dataviewで集計してChartsでグラフ描画

Dataviewプラグインのdataviewjsで、さまざまなページからデータを取得し集計が可能なのでごにょごにょやった結果をChartsに渡して可視化する

いきなりだが、自分が使っているコードを載せておく

1行目の日付部分に決め打ちが入ってしまっているがそれ以外は参考にはできると思う

const pages = dv.pages('#daily').filter(p => p.file.name != "daily_note" && p.file.name > "2023-01-02").sort(p => p.file.name);

function extract(pages, key) {
  return pages.map(p => p[key]).values
}

const days = pages.map(p => p.file.name).values  
const scores =  extract(pages, 'score')
const facilitates = extract(pages, 'facilitate')
const meetings = extract(pages, 'meeting')

function scoreChart(terms, data) {
  return {
    type: 'line',
    data: {
      labels: terms,  
      datasets: [{
        label: 'Mark',
        data: data,
        backgroundColor: ['rgba(99, 255, 132, 0.2)'],  
        borderColor: ['rgba(99, 255, 132, 1)'],  
        borderWidth: 1,
      tension: 0.3
      }]
    }
  }
}

function meetingChart(terms, meeting, facilitate) {
  return {
    type: 'bar',
    data: {
      labels: terms,
      datasets: [{
        label: 'meeting',
        data: meeting,
        borderColor: ['rgba(99, 132, 255, 1)'],
        backgroundColor: ['rgba(99, 132, 255, 0.7)']
      },{
        label: 'facilitate',
        data: facilitate,
        borderColor: ['rgba(255, 99, 132, 1)'],
        backgroundColor: ['rgba(255, 99, 132, 0.7)']
      }]
    }
  }
}

const dailyScore = scoreChart(days, scores)
const dailyMeeting = meetingChart(days, meetings, facilitates)

window.renderChart(dailyScore, this.container)
window.renderChart(dailyMeeting, this.container)

Dailyの推移

余談だが、自分はscore以外にもfacilitate,meetingも数値を取っている

会議数よりファシリテーションする数によってその日の疲れが違うなーと思ったので記録している

Weeklyで集計した値をグラフ化する

dailyでは取ってきた値をそのままChartsへ渡すだけで良かったがWeeklyの場合は適切な集計をしてからChartsへ渡す必要がある

雑なコードだがこちらも以下に載せておく

const pages = dv.pages('#daily').filter(p => p.file.name != "daily_note" && p.file.name > "2023-01-02").sort(p => p.file.name);

function extract(pages, key) {
  return pages.map(p => p[key]).values
}

function aggregate(pages, term, key) {
  const termValues = pages.values.reduce((acc, cur) => {
    acc[cur[term]] ||= [];
    acc[cur[term]] = [...acc[cur[term]], cur[key]]
    return acc
  }, {})
  
  const metrics = Object.keys(termValues).map(t => {
    const sum = termValues[t].reduce((a, c) => a + c);
    return {
      avg: sum / termValues[t].length,
      sum: sum
    }
  });

  return {terms: Object.keys(termValues), data: metrics};
}


function aggregateKeys(pages, term, metric, keys) {
  const metrics = keys.map(key => {
    return aggregate(pages, term, key)
  });
  const data = metrics.map(m => m.data.map(r => r[metric]));

  return [metrics[0].terms, ...data]
}

const days = pages.map(p => p.file.name).values  
const scores =  extract(pages, 'score')
const facilitates = extract(pages, 'facilitate')
const meetings = extract(pages, 'meeting')

function scoreChart(terms, data) {
  return {
    type: 'line',
    data: {
      labels: terms,  
      datasets: [{
        label: 'Mark',
        data: data,
        backgroundColor: ['rgba(99, 255, 132, 0.2)'],  
        borderColor: ['rgba(99, 255, 132, 1)'],  
        borderWidth: 1,
      tension: 0.3
      }]
    }
  }
}

function meetingChart(terms, meeting, facilitate) {
  return {
    type: 'bar',
    data: {
      labels: terms,
      datasets: [{
        label: 'meeting',
        data: meeting,
        borderColor: ['rgba(99, 132, 255, 1)'],
        backgroundColor: ['rgba(99, 132, 255, 0.7)']
      },{
        label: 'facilitate',
        data: facilitate,
        borderColor: ['rgba(255, 99, 132, 1)'],
        backgroundColor: ['rgba(255, 99, 132, 0.7)']
      }]
    }
  }
}

const dailyScore = scoreChart(days, scores)
const dailyMeeting = meetingChart(days, meetings, facilitates)
const weeklyScore = scoreChart(...aggregateKeys(pages, 'week', 'avg', ['score']))
const weeklyMeeting = meetingChart(...aggregateKeys(pages, 'week', 'sum', ['meeting', 'facilitate']))

window.renderChart(dailyScore, this.container)
window.renderChart(dailyMeeting, this.container)
window.renderChart(weeklyScore, this.container)
window.renderChart(weeklyMeeting, this.container)

このコードでは、いくつかまとめた処理を関数化しているが

  • Daily Noteから数値データを取り出す
  • 週単位で合計、平均などの計算をする
  • 計算結果をChartsへ渡してレンダリングする

といった処理をしている

Weeklyの推移

まとめ

ObsidianChartsプラグインを使うことで、DailyNoteで記録した数値データを簡単に時系列でグラフ化できる

Dataviewプラグインと組み合わせることで集計をした結果を時系列でグラフ化できる

この結果を見ながら振り返りなどを行うことでより分析しやすくなる