Core Concepts

Understanding the key concepts of Dashboard Lego will help you build better dashboards.

Modular Architecture

Dashboard Lego is built around the concept of modular, reusable components called “blocks”. Each block is a self-contained unit that:

  • Displays specific content (KPIs, charts, text)

  • Manages its own data requirements

  • Can interact with other blocks through state management

  • Can be easily combined to create complex dashboards

Block Types

BaseBlock

All blocks inherit from BaseBlock, which provides:

  • Unique identification system

  • State management integration

  • Layout and styling capabilities

  • Callback registration

Chart Blocks

  • TypedChartBlock: Unified chart block for both static and interactive charts (v0.15+) - Use without controls for static charts - Use with controls parameter for interactive charts

  • MinimalChartBlock: Minimalist chart block for clean visualizations (v0.15.2+)

Data Display Blocks

  • get_metric_row(): Factory function to create metric blocks for KPIs (v0.15+)

  • SingleMetricBlock: Individual metric display block

  • TextBlock: Text content and markdown

Data Sources

Data sources abstract data loading and provide a consistent interface for blocks using composition pattern (v0.15+). They handle:

  • Data loading from various sources (CSV, Parquet, SQL, etc.) via DataBuilder

  • Data transformation (filtering, aggregation) via DataTransformer

  • Caching for performance at each pipeline stage

  • Stateless 2-stage pipeline: Build → Transform

State Management

Dashboard Lego uses a publish-subscribe pattern for block interaction:

  • Publishers: Blocks that emit state changes (e.g., filter selections)

  • Subscribers: Blocks that react to state changes (e.g., charts that update)

  • StateManager: Central coordinator that manages state flow

Example of state flow:

from dashboard_lego.blocks import TypedChartBlock, get_metric_row, Control
import dash_core_components as dcc

# Block A publishes filter state
interactive_chart = TypedChartBlock(
    block_id="filter_chart",
    datasource=datasource,
    plot_type="bar",
    plot_params={"x": "{{category}}", "y": "Sales"},
    controls={"category": Control(component=dcc.Dropdown, props={"options": [...]})}
)

# Block B subscribes to filter state
metrics, row_opts = get_metric_row(
    metrics_spec={
        "total_sales": {
            "column": "Sales",
            "agg": "sum",
            "title": "Total Sales",
            "color": "success"
        }
    },
    datasource=datasource,
    subscribes_to="filter_chart-category"  # Subscribes to category filter
)

Layout System

Dashboard Lego uses a flexible grid system based on Bootstrap:

  • Rows: Horizontal groups of blocks

  • Columns: Bootstrap grid columns (1-12 width)

  • Responsive: Different layouts for different screen sizes

  • Presets: Pre-built layout patterns for common arrangements

Example layout:

# Two-column layout: 8 columns + 4 columns
metrics, row_opts = get_metric_row(...)
layout = [
    [(chart_block, {'md': 8}), (metrics[0], {'md': 4})]
]

Presets

Presets are pre-built blocks for common use cases:

  • EDA Presets: Exploratory data analysis visualizations

  • ML Presets: Machine learning model visualizations

  • Layout Presets: Common dashboard arrangements

Block-Level Data Transformations

Dashboard Lego v0.15.0 introduces block-specific data transformations, allowing each block to apply custom transformations (aggregation, filtering, pivoting) to the data it displays without affecting other blocks.

Overview

The transform_fn parameter enables blocks to define their own data transformation logic that executes after the global data pipeline. This allows for:

  • Block-specific aggregations (groupby, pivot tables)

  • Custom filtering without affecting other blocks

  • Data reshaping for specific visualizations

  • Complex multi-step transformations

Data Flow

The complete data pipeline with block transforms:

1. Data Builder (load + process)
       ↓
2. Global Filter (optional)
       ↓
3. Block Transform (if specified) ← NEW in v0.15.0
       ↓
4. Block Rendering

