Skip to main content

Code-first analytics dashboard platform — same data model as Metabase, Looker, PowerBI, Cube — but in Python, for agents, outputting Markdown

Project description

dashboardmd

Code-first analytics dashboard platform. Connectors for everything. Markdown output.

Universal data model — same concepts as Metabase, Looker, PowerBI, Cube — but in Python, for agents, with composable connectors that work together.

The Core Idea

Every analytics platform uses the same foundational concepts:

  1. Entities (tables/views with semantic meaning)
  2. Dimensions (attributes you group and filter by)
  3. Measures (aggregations you compute)
  4. Relationships (how entities join together)
  5. Queries (select measures + dimensions → get results)
  6. Dashboards (tiles bound to queries + global filters)

dashboardmd mirrors these concepts in Python. Connectors are the universal integration layer — whether your data comes from CSV files, REST APIs, BI platforms, or community packages, everything plugs into the same system.

     Connectors                           Built-in
  ┌──────────────────────────┐     ┌───────────────────────┐
  │ Data Connectors          │     │ File Sources           │
  │  • Custom (your code)    │     │  • CSV / Parquet / JSON│
  │  • Community (pip)       │     │  • DuckDB / SQLite     │
  │  • API / Callable        │     │  • PostgreSQL / MySQL  │
  │                          │     │  • pandas DataFrames   │
  │ BI Platform Connectors   │     │                       │
  │  • MetabaseConnector     │     │ Semantic Layer         │
  │  • LookMLConnector       │     │  • Entity / Dimension  │
  │  • CubeConnector         │     │  • Measure / Query     │
  │  • PowerBIConnector      │     │  • Relationship        │
  └────────────┬─────────────┘     └───────────┬───────────┘
               │                               │
               └───────────────┬───────────────┘
                               ▼
                    ┌──────────────────┐
                    │   dashboardmd    │
                    │    Analyst       │  ← DuckDB engine
                    │  analyst.use()   │  ← composable connectors
                    └────────┬─────────┘
                             │
                             ▼
                ┌──────────────────────────┐
                │      Markdown Report     │
                │        (.md files)       │
                └──────────────────────────┘

Installation

pip install dashboardmd

With optional dependencies:

pip install "dashboardmd[pandas]"      # DataFrame support
pip install "dashboardmd[plotting]"    # Chart images via matplotlib
pip install "dashboardmd[all]"         # Everything

Quick Start

Direct SQL with Analyst (maximum agent power)

The Analyst is the core of dashboardmd — a DuckDB-powered query engine that gives AI agents full analytical SQL capabilities over any data source.

from dashboardmd import Analyst

# Create an analyst and register data sources
analyst = Analyst()
analyst.add("orders", "data/orders.csv")
analyst.add("customers", "data/customers.csv")

# Full DuckDB SQL — aggregations, window functions, CTEs, JOINs, pivots, regex...
result = analyst.sql("""
    SELECT
        c.segment,
        COUNT(*) AS order_count,
        SUM(o.amount) AS revenue,
        AVG(o.amount) AS avg_order_value
    FROM orders o
    JOIN customers c ON o.customer_id = c.id
    WHERE o.status = 'completed'
    GROUP BY 1
    ORDER BY revenue DESC
""")

# Multiple output formats
result.show()                  # Print to stdout
result.to_markdown_table()     # Render as Markdown table
result.df()                    # Return as pandas DataFrame
result.fetchall()              # Raw tuples
result.scalar()                # Single value

# Schema exploration (great for agents)
analyst.tables()               # List all tables
analyst.schema("orders")       # Column names and types
analyst.sample("orders", 5)    # Preview rows
analyst.count("orders")        # Row count

# Write results to Markdown
analyst.to_md("output/analysis.md", title="Revenue Analysis", queries=[
    ("By Segment", "SELECT segment, SUM(amount) FROM orders GROUP BY 1"),
    ("Top 10", "SELECT * FROM orders ORDER BY amount DESC LIMIT 10"),
])

Semantic Queries (BI-style)

Build on top of Analyst with entities, dimensions, and measures — same concepts as Looker, PowerBI, Cube, and Metabase.

from dashboardmd import Analyst, Entity, Dimension, Measure, Relationship

