# Obsidian Charts

> Build interactive charts in Obsidian notes using the Charts plugin (phibr0/obsidian-charts). Renders Chart.js bar/line/pie/doughnut/radar/polarArea via `chart` codeblocks, can pull data straight from a markdown table by block ID (cross-file supported), and can render from a Dataview query via `window.renderChart`. Use when the user wants to chart, plot, graph, or visualize data sitting in their Obsidian notes — including tables, frontmatter values, Dataview/Dataviewjs results, or hand-written series — or mentions "obsidian charts", "chart codeblock", "renderChart", or "chart from table".

- Skill: `risadams/obsidian-charts` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add risadams/obsidian-charts`
- Raw SKILL.md: https://api.skillmd.com/api/skills/risadams/obsidian-charts/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: risadams (https://skillmd.com/u/risadams)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/risadams/obsidian-charts

---


# 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).