Each block with a transform_fn gets a specialized datasource that chains the transform after the global filter.

Basic Usage

from dashboard_lego.blocks.typed_chart import TypedChartBlock

# Block without transform - shows raw data
raw_chart = TypedChartBlock(
    block_id="raw_sales",
    datasource=datasource,
    plot_type='scatter',
    plot_params={'x': 'date', 'y': 'sales'}
)

# Block with aggregation transform
aggregated_chart = TypedChartBlock(
    block_id="category_totals",
    datasource=datasource,
    plot_type='bar',
    plot_params={'x': 'category', 'y': 'total_sales'},
    transform_fn=lambda df: df.groupby('category')['sales'].sum().reset_index(name='total_sales')
)

Common Patterns

Aggregation:

# Group by category and sum sales
transform_fn=lambda df: df.groupby('category')['sales'].sum().reset_index()

Filtering:

# Show only high-value transactions
transform_fn=lambda df: df[df['sales'] > 1000]

Pivot Tables:

# Create category × region matrix
transform_fn=lambda df: df.pivot_table(
    index='category',
    columns='region',
    values='sales',
    aggfunc='mean'
)

Complex Multi-Step:

def complex_transform(df):
    # Step 1: Filter
    filtered = df[df['category'] == 'Electronics']
    # Step 2: Aggregate
    grouped = filtered.groupby('region')['sales'].sum()
    # Step 3: Calculate metrics
    return grouped.reset_index(name='total_sales')

transform_fn=complex_transform

Key Concepts

Immutability:

The original datasource is never modified. Each block with a transform_fn gets an independent specialized clone.

Order Matters:

Transforms execute in order: Build → Global Filter → Block Transform

Independence:

Multiple blocks can have different transforms on the same datasource without interfering with each other.

Caching:

Each specialized datasource maintains independent cache keys, so transforms are only computed once.

Example Scenarios

Scenario 1: Different Aggregations

# Dashboard showing same data aggregated different ways
sales_by_category = TypedChartBlock(
    block_id="by_category",
    datasource=datasource,
    plot_type='bar',
    plot_params={'x': 'category', 'y': 'total'},
    transform_fn=lambda df: df.groupby('category')['sales'].sum().reset_index(name='total')
)

sales_by_region = TypedChartBlock(
    block_id="by_region",
    datasource=datasource,
    plot_type='bar',
    plot_params={'x': 'region', 'y': 'total'},
    transform_fn=lambda df: df.groupby('region')['sales'].sum().reset_index(name='total')
)

Scenario 2: With Global Filters

# Global filter applies first, then block transform
datasource = DataSource(
    data_builder=builder,
    data_transformer=DateRangeFilter()  # Global filter
)

# This block will:
# 1. Apply DateRangeFilter (global)
# 2. Then aggregate by category (block-specific)
chart = TypedChartBlock(
    block_id="filtered_totals",
    datasource=datasource,
    plot_type='bar',
    plot_params={'x': 'category', 'y': 'total'},
    transform_fn=lambda df: df.groupby('category')['sales'].sum().reset_index(name='total')
)

Best Practices

Block Design

  • Keep blocks focused on a single responsibility

  • Use meaningful block IDs

  • Implement proper error handling

  • Document data requirements

State Management

  • Use descriptive state names

  • Avoid circular dependencies

  • Group related state changes

  • Handle state initialization properly

Data Transformations

  • Keep transform functions simple and readable

  • Use descriptive lambda names for complex transforms

  • Consider extracting complex transforms to named functions

  • Remember: transforms execute after global filters

  • Test transforms independently before adding to blocks

Performance

  • Use data source caching

  • Implement efficient data filtering

  • Minimize callback complexity

  • Use appropriate chart types for data size

  • Block transforms are cached automatically

Layout Design

  • Use layout presets when possible

  • Consider responsive design

  • Group related blocks together

  • Maintain consistent spacing and alignment