# Define entities (like Looker views, PowerBI tables, Cube cubes)
orders = Entity("orders", source="data/orders.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("date", type="time"),
    Dimension("customer_id", type="number"),
    Dimension("status", type="string"),
], measures=[
    Measure("revenue", type="sum", sql="amount"),
    Measure("count", type="count"),
])

# Register entities and query semantically
analyst = Analyst()
analyst.add_entity(orders)
result = analyst.query(measures=["orders.revenue"], dimensions=["orders.status"])
print(result.to_markdown_table())

Dashboards (structured reports)

from dashboardmd import Dashboard, Entity, Dimension, Measure, Relationship

orders = Entity("orders", source="data/orders.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("date", type="time"),
    Dimension("customer_id", type="number"),
    Dimension("status", type="string"),
], measures=[
    Measure("revenue", type="sum", sql="amount", format="$,.0f"),
    Measure("count", type="count"),
])

customers = Entity("customers", source="data/customers.csv", dimensions=[
    Dimension("id", type="number", primary_key=True),
    Dimension("name", type="string"),
    Dimension("segment", type="string"),
])

rels = [
    Relationship("orders", "customers", on=("customer_id", "id"), type="many_to_one"),
]

# Build the dashboard
dash = Dashboard(
    title="Weekly Business Review",
    entities=[orders, customers],
    relationships=rels,
    output="output/weekly.md",
)

dash.filter("date_range", dimension="orders.date", default="last_30_days")

dash.section("Key Metrics")
dash.tile("orders.revenue", compare="previous_period")
dash.tile("orders.count", compare="previous_period")

dash.section("Revenue by Segment")
dash.tile("orders.revenue", by="customers.segment", type="bar_chart")

# Raw SQL tiles — full DuckDB power inside dashboards
dash.section("Custom Analysis")
dash.tile_sql("Top Customers", """
    SELECT c.name, SUM(o.amount) AS total
    FROM orders o JOIN customers c ON o.customer_id = c.id
    GROUP BY 1 ORDER BY 2 DESC LIMIT 5
""")

dash.save()  # → output/weekly.md

Connectors

Connectors are the universal integration layer. A connector bundles everything needed to analyze a data domain: data sources, cleaning, entity definitions (dimensions/measures), relationships, and pre-built dashboard widgets.

Composable by design

Multiple connectors install into one Analyst and work together:

from dashboardmd import Analyst, Relationship
from dashboardmd.connectors import MetabaseConnector

analyst = Analyst()

# BI platform connector — import your existing Metabase model
analyst.use(MetabaseConnector(metabase_metadata))

# Community connector — pip install dashboardmd-github
analyst.use(GitHubConnector(token="...", repo="org/repo"))

# Custom connector — your own data
analyst.use(MyInternalConnector(api_key="..."))

# Cross-connector joins — link data across boundaries
analyst.add_relationship(Relationship(
    "orders", "pull_requests", on=("id", "order_id"), type="one_to_many"
))

# Query across everything as one system
analyst.query(
    measures=["orders.revenue"],
    dimensions=["pull_requests.author"],
)

BI Platform Connectors (built-in)

Import data models from any BI platform. They implement the same Connector interface, so they compose with data connectors:

from dashboardmd import Analyst
from dashboardmd.connectors import MetabaseConnector, LookMLConnector, CubeConnector, PowerBIConnector

# Import from Metabase
analyst = Analyst()
analyst.use(MetabaseConnector(metabase_metadata_dict))

# Import from LookML / Looker
analyst.use(LookMLConnector(lookml_model_dict))

# Import from Cube.js
analyst.use(CubeConnector(cube_schema_dict))

# Import from PowerBI
analyst.use(PowerBIConnector(powerbi_model_dict))

Custom Connectors

Build your own connector for any data domain:

from dashboardmd import Connector, DashboardWidget, Entity, Dimension, Measure
from dashboardmd.sources.base import SourceHandler

class MyAPISource(SourceHandler):
    def __init__(self, url, token):
        self.url = url
        self.token = token

    def register(self, conn, table_name):
        rows = self._fetch()           # your API logic
        rows = self._clean(rows)       # your cleaning logic
        self._register_rows(conn, table_name, rows)  # built-in helper

    def describe(self):
        return {"columns": []}

