Heatmap Calendar to Track Habits in Obsidian

A heatmap calendar is a powerful way to track and visualize our activities. It makes it easy to get insights about how we spend and engage our time. 

If you use Obsidian and want to track your habits and activities with a heatmap calendar, you landed on the right spot. 

This article teaches you how to create a heatmap calendar tailored for tracking habits, and other activities within Obsidian.

Previously, I talked about creating a simple habit tracker with the dataview plugin. By the end of this article, you’ll learn a little more advanced way to track habits i.e. by using a heatmap calendar.

Heatmap calendar

I’m a non-tech guy. So, I’ve made it as simple as possible to implement this in your vault. 

Install the required plugins

We’ll need two plugins to create a heatmap calendar. The first one is Dataview. I guess you are already using that one. 

After installing the dataview plugin, you need to enable the javascript queries. 

The second plugin you need is Heatmap Calendar by Richardsl.

Heatmap calendar visualizes the data in your notes similar to the GitHub activity calendar.

Creating a Heatmap Calendar

First, have your data in place. Where do you want to query data from? For example: I have created new notes for this experiment inside the Daily Note folder.

Here’s a dummy template I’ve created with 4 properties.

  • Exercise(Number)
  • Spent(Number)
  • Mood(Number)
  • Writing(Checkbox)
---
Exercise:
Spent:
Mood:
Writing: false
---

Simple Heatmap Calendar

```dataviewjs

dv.span("**🏋️ Exercise 🏋️**")

const calendarData = {
colors: {
red: ["#ff9e82","#ff7b55","#ff4d1a","#e73400","#bd2a00",]
},
entries: []
}

for(let page of dv.pages('"Daily Note"').where(p=>p.Exercise)){
calendarData.entries.push({
date: page.file.name,
intensity: page.Exercise,
content: await dv.span(`[](${page.file.name})`), //for hover preview
})

}

renderHeatmapCalendar(this.container, calendarData)

```

If you want to implement this into your vault. Here are the properties, you’ll need to replace based on your vault’s organization. 

1. dv.span("**🏋️ Exercise 🏋️**") //change the title
2. for(let page of dv.pages('"Daily Note"').where(p=>p.Exercise))
//Folder location where you want to query data from + the property you want to visualize
3. intensity: page.Exercise //Replace it with the name of the property

This creates a heatmap calendar like this:

Note: I’ve created daily notes only for the month of December

It visualizes my exercise activity from daily notes. I logged the duration of the workout in the daily notes. So, it visualizes the intensity of the workouts. Red color being the highest and light red being the lowest duration. 

Now, let’s create a different type of heatmap calendar with a specific target value.

Heatmap calendar with a target value. 

This works exactly as before but when a specific value is met, you can configure it to visualize it differently. 

For example: Let’s say your goal is to workout 30 minutes every day. You can rewrite the code to display a green color when the 30-minute workout duration is met. 

All you need to do is add intensityScaleEnd.

```dataviewjs

dv.span("**🏋️ Exercise 🏋️** (Green if you reached your goal of 30 minutes)")

const calendarData = {
intensityScaleEnd: 30,
colors: {
red: ["#ff9e82","#ff7b55","#ff4d1a","#e73400","#bd2a00",
"hsl(132, 90%, 40%)"] //last one green
},
entries: []
}

for(let page of dv.pages('"Daily Note"').where(p=>p.Exercise)){
calendarData.entries.push({
date: page.file.name,
intensity: page.Exercise,
content: await dv.span(`[](${page.file.name})`)
})

}

renderHeatmapCalendar(this.container, calendarData)

```

This visualizes the data like this:

Don’t Break the Chain

This one can be used when you are using checkboxes in your properties. Where there is only one case, either true or false. 

I have a writing property. If I want to visualize the data with the don’t break the chain rule, here’s how to do it.

```dataviewjs

dv.span("** Writing **- Dont break the chain! ")

const calendarData = {
colors: {
white: ["#E8D7BA"],
},
entries: []
}

for(let page of dv.pages('"Daily Note"').where(p=>p.Writing)){

calendarData.entries.push({
date: page.file.name,
content: await dv.span(`[✔️](${page.file.name})`), //for hover preview
})
}

//console.log(calendarData)

renderHeatmapCalendar(this.container, calendarData)

```

I used a white background color with a tick emoji inside it. 

And the result looks like this:

An Intensity Scale

This one can be used when you want to visualize only a specific range of data from a property. 

Here’s an example of visualizing data within a specific range. 

You do this by specifying intensityScaleStart and intensityScaleEnd.

```dataviewjs
dv.span("** 😊 Mood 😥**")

const calendarData = {
intensityScaleStart: 1,
intensityScaleEnd: 9,
colors: {
green: ["#ffffff", "#f2e7f7", "#e5d0f0", "#d8b8e9", "#ccalel", "#bf8ada", "#b272d3", "#a65bcb", "#9943c4"],
},
entries: []
}

for(let page of dv.pages('"Daily Note"').where(p=>p.Mood)){

calendarData.entries.push({
date: page.file.name,
intensity: page.Mood,
content: await dv.span(`[](${page.file.name})`), //for hover preview
})

}

renderHeatmapCalendar(this.container, calendarData)

```

The result looks like this:

I’ve used 9 different tints for this purple color. 

You can get different shades and tints for a particular color from this site

This image has an empty alt attribute; its file name is image-14.png

Conclusion

This is how you can use the Obsidian heatmap calendar plugin to visualize different habits and activities inside of Obsidian. If you want to dive deep into the plugin, you can check out the documentation page in github

If you found this article valuable, you’ll love Obsidian Ninja.

Share your love
Prakash Joshi Pax
Prakash Joshi Pax
Articles: 11

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.