Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions docs/md/doc/perspective.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Perspective.js Integration

BSL can write semantic query results as Perspective.js-compatible Arrow artifacts. This integration is intentionally narrow: BSL prepares a static backend artifact, and host applications decide how to serve the files and instantiate `@finos/perspective` or `<perspective-viewer>`.

## Why Perspective artifacts

Perspective is useful for BI-style tables and exploratory dashboard panels:

- interactive sorting, filtering, grouping, and pivoting
- browser-side WebAssembly execution
- Arrow-friendly client/server replication
- embeddable web component runtime

BSL does not depend on Perspective's frontend packages. It writes a small host-generic manifest next to an Arrow file.

## Backend/frontend model

The intended integration boundary is expression-first and artifact-focused:

```text
LLM or application intent
-> BSL semantic query / Ibis expression
-> backend writes Arrow + Perspective manifest
-> host serves those files
-> frontend loads Arrow into Perspective and applies viewer hints
```

Agents and application code should describe semantic intent in BSL terms: models, dimensions, measures, filters, and optional viewer hints. They should not generate raw Perspective runtime objects or frontend-specific table setup code.

The backend should own:

- compiling semantic intent into a BSL/Ibis expression
- materializing the expression as Arrow
- writing the Arrow artifact and manifest

The frontend should own:

- fetching the manifest and Arrow file
- loading Arrow into Perspective
- instantiating the viewer component
- applying allowed viewer hints such as plugin, columns, grouping, sorting, and filters

## Write a Perspective artifact

```python
result = orders.group_by("customer", "region").aggregate("revenue", "order_count")

from boring_semantic_layer.integrations.perspective import write_perspective_artifact

artifact = write_perspective_artifact(
result,
"./dashboard-data",
id="orders_by_customer",
viewer={"plugin": "Datagrid", "group_by": ["region"]},
)

print(artifact.manifest_path)
print(artifact.data_path)
```

This writes:

```text
dashboard-data/
orders_by_customer.perspective.json
orders_by_customer.arrow
```

The manifest uses `kind: "bsl.perspective.artifact"` and stores the external file reference in `data_ref`:

```json
{
"kind": "bsl.perspective.artifact",
"version": 1,
"id": "orders_by_customer",
"schema": [
{"name": "customer", "type": "string", "role": "dimension"},
{"name": "region", "type": "string", "role": "dimension"},
{"name": "revenue", "type": "float", "role": "measure"}
],
"viewer": {"plugin": "Datagrid", "group_by": ["region"]},
"data_ref": {"format": "arrow", "path": "orders_by_customer.arrow"}
}
```

Arrow export requires `pyarrow`; install it with `pip install 'boring-semantic-layer[viz-perspective]'` or your project's equivalent extra installation.

## Use with host applications

A host application can load the manifest, fetch the referenced Arrow file, and pass the Arrow bytes into a Perspective table or viewer. Hosts should expose high-level application components instead of asking agents to generate raw Perspective options.

BSL owns query execution and artifact writing; the host owns transport, UI rendering, and component mapping.
5 changes: 5 additions & 0 deletions docs/md/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@
"description": "ASCII charts for terminal/CLI with Plotext backend",
"source": "prompts/chart/plotext.md"
},
"perspective": {
"title": "Perspective.js Integration",
"description": "Export BSL query results as Perspective-compatible datasets and artifacts",
"source": "doc/perspective.md"
},
"sessionized": {
"title": "Sessionized Data",
"description": "Working with session-based data and user journey analysis",
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/claude-code/bsl-model-builder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ flights_st = flights_st.with_measures(
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/claude-code/bsl-query-expert/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ Step 2 (filter): query_model(query="model.filter(lambda t: t.region.isin(['CA'
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/codex/bsl-model-builder.codex
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ flights_st = flights_st.with_measures(
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/codex/bsl-query-expert.codex
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Step 2 (filter): query_model(query="model.filter(lambda t: t.region.isin(['CA'
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/cursor/bsl-model-builder.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ flights_st = flights_st.with_measures(
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
2 changes: 2 additions & 0 deletions docs/md/skills/cursor/bsl-query-expert.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ Step 2 (filter): query_model(query="model.filter(lambda t: t.region.isin(['CA'
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotly.md
- **Terminal Charts**: ASCII charts for terminal/CLI with Plotext backend
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/prompts/chart/plotext.md
- **Perspective.js Integration**: Export BSL query results as Perspective-compatible datasets and artifacts
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/perspective.md
- **Sessionized Data**: Working with session-based data and user journey analysis
- URL: https://github.com/boringdata/boring-semantic-layer/blob/main/docs/md/doc/sessionized.md
- **Comparison Queries**: Period-over-period comparisons and trend analysis
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ examples = ["xorq[duckdb]>=0.3.31", "duckdb<1.4"]
viz-altair = ["altair>=5.0.0", "vl-convert-python>=1.0.0"]
viz-plotly = ["plotly>=6.3.0", "kaleido", "nbformat>=4.2.0"]
viz-plotext = ["plotext>=5.0.0"]
viz-perspective = ["pyarrow>=14.0.0"]

agent = [
"langchain>=0.3.0",
Expand Down
17 changes: 17 additions & 0 deletions src/boring_semantic_layer/integrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Optional integrations for dashboard and BI runtimes."""

from .perspective import (
PerspectiveArtifact,
PerspectiveColumn,
infer_perspective_schema,
perspective_viewer_config,
write_perspective_artifact,
)

__all__ = [
"PerspectiveArtifact",
"PerspectiveColumn",
"infer_perspective_schema",
"perspective_viewer_config",
"write_perspective_artifact",
]
Loading
Loading