Skip to content
Back to skills

Obsidian Charts

ASecurity

Build interactive Chart.js charts in Obsidian notes via `chart` codeblocks — inline series, a markdown table by block ID, or a Dataview query. Use when the user wants to chart, plot, graph, or visualize data in their Obsidian notes, or mentions "obsidian charts" or "renderChart".

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 6, 2026
ai-agentsgoapi

Works with

  • claude code
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned September 25, 2026

npx -y skills add risadams/ink-and-agency --skill obsidian-charts --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Obsidian Charts?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Obsidian Charts
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/risadams-obsidian-charts/badge)](https://www.skillsdirectory.com/skills/risadams-obsidian-charts)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: obsidian-charts
category: obsidian
description: >
  Build interactive Chart.js charts in Obsidian notes via `chart` codeblocks — inline
  series, a markdown table by block ID, or a Dataview query. Use when the user wants to
  chart, plot, graph, or visualize data in their Obsidian notes, or mentions "obsidian
  charts" or "renderChart".
codex-short-description: "Build Chart.js charts in Obsidian notes from inline series, tables, or Dataview"
related-skills:
  - obsidian-bases
loop-eligible: false

compatibility: claude-code codex opencode
---
# Obsidian Charts Skill

Assumes the user already has the **Charts** community plugin (phibr0/obsidian-charts) installed and enabled.

## Decide the data source first

Before writing any codeblock, pick the source — it changes the syntax:

| Source | Use when | Pattern |
|---|---|---|
| Inline literal | Small, hand-typed series | `chart` codeblock with `labels:` + `series:` |
| Markdown table in same note | Data already lives in a table | `chart` codeblock with `id: <blockId>` |
| Markdown table in another note | Shared data table | `chart` codeblock with `id:` + `file:` |
| Dataview / Dataviewjs query | Data is computed/aggregated | `dataviewjs` codeblock calling `window.renderChart(...)` |
| Frontmatter values | Comparing notes by property | Dataviewjs + `renderChart` (Dataview required) |

If the user is unsure, look at the note. A table → use table linking. A query → use renderChart. Loose numbers in prose → inline literal.

## Quick start — inline data

````markdown
```chart
type: bar
labels: [Mon, Tue, Wed, Thu, Fri]
series:
  - title: Hours focused
    data: [4, 3, 5, 2, 6]
beginAtZero: true
width: 80%
```
````

## Quick start — from a table in the same note

````markdown
| | Q1 | Q2 | Q3 | Q4 |
| - | - | - | - | - |
| Revenue | 10 | 14 | 12 | 18 |
| Cost    | 8  | 9  | 11 | 13 |
^revenue

```chart
type: bar
id: revenue
layout: rows
beginAtZero: true
```
````

`layout: rows` reads each table row as a series; `layout: columns` reads each column as a series. Add `select: [Revenue]` to restrict which rows/columns are charted. Add `file: <OtherNote>` to point at a `^blockId` in another note.

## Quick start — from a Dataview query

Requires the **Dataview** plugin with JS enabled.

````markdown
```dataviewjs
const pages = dv.pages('"Journal"').where(p => p.mood);
window.renderChart({
  type: 'line',
  data: {
    labels: pages.map(p => p.file.name).array(),
    datasets: [{
      label: 'Mood',
      data: pages.map(p => p.mood).array(),
      tension: 0.3,
    }]
  }
}, this.container);
```
````

## Core parameters (chart codeblock)

| Key | Values | Notes |
|---|---|---|
| `type` | `bar` `line` `pie` `doughnut` `radar` `polarArea` | Required |
| `labels` | `[a, b, c]` | Required for non-table source |
| `series` | list of `{ title, data }` | Required for non-table source |
| `id` | block ID | Use instead of `labels`/`series` to pull from a table |
| `file` | note basename | Pairs with `id` for cross-note tables |
| `layout` | `rows` \| `columns` | Table-source only |
| `select` | `[name1, name2]` | Filter rows/cols from a table |
| `beginAtZero` | bool | Force y-axis to start at 0 |
| `stacked` | bool | Stack series (bar/line) |
| `tension` | 0–1 | Line curve smoothing |
| `fill` | bool | Fill area under line |
| `width` | `80%` etc. | Chart width |
| `legend` | bool | Show legend |
| `legendPosition` | `top` `bottom` `left` `right` | |
| `bestFit` | bool | Draw trend line (line/scatter) |
| `bestFitTitle` | string | Label for trend line |
| `bestFitNumber` | number | Series index for trend |
| `labelColors` | bool | Color labels by series |
| `time` | `day` `month` `year` etc. | Treat labels as dates |
| `indexAxis` | `x` \| `y` | `y` makes horizontal bar chart |
| `xMin` `xMax` `yMin` `yMax` | number/date | Axis bounds |
| `xTitle` `yTitle` | string | Axis labels |

See [REFERENCE.md](REFERENCE.md) for the full parameter list, `renderChart` API, color/styling, multi-series patterns, and troubleshooting.

## Workflow when helping the user

1. **Locate the data.** Read the note, identify whether the data is a table (does it have a `^blockId`?), a query result, or loose values.
2. **Pick the chart type.** Comparing categories → `bar`. Trend over time → `line`. Parts of a whole → `pie` / `doughnut`. Multi-dimensional → `radar`.
3. **If using a table**, confirm there is a `^blockId` line beneath it. If not, add one — without it, the chart cannot reference the table.
4. **Draft the codeblock** inline in the note (don't make a new file unless the user asks).
5. **Pick `layout`** carefully — `rows` vs `columns` is the most common "why is my chart wrong" issue. If the chart looks transposed, flip it.
6. **Tell the user to open the note in Reading view or Live Preview** to render the chart; Source view shows the raw codeblock.

## Common gotchas

- **No render in Source mode** — switch to Live Preview or Reading view.
- **Table reference fails** — the `^blockId` must be on its own line immediately after the table, and `id:` in the codeblock must match exactly (no `^`).
- **`layout` mismatch** — series and labels look swapped; flip `rows` ↔ `columns`.
- **Date axis flat / unsorted** — set `time: day` (or `month`/`year`) so the plugin treats labels as dates.
- **`renderChart` undefined** — the Charts plugin isn't enabled, or the codeblock isn't `dataviewjs` (it must be — `dataview` won't work for JS).
- **Series with mismatched lengths** — every `data` array must match `labels.length` (pad with `null` for missing points).

> **Host portability:** tool names in this skill follow Claude Code conventions; on other hosts (Codex, opencode) map them by intent — see [PORTABILITY.md](../PORTABILITY.md).

<!-- self-evolve:start -->
## Self-Evolve Loop
Journal `~/.ink-and-agency/learnings/obsidian-charts.md` (or workspace-local `.ink-and-agency/` where the sandbox confines writes). Read it first; append what the run taught — [SELF-EVOLVE.md](../SELF-EVOLVE.md).
<!-- self-evolve:end -->

Files in this skill

  • EXAMPLES.md8 KB
  • README.md10.1 KB
  • REFERENCE.md7.6 KB
  • SKILL.md6 KB
  • agents/openai.yaml260 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.