Bases Chart
approvedby kevinmcaleer
This plugin has not been manually reviewed by Obsidian staff. Visualize Bases data as bar, column, pie, doughnut, gauge, line, and calendar charts using SQL queries.
Bases Chart
Visualize your Obsidian Bases data as charts — directly inside your notes.
Features
- 8 chart types — bar, column (horizontal bar), pie, doughnut, gauge (half-doughnut), line, GitHub-style calendar heatmap, and stat (single-number KPI)
- SQL query language — familiar syntax for querying your Bases data
- Visual configuration — inline settings panel with dropdowns, toggles, draggable color palette, and live SQL preview
- Multi-metric queries — count multiple conditions in a single chart (e.g. "missing tags" vs "missing dates")
- Multi-source — compare data across multiple
.basefiles side-by-side, or merge them with UNION - Date bucketing —
GROUP BY month(file.ctime)/year(...)/day(...)for time-series charts - Relative-time functions —
today(),now(),daysSince(),daysUntil(),year(),month(),day() - Sorting — order bars by value or label, ascending or descending
- Data labels — show values at base, top, or outside of bars/slices with callout support for pie charts
- Appearance controls — custom colors with drag-to-reorder, gridline toggle, legend toggle, font size and colour for stat charts, configurable chart height
Quick Start
Add a fenced code block with bases-chart and write a SQL query:
```bases-chart
type: bar
sql: SELECT COUNT(*) FROM "Todos.base" GROUP BY status
```
Or start with an empty block and use the gear icon to configure visually:
```bases-chart
```
You can also insert a chart via the command palette: Insert bases chart.
Configuration
The YAML config has two parts: appearance (stored in YAML) and data (stored as SQL):
type: bar # chart type (bar | column | pie | doughnut | gauge | line | calendar | stat)
sql: SELECT COUNT(*) FROM "Todos.base" GROUP BY status
title: My Chart # optional title
showGridlines: true # show/hide gridlines
showLegend: true # show/hide legend
dataLabels: outside # none | base | top | outside
colors: # custom color palette
- "#4e79a7"
- "#f28e2b"
height: 400 # chart height in pixels (default 400; 200 for stat)
fontSize: 72 # stat chart only — number font size in pixels (default 72)
fontColor: "#4e79a7" # stat chart only — hex colour; omit to inherit the theme
SQL Reference
Basic queries
-- Count notes grouped by a property
SELECT COUNT(*) FROM "Todos.base" GROUP BY status
-- Show a value per note
SELECT file.name, Priority FROM "Projects.base/Starred"
-- Computed values
SELECT daysSince(file.ctime) FROM "Todos.base/Starred" ORDER BY value DESC
-- Aggregate with grouping
SELECT AVG(rating) FROM "Books.base" GROUP BY categories
SELECT clause
| Syntax | Meaning |
|---|---|
SELECT file.name, Rank | Per-note: label + value |
SELECT daysSince(file.ctime) | Per-note: computed value |
SELECT COUNT(*) | Count (use with GROUP BY) |
SELECT SUM(prop) | Sum values per group |
SELECT AVG(prop) | Average values per group |
FROM clause
| Syntax | Meaning |
|---|---|
FROM "Todos.base" | Use first view from a Base |
FROM "Todos.base/Starred" | Use a specific named view |
FROM "A.base", "B.base" | Separate datasets (grouped bars) |
FROM "A.base" UNION "B.base" | Merge into one pool |
FROM notes | All notes in vault |
WHERE clause
Top-level WHERE supports tag and folder filters:
WHERE tags CONTAINS 'project'
WHERE folder = 'Work'
WHERE tags CONTAINS 'todo' AND folder = 'Work'
Per-metric WHERE (inside a multi-metric SELECT) supports a richer
comparator set, including relative-time functions and date-bucket
wrappers on the left-hand side:
-- Operators: =, !=, >, >=, <, <=, CONTAINS, IS EMPTY, IS NOT EMPTY
COUNT(*) WHERE status != 'done'
COUNT(*) WHERE Priority >= 3
COUNT(*) WHERE date IS NOT EMPTY
-- today() expands to 'YYYY-MM-DD' (local date)
COUNT(*) WHERE day(file.ctime) = today() -- created today
COUNT(*) WHERE month(file.ctime) = month(today()) -- created this month (see note below)
-- now() expands to current epoch milliseconds
COUNT(*) WHERE file.mtime >= 1760000000000 -- modified since this timestamp
Note:
month(today())currently requirestoday()to resolve to a value whosemonth(...)wrapper produces the same bucket format. The cleanest pattern for "created this month" is still to group by month and pick the current bucket — or use a literal'2026-04'.
GROUP BY
GROUP BY status -- by a property
GROUP BY day(file.ctime) -- per-day bucket → "YYYY-MM-DD"
GROUP BY month(file.ctime) -- per-month bucket → "YYYY-MM"
GROUP BY year(file.ctime) -- per-year bucket → "YYYY"
Date-bucket grouping works on any date property — frontmatter dates
(GROUP BY month(published)) as well as file timestamps.
Multi-metric SELECT
Each metric gets its own bar/slice:
SELECT
COUNT(*) WHERE tags IS EMPTY AS "Missing Tags",
COUNT(*) WHERE topics IS EMPTY AS "Missing Topics",
COUNT(*) WHERE date IS EMPTY AS "Missing Dates"
FROM "Todos.base"
ORDER BY
ORDER BY value DESC -- sort by bar height
ORDER BY value ASC -- smallest first
ORDER BY label ASC -- alphabetical
ORDER BY label DESC -- reverse alphabetical
Built-in functions
| Function | Where it's valid | Description |
|---|---|---|
daysSince(prop) | SELECT | Days between property date and today (per note) |
daysUntil(prop) | SELECT | Days from today to property date (per note) |
year(prop) | SELECT, GROUP BY, WHERE LHS | Year bucket → "YYYY" |
month(prop) | SELECT, GROUP BY, WHERE LHS | Month bucket → "YYYY-MM" |
day(prop) | SELECT, GROUP BY, WHERE LHS | Day bucket → "YYYY-MM-DD" |
today() | WHERE RHS (per-metric) | Expands to 'YYYY-MM-DD' (local date) |
now() | WHERE RHS (per-metric) | Expands to current epoch milliseconds |
Chart Types
| Type | Description |
|---|---|
bar | Vertical bar chart |
column | Horizontal bar chart |
pie | Pie chart |
doughnut | Doughnut chart (pie with center hole) |
gauge | Half-doughnut (top hemisphere only) |
line | Line chart |
calendar | GitHub-style contribution heatmap (52 weeks) |
stat | Single large number — ideal for dashboards / KPI tiles |
Examples
Todo age ranking
type: bar
sql: SELECT daysSince(file.ctime) FROM "Todos.base/Starred" ORDER BY value DESC
dataLabels: outside
showGridlines: false
Project status gauge
type: gauge
sql: SELECT COUNT(*) FROM "Projects.base" GROUP BY status
dataLabels: outside
Note activity calendar
type: calendar
sql: SELECT COUNT(*) FROM "Todos.base"
title: Note Activity
Data quality audit
type: bar
sql: >
SELECT
COUNT(*) WHERE tags IS EMPTY AS "No Tags",
COUNT(*) WHERE topics IS EMPTY AS "No Topics",
COUNT(*) WHERE date IS EMPTY AS "No Date"
FROM "Todos.base"
dataLabels: outside
Notes created today (stat tile)
type: stat
title: Notes created today
sql: SELECT COUNT(*) WHERE day(file.ctime) = today() AS "Today" FROM notes
fontSize: 96
fontColor: "#4e79a7"
Notes created each month (time series)
type: bar
title: Notes per month
sql: SELECT COUNT(*) FROM notes GROUP BY month(file.ctime) ORDER BY label asc
dataLabels: top
showLegend: false
KPI row — three stat tiles side-by-side
Drop these in a 3-column layout (e.g. the Dashboards plugin) for a tidy summary strip:
type: stat
title: Total notes
sql: SELECT COUNT(*) AS "Notes" FROM notes
type: stat
title: Created this month
sql: SELECT COUNT(*) WHERE month(file.ctime) = '2026-04' AS "This month" FROM notes
fontColor: "#59a14f"
type: stat
title: Modified in last 24h
sql: SELECT COUNT(*) WHERE file.mtime >= 1760000000000 AS "Last 24h" FROM notes
fontColor: "#f28e2b"
Installation
From Obsidian
- Open Settings → Community Plugins → Browse
- Search for Bases Chart
- Click Install, then Enable
From source
cd /path/to/vault/.obsidian/plugins
git clone https://github.com/kevinmcaleer/obsidian-bases-chart.git
cd bases-chart
npm install
npm run build
Restart Obsidian and enable the plugin in Settings → Community Plugins.
Manual
- Download
main.js,manifest.json, andstyles.cssfrom the latest release - Create a folder
bases-chartinside.obsidian/plugins/ - Copy the three files into that folder
- Restart Obsidian and enable the plugin
Development
npm install
npm run dev # one-shot build with source maps
npm run build # production build (minified, auto-bumps version)
License
MIT
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.