class MyConnector(Connector):
    def __init__(self, api_key):
        self.api_key = api_key

    def name(self):
        return "my_service"

    def sources(self):
        return {"events": MyAPISource("https://api.example.com/events", self.api_key)}

    def entities(self):
        return [Entity("events", dimensions=[
            Dimension("id", type="number", primary_key=True),
            Dimension("type", type="string"),
            Dimension("timestamp", type="time"),
        ], measures=[
            Measure("count", type="count"),
        ])]

    def widgets(self):
        return [DashboardWidget(
            name="Overview",
            title="Event Analytics",
            requires=["events"],
            build=self._build_overview,
        )]

    def _build_overview(self, dash):
        dash.section("Events")
        dash.tile("events.count", by="events.type")

# Use it
analyst = Analyst()
analyst.use(MyConnector(api_key="..."))

Multi-Connector Dashboards

Connectors contribute widgets to shared dashboards:

from dashboardmd import Analyst, Dashboard, Relationship

analyst = Analyst()
analyst.use(project_connector)
analyst.use(team_connector)

# Cross-connector relationship
analyst.add_relationship(Relationship(
    "tasks", "team_members", on=("assignee", "username"), type="many_to_one"
))

# Build unified dashboard with widgets from both connectors
dash = Dashboard(title="Engineering Velocity", analyst=analyst, output="velocity.md")
project_connector.contribute_widgets(dash, ["Project Status"])
team_connector.contribute_widgets(dash, ["Team Overview"])

# Add custom cross-connector analysis
dash.section("Cross-Team Insights")
dash.tile_sql("Hours by Department", """
    SELECT tm.department, SUM(tl.hours) as total
    FROM time_logs tl JOIN team_members tm ON tl.username = tm.username
    GROUP BY 1 ORDER BY 2 DESC
""")

dash.save()

Concept Mapping

Concept Looker PowerBI Cube Metabase dashboardmd
Logical table View Table Cube Table Entity
Attribute dimension Column dimension Column Dimension
Aggregation measure DAX Measure measure Metric Measure
Table link explore + join Relationship joins FK Relationship
Query Explore query Visual query /load API Question Query
Dashboard Dashboard + tiles Report + visuals (frontend) Dashboard + cards Dashboard + Tiles
Integration Connector

CLI

dashboardmd discover data/          # Auto-discover entities from data files
dashboardmd query data/ "SELECT COUNT(*) FROM orders"   # Run SQL against data
dashboardmd run dashboard.py        # Execute a dashboard script

Development

# Install in development mode
make install

# Run tests
make test

# Run linter + type checker + tests
make check

Project Status

dashboardmd is in early development (v0.1.0). See the design proposal for the full vision and implementation plan.

License

MIT

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

dashboardmd-0.1.0.tar.gz (747.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dashboardmd-0.1.0-py3-none-any.whl (44.5 kB view details)

Uploaded Python 3

File details

Details for the file dashboardmd-0.1.0.tar.gz.

File metadata

  • Download URL: dashboardmd-0.1.0.tar.gz
  • Upload date:
  • Size: 747.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dashboardmd-0.1.0.tar.gz
Algorithm Hash digest
SHA256 271d25ddcd3a7afa152a702d7fccc9f9df0d747386acf80ac486c7335303b20f
MD5 f93aa00c1658445ae0c647b1a5c524ba
BLAKE2b-256 8b3d1294eb3104b61483cdee4bdefa25d1406ea30fdb83363d8587ac4fbf6c8e

See more details on using hashes here.

Provenance

The following attestation bundles were made for dashboardmd-0.1.0.tar.gz:

Publisher: release.yml on minhlucvan/dashboardmd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dashboardmd-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dashboardmd-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 44.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dashboardmd-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7cbe75f738ee6110977056c74da769c498d9228b5c9d9bb635255882275c9efe
MD5 3d80df8b7c85b601880c4f144a5869d3
BLAKE2b-256 ce4af66579e25ee9a73375cd7538d1b9bd98877d82754a10a6043d3bbb0da0c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for dashboardmd-0.1.0-py3-none-any.whl:

Publisher: release.yml on minhlucvan/dashboardmd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page