AI-native declarative visual analytics — YAML DSL to Vega-Lite translator
Project description
Declarative visual analytics for semantic models.
Write charts and dashboards in YAML, render to Vega-Lite.
Shelves charts read from a semantic model — measures, dimensions, formats, and aggregations defined once and reused everywhere, so you never copy-paste field logic across dashboards. You can back that model two ways:
- Start with a flat file. Point a model at a local CSV, Parquet, or JSON file and Shelves queries it directly with DuckDB.
shelves-importcan even generate the model for you. Zero infrastructure — go from a raw file to a chart in seconds. - Grow into a semantic layer. Point the same model at a Cube.dev instance when you want shared governed definitions across a team. Only the model's
sourceblock changes; your charts stay untouched.
The two paths use the identical model and chart schema, so a project can graduate from file to Cube without rewriting a single chart.
Install
pip install shelves-bi
For the flat-file path, install the optional DuckDB extra:
pip install 'shelves-bi[duckdb]'
Requires Python 3.11+.
Quick start (flat file)
Generate a model from a CSV — string columns become dimensions, numeric columns become measures, dates become temporal dimensions:
shelves-import sales.csv # writes models/sales.yaml
The generated model points at your file:
# models/sales.yaml
model: sales
label: Sales
source:
type: file
path: sales.csv
measures:
revenue:
column: Revenue
aggregation: sum
label: Revenue
format: "$,.0f"
dimensions:
category:
column: Category
label: Category
order_date:
column: Order Date
type: temporal
label: Order Date
defaultGrain: month
Write a chart that references the model by name, then render:
# charts/revenue_by_category.yaml
sheet: "Revenue by Category"
data: sales
cols: category
rows: revenue
marks: bar
color: category
sort:
field: revenue
order: descending
shelves-render charts/revenue_by_category.yaml --models-dir models/
Output goes to output/<sheet-name-slug>.html by default. Use --out to override.
Connect to Cube
When you're ready for a governed semantic layer, point the model's source at a Cube.dev instance instead. Set your credentials in a .env file or as environment variables:
CUBE_API_URL=http://localhost:4000
CUBE_API_TOKEN=your-cube-api-token
Only the source block changes — measures, dimensions, labels, and formats are declared the same way as the file model above:
# models/orders.yaml
model: orders
label: Orders
source:
type: cube
cube: orders
measures:
net_sales:
label: Net Sales
format: "$,.0f"
aggregation: sum
dimensions:
category:
label: Category
order_date:
type: temporal
label: Order Date
defaultGrain: month
format:
month: "%b %Y"
Your existing charts keep working unchanged.
Project structure
A typical Shelves project looks like this:
my-project/
models/
sales.yaml # semantic model definitions (file or cube source)
charts/
revenue_by_category.yaml
sales_over_time.yaml
dashboards/
overview.yaml
.env # CUBE_API_URL / CUBE_API_TOKEN (only for the Cube path)
Dashboards
Dashboards compose multiple charts into a single HTML page with layout, text, and styling:
# dashboards/overview.yaml
dashboard: "Sales Overview"
canvas: { width: 1440, height: 900 }
root:
orientation: vertical
contains:
- text: "Sales Overview"
preset: title
- horizontal:
contains:
- sheet: "charts/revenue_by_category.yaml"
width: "60%"
- sheet: "charts/sales_over_time.yaml"
width: "40%"
# Dashboard (charts and models resolved from directories)
shelves-render dashboards/overview.yaml --chart-dir charts/ --models-dir models/
# Dev server with live reload
shelves-dev charts/revenue_by_category.yaml --models-dir models/
Python API
from shelves import parse_chart, translate_chart, merge_theme, render_html
from shelves.data.bind import resolve_data
spec = parse_chart(yaml_string) # YAML -> ChartSpec
vl = translate_chart(spec) # ChartSpec -> Vega-Lite dict
themed = merge_theme(vl) # apply default theme
final = resolve_data(themed, spec) # query the model's source and bind
html = render_html(final) # standalone HTML with vegaEmbed
Each step is independent and composable.
Documentation
- Getting Started — setup, first chart, first dashboard
- DSL Reference — complete field and property reference
- Dashboards — layout DSL, components, and styling
Development
git clone https://github.com/shelveshq/shelves.git
cd shelves
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
License
Apache 2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shelves_bi-0.5.0.tar.gz.
File metadata
- Download URL: shelves_bi-0.5.0.tar.gz
- Upload date:
- Size: 895.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ad22425adc11daa7b05d57089c68408d5128a1ef99317759463cf30c13170fb
|
|
| MD5 |
edc9a639ac1f7aa6ab3b38e9730906f4
|
|
| BLAKE2b-256 |
efcd6c6388485a8cdce1a2d747c2f1eaa33e3f032d47caf99a73df6e264cd80e
|
File details
Details for the file shelves_bi-0.5.0-py3-none-any.whl.
File metadata
- Download URL: shelves_bi-0.5.0-py3-none-any.whl
- Upload date:
- Size: 803.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f77b5051f0ad83e2a6cecde3cacb8d3d17bed341cc05c0c4a59fb26e442e6dc
|
|
| MD5 |
edf3ab1a81b6c19d350c75e4ee9bcd4a
|
|
| BLAKE2b-256 |
2e6e0b89750e46acefa59a063d9f7d1d4ebca2d22b7e797b04bdf0220d5e5988
|