Dashboard Development Guide
Dashboards are the visualization layer of the coomia-dip platform, transforming Ontology data and metrics into interactive charts and reports. This guide covers building dashboards using YAML and the Python SDK, including layout design, data source binding, chart configuration, interactive linking, permission control, and real-time refresh.
“Series: S12 Developer Tutorials · Article 10 | Level: Intermediate | Reading Time: 15 min
Dashboard Development Guide
#TL;DR
Dashboards are the visualization layer of the coomia-dip platform, transforming Ontology data and metrics into interactive charts and reports. This guide covers building dashboards using YAML and the Python SDK, including layout design, data source binding, chart configuration, interactive linking, permission control, and real-time refresh.
#1. Dashboard Overview
#1.1 Architecture
┌─────────────────────────────────────┐
│ Dashboard Runtime │
│ (Frontend - React/Vue) │
├─────────────────────────────────────┤
│ Layout Engine │ Widget Registry │
│ Filter Engine │ Theme Manager │
└────────┬────────────────┬───────────┘
│ gRPC/WebSocket │
▼ ▼
┌─────────────────┐ ┌────────────────┐
│ Control Layer │ │ Data Layer │
│ (Metric API) │ │ (OQL Query) │
└─────────────────┘ └────────────────┘
#1.2 Core Concepts
| Concept | Description |
|---|---|
| Dashboard | A container holding multiple Widgets |
| Widget | Visual components: charts, tables, metric cards |
| DataSource | Data binding to metrics or OQL queries |
| Filter | Global/local filters with linked interactions |
| Layout | Grid-based positioning system |
#2. Creating a Dashboard
#2.1 YAML Declaration
# dashboards/sales_overview.yaml
name: sales_overview
display_name: Sales Overview Dashboard
description: Real-time display of core sales metrics and trends
category: sales
owner: sales-team
refresh_interval: 300
theme:
primary_color: "#1890ff"
chart_palette: ["#1890ff", "#52c41a", "#faad14", "#f5222d", "#722ed1"]
permissions:
view: [sales-team, management]
edit: [sales-admin]
filters:
- name: time_range
type: date_range
default: last_30_days
position: header
- name: region
type: select
source: "FIND Region SELECT name, code ORDER BY name"
multiple: true
position: header
- name: product_category
type: select
source: "FIND ProductCategory SELECT name, code"
multiple: true
position: header
layout:
columns: 24
row_height: 60
widgets:
# Row 1: Core Metric Cards
- name: total_revenue_card
type: metric_card
position: {x: 0, y: 0, w: 6, h: 2}
config:
metric: total_revenue
format: "currency"
comparison: month_over_month
trend: true
icon: dollar
- name: order_count_card
type: metric_card
position: {x: 6, y: 0, w: 6, h: 2}
config:
metric: order_count
format: "number"
comparison: month_over_month
icon: shopping-cart
- name: avg_order_value_card
type: metric_card
position: {x: 12, y: 0, w: 6, h: 2}
config:
metric: avg_order_value
format: "currency"
comparison: month_over_month
icon: bar-chart
- name: customer_count_card
type: metric_card
position: {x: 18, y: 0, w: 6, h: 2}
config:
metric: active_customer_count
format: "number"
comparison: month_over_month
icon: team
# Row 2: Trend Chart and Pie Chart
- name: revenue_trend
type: line_chart
position: {x: 0, y: 2, w: 16, h: 4}
config:
title: Revenue Trend
data_source:
metric: total_revenue
granularity: day
apply_filters: [time_range, region]
series:
- name: Current Period
color: "#1890ff"
- name: Previous Period
type: comparison
period: previous_period
style: dashed
color: "#d9d9d9"
axes:
x: { type: time, format: "MM-DD" }
y: { type: value, format: "currency_short" }
- name: region_pie
type: pie_chart
position: {x: 16, y: 2, w: 8, h: 4}
config:
title: Revenue by Region
data_source:
metric: total_revenue
dimension: region
apply_filters: [time_range]
show_percentage: true
show_legend: true
# Row 3: Bar Chart and Ranking Table
- name: product_bar
type: bar_chart
position: {x: 0, y: 6, w: 12, h: 4}
config:
title: Sales by Product Category
data_source:
metric: total_revenue
dimension: product_category
apply_filters: [time_range, region]
orientation: horizontal
sort: desc
show_value: true
- name: top_customers
type: table
position: {x: 12, y: 6, w: 12, h: 4}
config:
title: Top 10 Customers
data_source:
type: oql
query: |
FIND Customer
INCLUDE
TRAVERSE serves <- Project <- Order
WHERE Order.status = 'completed'
AGGREGATE SUM(Order.total_amount) AS revenue, COUNT(*) AS order_count
SELECT Customer.name, Customer.tier, revenue, order_count
ORDER BY revenue DESC
LIMIT 10
apply_filters: [time_range]
columns:
- { field: name, title: Customer Name, width: 200 }
- { field: tier, title: Tier, width: 80, render: tag }
- { field: revenue, title: Total Revenue, width: 120, format: currency }
- { field: order_count, title: Orders, width: 80, align: center }
#2.2 Python API Creation
from ontology_sdk import OntoPlatform
from ontology_sdk.dashboard import (
DashboardBuilder, MetricCard, LineChart, PieChart,
BarChart, Table, Filter, Layout
)
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
dashboard = (
DashboardBuilder("sales_overview")
.display_name("Sales Overview Dashboard")
.category("sales")
.refresh_interval(300)
.filter(Filter.date_range("time_range", default="last_30_days"))
.filter(Filter.select("region", source="FIND Region SELECT name, code", multiple=True))
# Metric cards
.widget(
MetricCard("total_revenue_card")
.metric("total_revenue")
.format("currency")
.comparison("month_over_month")
.position(0, 0, 6, 2)
)
.widget(
MetricCard("order_count_card")
.metric("order_count")
.format("number")
.comparison("month_over_month")
.position(6, 0, 6, 2)
)
# Trend line chart
.widget(
LineChart("revenue_trend")
.title("Revenue Trend")
.metric("total_revenue", granularity="day")
.comparison_series("previous_period")
.apply_filters(["time_range", "region"])
.position(0, 2, 16, 4)
)
# Pie chart
.widget(
PieChart("region_pie")
.title("Revenue by Region")
.metric("total_revenue", dimension="region")
.show_percentage(True)
.position(16, 2, 8, 4)
)
# Bar chart
.widget(
BarChart("product_bar")
.title("Sales by Product Category")
.metric("total_revenue", dimension="product_category")
.orientation("horizontal")
.sort("desc")
.position(0, 6, 12, 4)
)
# Table
.widget(
Table("top_customers")
.title("Top 10 Customers")
.oql_source("""
FIND Customer
INCLUDE TRAVERSE serves <- Project <- Order
WHERE Order.status = 'completed'
AGGREGATE SUM(Order.total_amount) AS revenue
SELECT Customer.name, Customer.tier, revenue
ORDER BY revenue DESC LIMIT 10
""")
.columns([
{"field": "name", "title": "Customer Name"},
{"field": "tier", "title": "Tier", "render": "tag"},
{"field": "revenue", "title": "Total Revenue", "format": "currency"},
])
.position(12, 6, 12, 4)
)
.build()
)
platform.dashboards.register(dashboard)
print(f"Dashboard registered: {dashboard.name}")
#3. Widget Types in Detail
#3.1 Metric Card
card = (
MetricCard("revenue_card")
.metric("total_revenue")
.format("currency")
.comparison("month_over_month")
.trend(True)
.sparkline(True)
.threshold(
warning=1000000,
danger=500000,
direction="below"
)
.position(0, 0, 6, 2)
)
#3.2 Line Chart
line = (
LineChart("multi_metric_trend")
.title("Multi-Metric Trend Comparison")
.series("total_revenue", label="Revenue", color="#1890ff", y_axis="left")
.series("order_count", label="Orders", color="#52c41a", y_axis="right")
.series("avg_order_value", label="AOV", color="#faad14", y_axis="left")
.dual_y_axis(left_label="Amount ($)", right_label="Count")
.granularity("day")
.apply_filters(["time_range"])
.legend(position="top")
.tooltip(shared=True)
.position(0, 2, 24, 5)
)
#3.3 Map Chart
from ontology_sdk.dashboard import MapChart
geo_map = (
MapChart("revenue_map")
.title("National Revenue Distribution")
.map_type("world")
.metric("total_revenue", dimension="region")
.color_scale(["#e6f7ff", "#1890ff", "#003a8c"])
.show_labels(True)
.drill_down(enabled=True, levels=["country", "state", "city"])
.position(0, 10, 24, 6)
)
#3.4 Gauge
from ontology_sdk.dashboard import Gauge
completion_gauge = (
Gauge("project_completion")
.title("Overall Project Completion Rate")
.metric("project_completion_rate")
.format("percentage")
.ranges([
{"min": 0, "max": 60, "color": "#f5222d"},
{"min": 60, "max": 80, "color": "#faad14"},
{"min": 80, "max": 100, "color": "#52c41a"},
])
.position(0, 16, 8, 4)
)
#4. Interactions and Linking
#4.1 Global Filter Linking
filters:
- name: department
type: cascade
levels:
- source: "FIND BusinessUnit SELECT name, code"
label: Business Unit
- source: "FIND Department WHERE business_unit = :parent SELECT name, code"
label: Department
- source: "FIND Team WHERE department = :parent SELECT name, code"
label: Team
cascade: true
position: header
#4.2 Widget-to-Widget Interaction
# Click pie chart region -> filter table data
dashboard_builder.interaction(
source_widget="region_pie",
event="click",
target_widget="top_customers",
action="filter",
mapping={"region": "$clicked.dimension_value"}
)
# Select table row -> show detail panel
dashboard_builder.interaction(
source_widget="top_customers",
event="row_click",
target_widget="customer_detail_panel",
action="load_detail",
mapping={"customer_rid": "$row.rid"}
)
#4.3 Drill-Down Analysis
line_chart = (
LineChart("revenue_trend")
.title("Revenue Trend")
.metric("total_revenue", granularity="month")
.drill_down(
levels=["month", "week", "day"],
animation=True
)
.position(0, 2, 16, 4)
)
#5. Real-Time Dashboards
#5.1 WebSocket Real-Time Push
from ontology_sdk.dashboard import RealtimeDashboard
realtime = (
RealtimeDashboard("ops_monitor")
.display_name("Operations Monitoring Screen")
.refresh_mode("realtime")
.websocket_config(
url="ws://data-Layer:8081/ws/metrics",
reconnect_interval=5
)
.widget(
MetricCard("current_qps")
.metric("realtime_request_rate")
.format("number")
.suffix("/s")
.realtime(True)
.position(0, 0, 6, 2)
)
.widget(
LineChart("qps_trend")
.title("Real-time QPS Trend")
.metric("realtime_request_rate")
.granularity("1m")
.rolling_window("30m")
.realtime(True)
.position(0, 2, 24, 4)
)
.build()
)
#6. Dashboard Templates
#6.1 Built-in Templates
# Create from template
dashboard = platform.dashboards.create_from_template(
template="executive_overview",
name="ceo_dashboard",
config={
"metrics": {
"primary_revenue": "total_revenue",
"primary_cost": "total_cost",
"primary_count": "order_count",
},
"dimensions": {
"region": "customer.region",
"category": "product.category",
}
}
)
# List available templates
templates = platform.dashboards.list_templates()
for t in templates:
print(f"{t.name}: {t.description} (Widgets: {t.widget_count})")
#6.2 Export as Template
platform.dashboards.export_as_template(
dashboard_name="sales_overview",
template_name="sales_dashboard_template",
parameterize=["metrics", "dimensions", "filters"]
)
#7. Permission Control
from ontology_sdk.dashboard import DashboardPermission
platform.dashboards.set_permissions(
"sales_overview",
permissions=[
DashboardPermission(role="sales-admin", level="edit"),
DashboardPermission(role="sales-team", level="view"),
DashboardPermission(role="management", level="view"),
DashboardPermission(
role="regional-manager",
level="view",
row_filter={"region": "$user.region"} # Row-level data permission
),
]
)
#8. Export and Sharing
# Export as PDF
pdf_bytes = platform.dashboards.export(
"sales_overview",
format="pdf",
filters={"time_range": "2025-01-01,2025-03-31"},
paper_size="A3",
orientation="landscape"
)
with open("sales_report_Q1.pdf", "wb") as f:
f.write(pdf_bytes)
# Generate share link
share_link = platform.dashboards.share(
"sales_overview",
expires_in="7d",
password="optional-password",
filters_locked=True
)
print(f"Share link: {share_link.url}")
# Schedule email reports
platform.dashboards.schedule_report(
"sales_overview",
schedule="0 9 * * 1", # Every Monday at 9 AM
format="pdf",
recipients=["management@company.com"],
subject="Weekly Sales Report"
)
#9. Complete Example: Project Management Dashboard
from ontology_sdk import OntoPlatform
from ontology_sdk.dashboard import (
DashboardBuilder, MetricCard, LineChart, BarChart,
Table, PieChart, Filter, Gauge
)
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
dashboard = (
DashboardBuilder("project_management")
.display_name("Project Management Dashboard")
.category("project")
.refresh_interval(600)
# Filters
.filter(Filter.date_range("time_range", default="last_90_days"))
.filter(Filter.select("department", source="FIND Department SELECT name"))
.filter(Filter.select("status", options=["planning", "in_progress", "done", "paused"]))
# Row 1: Core metrics
.widget(MetricCard("active_projects").metric("active_project_count").position(0, 0, 6, 2))
.widget(MetricCard("completion_rate").metric("project_completion_rate").format("percentage").position(6, 0, 6, 2))
.widget(MetricCard("overdue_tasks").metric("overdue_task_count").threshold(danger=10).position(12, 0, 6, 2))
.widget(MetricCard("team_velocity").metric("avg_team_velocity").position(18, 0, 6, 2))
# Row 2: Status distribution + completion trend
.widget(
PieChart("status_distribution")
.title("Project Status Distribution")
.oql_source("FIND Project GROUP BY status AGGREGATE COUNT(*) AS count")
.position(0, 2, 8, 4)
)
.widget(
LineChart("completion_trend")
.title("Task Completion Trend")
.metric("completed_task_count", granularity="week")
.comparison_series("previous_period")
.position(8, 2, 16, 4)
)
# Row 3: Department workload + project list
.widget(
BarChart("dept_workload")
.title("Department Task Load")
.oql_source("""
FIND Task WHERE status != 'done'
TRAVERSE assigned_to -> Employee
TRAVERSE works_in -> Department
GROUP BY Department.name
AGGREGATE COUNT(*) AS pending_tasks
""")
.position(0, 6, 10, 4)
)
.widget(
Table("project_list")
.title("Project Progress Details")
.oql_source("""
FIND Project
WHERE status IN ('planning', 'in_progress')
INCLUDE TRAVERSE has_task -> Task
AGGREGATE COUNT(*) AS total, COUNT(CASE WHEN Task.status='done' THEN 1 END) AS done
SELECT name, status, priority, end_date, total, done
ORDER BY end_date ASC
""")
.columns([
{"field": "name", "title": "Project Name", "width": 200},
{"field": "status", "title": "Status", "render": "tag"},
{"field": "priority", "title": "Priority", "render": "tag"},
{"field": "end_date", "title": "Due Date"},
{"field": "progress", "title": "Progress", "render": "progress_bar",
"computed": "done / total * 100"},
])
.position(10, 6, 14, 4)
)
.build()
)
platform.dashboards.register(dashboard)
url = platform.dashboards.get_url("project_management")
print(f"Dashboard URL: {url}")
#Key Takeaways
- Declarative first: YAML for layout and data binding, Python API for complex interactions
- Flexible data sources: Both metric queries and OQL queries as data sources
- Interactive linking: Global filters, widget-to-widget linking, and drill-down analysis create a complete analytics experience
- Real-time capability: WebSocket push enables second-level refresh for monitoring screens
- Layered permissions: Dashboard-level view/edit permissions plus row-level data permissions
- Share and export: PDF export, share links, and scheduled reports
#Next Article
Next: S12-11 Permission Configuration Guide — Learn coomia-dip's three-layer permission model: RBAC + ABAC + Row-Level Security.
Tags: Dashboard Visualization Charts Reports Real-time Monitoring coomia-dip