Dashboard YAML Management¶
Depictio supports managing dashboards as human-readable YAML files using the depictio-cli command-line tool. This enables Infrastructure-as-Code (IaC) workflows, version control integration, and reproducible dashboard deployments.
Implementation Reference
The DashboardDataLite model and CLI dashboard commands were introduced in PR #663. Domain validation (enum constraints, cross-field rules, server schema checks) was added in PR #684.
Overview¶
┌─────────────────┐ ┌─────────────────┐
│ YAML Files │ depictio-cli import │ MongoDB │
│ (version │ ─────────────────────▶ │ Dashboard │
│ controlled) │ │ │
│ │ depictio-cli export │ │
│ │ ◀───────────────────── │ │
└─────────────────┘ └─────────────────┘
Key Benefits:
- Version Control: Track dashboard changes in Git with meaningful diffs
- Infrastructure-as-Code: Manage dashboards alongside your project configuration
- Human-Readable Format: Edit dashboards directly in YAML (60-80 lines vs 500+ in MongoDB)
- Reproducible Deployments: Import dashboards to any Depictio instance
- Early Validation: Catch invalid field values and incompatible combinations before importing
CLI Commands¶
The depictio-cli dashboard command group provides three commands for YAML management:
| Command | Description | Server Required |
|---|---|---|
validate |
Validate YAML (schema + server schema) | Optional (for Pass 2) |
import |
Import YAML to server | Yes (unless --dry-run) |
export |
Export dashboard to YAML | Yes |
Validate¶
Validate a dashboard YAML file. Runs in two passes:
- Pass 1 — schema + domain (always, no server required): checks required fields, enum values (
visu_type,column_type), and cross-field rules (aggregation × column_type, interactive_type × column_type, mode/code_content). - Pass 2 — server schema (default when
--configis provided): resolves each component'sworkflow_tag+data_collection_tagagainst the live delta table schema, checks thatcolumn_nameexists, and validates aggregation/interactive type against the inferred column type. Skip with--offline.
| Option | Description |
|---|---|
--config, -c |
Path to CLI config file (enables server schema validation — Pass 2) |
--offline |
Skip server schema check (Pass 1 only — useful without server access) |
--verbose, -v |
Show detailed validation output |
--api |
API base URL (default: from config) |
Examples:
# Schema + domain only (no server needed)
depictio-cli dashboard validate my_dashboard.yaml
# Full validation including server column check
depictio-cli dashboard validate my_dashboard.yaml --config ~/.depictio/admin_config.yaml
# Force offline even when config is provided
depictio-cli dashboard validate my_dashboard.yaml --config ~/.depictio/admin_config.yaml --offline
Example Output (all passes OK):
Validating: my_dashboard.yaml Pass 1: schema + domain constraints ✓ Schema + domain OK Pass 2: server schema validation ✓ Server schema OK ✓ Validation passed
Example Output (domain error — invalid visu_type):
Validating: my_dashboard.yaml Pass 1: schema + domain constraints ✗ Schema/domain validation failed Validation Errors ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Component ┃ Field ┃ Message ┃ ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ pie-chart │ - │ Invalid visu_type 'pie' for mode='ui'. │ │ │ │ Valid values: scatter, line, bar, box, histogram │ │ treemap-chart │ - │ Invalid visu_type 'treemap' for mode='ui'. │ │ │ │ Valid values: scatter, line, bar, box, histogram │ └───────────────┴───────────┴────────────────────────────────────────────────────┘
Import¶
Import a dashboard YAML file to the server. Always runs schema + domain validation first (Pass 1). Also runs server schema validation by default (Pass 2) — skip with --offline.
| Option | Description |
|---|---|
--config, -c |
Path to CLI config file (required unless --dry-run) |
--project, -p |
Project ID (overrides project_tag in YAML) |
--overwrite |
Update existing dashboard with same title |
--dry-run |
Validate schema + domain only, don't import (no server needed) |
--offline |
Skip server schema check (column names not verified) |
--api |
API base URL (default: from config) |
Validation before import
dashboard import always validates your YAML before sending it to the server. A failed validation aborts the import — you never import a dashboard that fails schema or domain checks.
Examples:
# Schema + domain validation only (no config, no import)
depictio-cli dashboard import dashboard.yaml --dry-run
# Full validation + import (server schema check runs by default)
depictio-cli dashboard import dashboard.yaml --config ~/.depictio/admin_config.yaml
# Import without server schema check
depictio-cli dashboard import dashboard.yaml --config ~/.depictio/admin_config.yaml --offline
# Update existing dashboard with same title
depictio-cli dashboard import dashboard.yaml --config ~/.depictio/admin_config.yaml --overwrite
# Override project from YAML
depictio-cli dashboard import dashboard.yaml --config ~/.depictio/admin_config.yaml --project 646b0f3c1e4a2d7f8e5b8c9a
Example Output:
Validating: dashboard.yaml ✓ Validation passed Title: Iris Dashboard Demo Components: 7 Project: Iris_Dataset_Project (from YAML project_tag) Loading CLI configuration... ✓ Configuration loaded API URL: localhost:8058 Importing dashboard (project: Iris_Dataset_Project)... ✓ Dashboard imported successfully! Dashboard ID: 6824cb3b89d2b72169309737 Title: Iris Dashboard Demo Project ID: 650a1b2c3d4e5f6a7b8c9d0e View at: localhost:8058/dashboard/6824cb3b89d2b72169309737
Export¶
Export a dashboard from the server to a YAML file.
| Option | Description |
|---|---|
--config, -c |
Path to CLI config file (required) |
--output, -o |
Output file path (default: dashboard.yaml) |
--api |
API base URL (default: from config) |
Examples:
# Export to default file
depictio-cli dashboard export 6824cb3b89d2b72169309737 --config ~/.depictio/admin_config.yaml
# Export to specific file
depictio-cli dashboard export 6824cb3b89d2b72169309737 --config ~/.depictio/admin_config.yaml -o iris_dashboard.yaml
YAML Format¶
DashboardDataLite Structure¶
The lite format is designed for human readability:
title: Dashboard Title
subtitle: Optional subtitle
project_tag: Project_Name
grid_sections: [] # optional — see Dashboard Sections below
filter_sections: [] # optional
components:
- tag: component-identifier
component_type: figure|card|text|interactive|table|image|multiqc|map|advanced_viz
workflow_tag: engine/workflow_name
data_collection_tag: dc_tag
section: Section Name # optional — the section this component belongs to
# Component-specific fields...
Dashboard Sections (v1.4.0+)¶
Two independent lists group a dashboard into named, foldable sections: grid_sections
organises the main canvas, filter_sections organises the left filter panel. A component
joins one by naming it in its own section field.
grid_sections:
- name: Cohort
icon: mdi:counter
color: teal
description: How many samples, and of what
collapsed: false
- name: Quality control
icon: mdi:check-decagram
color: orange
collapsed: true
filter_sections:
- name: Sample
icon: mdi:test-tube
color: blue
components:
- tag: sample-count
component_type: card
section: Cohort
# ...
- tag: habitat-filter
component_type: interactive
section: Sample
# ...
| Field | Type | Default | Description |
|---|---|---|---|
name |
str | required | Matched against each component's section |
icon |
str | null |
Iconify id, drawn in the section header |
color |
str | null |
Mantine palette name (teal, orange, …). An unknown name falls back to the theme default rather than failing the import |
description |
str | null |
Hint line under the header |
collapsed |
bool | false |
Start folded |
persistent |
bool | false |
Render on every tab of the dashboard (v1.6.0+) |
pin |
str | top |
top or bottom: which edge a persistent section sits at. Ignored unless persistent (v1.6.0+) |
Both lists default to empty, so a dashboard that declares no sections renders exactly the flat grid it did before.
What section accepts
sectionis valid on every component type, not just interactive ones.- A component with no
sectionrenders above the first section. - Section specs reject unknown keys outright, so a typo fails the import rather than being silently ignored.
- An interactive
groupmay not span two sections — grouped controls must sit together, or the import fails with "Interactive component groups must sit in a single section". - Folding is not just visual: a folded section fetches nothing until you open it.
Sections on every tab (v1.6.0+)¶
persistent: true hands a section to the whole dashboard instead of the tab that declares
it. The flag is valid in both lists, and means something slightly different in each:
- a grid section renders on every other tab too, read-only, above or below that tab's own content;
- a filter section's controls join every tab's filter panel, and the values picked in them survive a tab switch.
pin chooses which edge it sits at, on every tab including the one that declares it:
top (the default) before that tab's own sections, bottom after them. bottom is what
a reference block usually wants: a raw-data table present everywhere without pushing
aside each tab's own introduction.
filter_sections:
- name: Variety
icon: mdi:filter-variant
color: blue
description: Which flowers to look at, on every tab
persistent: true # pin defaults to top
grid_sections:
- name: Raw Data
icon: mdi:table
color: gray
description: Per-flower records behind every figure
collapsed: true
persistent: true
pin: bottom
Only the declaring tab lists the section and its components; the other tabs say nothing about it and receive it automatically. This is the bundled Iris demo, whose Overview tab declares both of the above while Iris Petal Analysis declares neither and shows both.
How a persistent section behaves
- Sections are still matched by name, so two tabs may each declare a persistent section called Filters without colliding: identity is the declaring tab plus the list plus the name.
- A tab cannot edit a section it does not declare. In the editor the section's menu offers a jump to the tab that owns it instead.
- Folding is shared: folding a persistent section on one tab folds it on all of them.
pinaccepts onlytoporbottom; anything else fails the import.- Both keys round-trip through
dashboard exportunchanged. - Neither key does anything on a dashboard with a single tab.
Funnel filtering (v1.7.0+)¶
funnel_filtering is a dashboard-level boolean deciding whether the filter panel marks
which values still lead to a non-empty result. It defaults to true, so it only needs
writing when opting a dashboard out:
The key round-trips through dashboard export / import like any other dashboard field.
What the flag does and does not control
- It is the author's default, not a lock. The button in the filter panel flips funnelling for a single page view without writing anything, so a viewer with no edit rights can still turn it off, and a viewer turning it on cannot change what the next person sees.
- A dashboard saved before v1.7.0 has no such key. Readers test
!== falserather than truthiness, so an absent value inherits the funnel rather than falling throughundefinedto off; only an explicitfalseopts out. - It gates both affordances at once: the per-value highlighting and the funnel overview button.
See Funnel filtering for what it looks like in the panel.
Complete Example¶
title: Iris Dashboard Demo
subtitle: Sample analysis dashboard
project_tag: Iris_Dataset_Project
grid_sections: # optional — foldable groups in the main canvas
- name: Overview
icon: mdi:counter
color: teal
- name: Distributions
icon: mdi:chart-box
color: violet
filter_sections: # optional — foldable groups in the left filter panel
- name: Sample
icon: mdi:test-tube
color: blue
components:
# Figure: Box plot
- tag: box-variety-sepal-length
component_type: figure
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
section: Distributions
visu_type: box
dict_kwargs:
x: variety
y: sepal.length
color: variety
title: Sepal Length by Variety
# Figure: Scatter plot
- tag: scatter-sepal-petal
component_type: figure
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
section: Distributions
visu_type: scatter
dict_kwargs:
x: sepal.length
y: petal.length
color: variety
# Card: Metric with aggregation
- tag: sepal-length-average
component_type: card
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
section: Overview
aggregation: average
column_name: sepal.length
icon_name: mdi:leaf
icon_color: "#8BC34A"
# Interactive: MultiSelect filter
- tag: variety-filter
component_type: interactive
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
section: Sample
interactive_component_type: MultiSelect
column_name: variety
custom_color: "#858585"
# Interactive: RangeSlider filter
- tag: sepal-length-filter
component_type: interactive
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
section: Sample
interactive_component_type: RangeSlider
column_name: sepal.length
# Table: Data display
- tag: data-table
component_type: table
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
# Image: Gallery component
- tag: sample-gallery
component_type: image
workflow_tag: python/image_workflow
data_collection_tag: sample_images
image_column: image_path
thumbnail_size: 150
columns: 3
max_images: 9
# MultiQC: Quality control report
- tag: fastqc-quality
component_type: multiqc
workflow_tag: python/nf_workflow
data_collection_tag: multiqc_report
selected_module: fastqc
selected_plot: per_base_sequence_quality
# Figure: Clustered heatmap
- tag: gene-expression-heatmap
component_type: figure
workflow_tag: python/bio_workflow
data_collection_tag: expression_matrix
visu_type: heatmap
dict_kwargs:
index_column: gene_name
row_annotations: [gene_type]
cluster_rows: true
normalize: zscore
# Map: Scatter map with selection
- tag: sampling-map
component_type: map
workflow_tag: python/my_workflow
data_collection_tag: sample_metadata
lat_column: latitude
lon_column: longitude
color_column: biome
hover_columns: [sample_id, site_name]
map_style: carto-positron
selection_enabled: true
selection_column: sample_id
Component Types Reference¶
| Type | Description | Required Fields |
|---|---|---|
figure |
Plotly charts (scatter, box, heatmap, etc.) | visu_type (ui mode) or code_content (code mode) |
card |
Metric cards with aggregations | aggregation, column_name |
interactive |
Filters (RangeSlider, MultiSelect, etc.) | interactive_component_type, column_name |
table |
Data tables | (none required — title auto-generated from DC tag) |
text |
Headings and prose tiles | (none required — title is the heading, body the prose) |
image |
Image galleries from S3/MinIO | image_column |
multiqc |
MultiQC quality control report viewer | selected_module, selected_plot |
map |
Geospatial maps (scatter, density, choropleth) | lat_column, lon_column (scatter/density) or locations_column, GeoJSON source (choropleth) |
Figure Component¶
Two rendering modes are supported:
UI Mode (default) — select a chart type and pass Plotly Express parameters:
- tag: scatter-plot
component_type: figure
workflow_tag: python/workflow_name
data_collection_tag: table_dc
visu_type: scatter # see valid values below
dict_kwargs:
x: column_x
y: column_y
color: category_column
title: Chart Title
Valid visu_type values (UI mode): scatter, line, bar, box, histogram, heatmap
Code Mode — write arbitrary Python/Plotly code for full flexibility:
- tag: custom-plot
component_type: figure
workflow_tag: python/workflow_name
data_collection_tag: table_dc
mode: code
code_content: |
import plotly.express as px
fig = px.scatter_matrix(df, dimensions=["sepal.length", "sepal.width", "petal.length"])
ComplexHeatmap — clustered heatmap with annotations (via plotly-complexheatmap):
- tag: gene-expression-heatmap
component_type: figure
workflow_tag: python/workflow_name
data_collection_tag: expression_dc
visu_type: heatmap
dict_kwargs:
index_column: gene_name
value_columns: [sample_A, sample_B, sample_C]
row_annotations: [gene_type, pathway]
cluster_rows: true
cluster_cols: true
normalize: zscore
colorscale: RdBu_r
split_rows_by: gene_type
cluster_method: ward
cluster_metric: euclidean
Heatmap dict_kwargs parameters:
| Parameter | Type | Description |
|---|---|---|
index_column |
string | Column for row labels |
value_columns |
list | Numeric columns for the matrix (omit for all numeric) |
row_annotations |
list | Columns shown as colored side bars |
cluster_rows / cluster_cols |
bool | Enable hierarchical clustering |
normalize |
string | zscore, minmax, or none |
colorscale |
string | Plotly colorscale (e.g. RdBu_r, Viridis) |
split_rows_by |
string | Split heatmap rows by annotation column |
cluster_method |
string | ward, average, complete, single |
cluster_metric |
string | euclidean, correlation, cosine |
Code mode and visu_type
visu_type is not validated when mode: code. Any Plotly chart can be built in code mode. code_content must be non-empty when mode: code.
Selection filtering — enable lasso/box selection to filter linked components:
- tag: scatter-with-selection
component_type: figure
visu_type: scatter
selection_enabled: true
selection_column: sample_id # required when selection_enabled=true
# ...
Card Component¶
Single-metric card:
- tag: metric-card
component_type: card
workflow_tag: python/workflow_name
data_collection_tag: table_dc
aggregation: average
column_name: numeric_column
column_type: float64 # optional — enables offline aggregation validation
icon_name: mdi:chart-line
icon_color: "#2196F3"
Multi-metric summary card — secondary aggregations displayed below the hero value:
- tag: petal-length-summary
component_type: card
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
aggregation: average # hero metric (large display)
aggregations: # secondary metrics (compact rows)
- median
- std_dev
- min
- max
secondary_layout: grid # optional — how the block below the hero is drawn
column_name: petal.length
column_type: float64
icon_name: mdi:leaf
icon_color: "#43A047"
title: "Petal Length"
aggregations is read by the four list-driven layouts (vertical, the default;
compact; grid; box_plot). The other twelve secondary_layout values compute their
own block and ignore it — see the field table below.
Conditional aggregation — pre-filter data before computing metrics:
- tag: high-coverage-count
component_type: card
workflow_tag: python/samples_workflow
data_collection_tag: samples
aggregation: count
column_name: sample_id
column_type: object
filter_expr: "(col('coverage') >= 30) & (col('quality_score') > 80)"
icon_name: mdi:filter-check-outline
icon_color: "#F4511E"
title: "High-Quality Samples"
filter_expr accepts a Polars expression string. See Filter Expressions for the full reference.
Aggregation × column_type compatibility:
| column_type | Valid aggregations |
|---|---|
int64 |
count, nunique, sum, average, median, min, max, range, variance, std_dev, percentile, q1, q3, box_plot_stats, skewness, kurtosis |
float64 |
count, nunique, sum, average, median, min, max, range, variance, std_dev, percentile, q1, q3, box_plot_stats, skewness, kurtosis |
bool |
count, sum, min, max |
datetime |
count, min, max |
timedelta |
count, sum, min, max |
category |
count, mode |
object |
count, mode, nunique |
column_type is optional
If you omit column_type, validation against the compatibility table is skipped offline. When --config is provided, the column type is inferred from the server schema and used for validation automatically.
Secondary layout fields — secondary_layout picks how the block under the hero value is
drawn, and each layout reads one companion field. The full list of layouts and what they
render is in Components.
| Field | Type | Default | Read by |
|---|---|---|---|
secondary_layout |
str | vertical |
(picks the layout) — one of the 16 modes |
aggregations |
list[str] | null |
vertical, compact, grid, box_plot |
breakdown_col |
str | null |
top_n, concentration, composition, donut |
top_n_count |
int (1–5) | 3 |
top_n, concentration, composition, donut |
coverage_max |
float | null |
coverage, gauge |
threshold_value (v1.4.0+) |
float | null |
threshold — the QC cut-off; without it the strip is not drawn |
threshold_direction (v1.4.0+) |
min | max |
min |
threshold — min is at-least (coverage, %Q30), max is at-most (duplication, contamination) |
threshold_warn (v1.4.0+) |
float | null |
threshold — ignored unless on the failing side of threshold_value |
attrition_cols (v1.4.0+) |
list[str] | [] |
attrition — ordered stage columns after the card's own, never re-sorted by value |
trend_col (v1.4.0+) |
str | null |
trend — the ordered column the sparkline buckets along |
# Pass/warn/fail against a QC cut-off
- tag: mean-coverage
component_type: card
workflow_tag: python/samples_workflow
data_collection_tag: samples
aggregation: average
column_name: coverage
column_type: float64
secondary_layout: threshold
threshold_value: 30
threshold_warn: 20
threshold_direction: min
title: "Mean Coverage"
Interactive Component¶
# MultiSelect — for categorical/text columns
- tag: category-filter
component_type: interactive
workflow_tag: python/workflow_name
data_collection_tag: table_dc
interactive_component_type: MultiSelect
column_name: category
# RangeSlider — for numeric columns
- tag: numeric-filter
component_type: interactive
workflow_tag: python/workflow_name
data_collection_tag: table_dc
interactive_component_type: RangeSlider
column_name: value
column_type: float64 # optional — enables offline type compatibility check
# DateRangePicker — for datetime columns
- tag: date-filter
component_type: interactive
workflow_tag: python/workflow_name
data_collection_tag: table_dc
interactive_component_type: DateRangePicker
column_name: sample_date
Scoped interactive component — pre-filter data to restrict available options:
# Only show varieties present in rows where petal.length > 4
- tag: long-petal-variety-filter
component_type: interactive
workflow_tag: python/iris_workflow
data_collection_tag: iris_table
interactive_component_type: MultiSelect
column_name: variety
column_type: object
filter_expr: "col('petal.length') > 4"
title: "Varieties (petal > 4 cm)"
filter_expr scopes the component's options/range to the filtered subset. See Filter Expressions.
Interactive type × column_type compatibility:
| column_type | Valid interactive_component_type |
|---|---|
int64 |
Slider, RangeSlider |
float64 |
Slider, RangeSlider |
datetime |
DateRangePicker |
category |
Select, MultiSelect, SegmentedControl |
object |
Select, MultiSelect, SegmentedControl |
bool |
(not yet supported) |
timedelta |
(not supported) |
Table Component¶
- tag: data-table
component_type: table
workflow_tag: python/workflow_name
data_collection_tag: table_dc
page_size: 25 # rows per page (default: 100)
columns: [col1, col2] # optional: allowlist of visible columns (omit to show all)
compact: false # optional: tighter row and header heights (default: false)
title: "Sample Data" # optional: auto-generated from DC tag if omitted
description: "Complete measurements across all samples" # optional subtitle
title_size: h3 # h1, h2, h3, or sm (default: sm)
title_align: left # left (default), center, or right
Title / description fields are rendered as a header above the AG Grid table. When title is omitted, it is auto-generated from data_collection_tag.
Text Component¶
Headings and prose used to document and organise a dashboard. Text tiles bind to no data
source, so workflow_tag and data_collection_tag are unused.
- tag: section-overview
component_type: text
title: Within-Sample Diversity
order: 2 # heading level H1–H6 (default: 1)
alignment: left # horizontal: left (default), center, right
vertical_alignment: center # vertical: top, center (default), bottom
body: |
Shannon, observed features and Faith's PD measure within-sample
richness and evenness.
| Field | Type | Default | Description |
|---|---|---|---|
order |
int (1–6) | 1 |
Heading level, H1 through H6 |
alignment |
left | center | right |
left |
Horizontal alignment of the title and body |
vertical_alignment |
top | center | bottom |
center |
Where the text block sits vertically in its tile |
body |
str | "" |
Optional paragraph below the heading |
vertical_alignment defaults to center (v1.4.0+)
Set vertical_alignment: top for the pre-v1.4.0 rendering. See
Components for why the default changed.
Image Component¶
- tag: image-gallery
component_type: image
workflow_tag: python/workflow_name
data_collection_tag: images_dc
image_column: image_path # required: column with image paths
thumbnail_size: 150 # pixels (default: 150)
columns: 4 # grid columns (default: 4)
max_images: 20 # max images shown (default: 20)
s3_base_folder is optional
If omitted, the image base folder is resolved automatically from the data collection's S3 configuration at runtime.
MultiQC Component¶
Embeds a specific plot from a MultiQC quality control report. Both selected_module and selected_plot are required — they uniquely identify which plot to render.
- tag: fastqc-quality
component_type: multiqc
workflow_tag: python/nf_workflow
data_collection_tag: multiqc_report
selected_module: fastqc
selected_plot: per_base_sequence_quality
Both fields are required
Omitting either selected_module or selected_plot will fail validation. YAML-defined components must be explicit about which plot to display.
Map Component¶
Supports three map types: scatter_map (default), density_map, and choropleth_map.
Scatter map — point markers at lat/lon coordinates:
- tag: sampling-map
component_type: map
workflow_tag: python/my_workflow
data_collection_tag: sample_metadata
lat_column: latitude
lon_column: longitude
color_column: biome
size_column: read_count
hover_columns: [sample_id, site_name]
map_style: carto-positron
selection_enabled: true
selection_column: sample_id
Choropleth map — colored regions from GeoJSON:
- tag: country-choropleth
component_type: map
workflow_tag: python/my_workflow
data_collection_tag: sample_metadata
map_type: choropleth_map
locations_column: country_name
featureidkey: properties.NAME
color_column: sample_id
choropleth_aggregation: count
color_continuous_scale: Viridis
opacity: 0.6
# GeoJSON source — pick one:
geojson_url: "https://example.com/countries.geojson" # URL
# geojson_dc_tag: europe_geojson # DC tag
Valid map_type values: scatter_map, density_map, choropleth_map
Valid map_style values: open-street-map, carto-positron, carto-darkmatter
Choropleth requirements
Choropleth maps require locations_column, color_column, and a GeoJSON source (geojson_url, geojson_dc_tag, or geojson_data). Selection filtering is not supported on choropleth maps.
Placement (v1.4.0+) — a map can stay in the grid or be lifted into a dashboard-wide panel that follows the viewer across every tab. See Components for what each state looks like.
# two extra keys on any map component
placement: floating # grid (default) or floating
floating_initial_state: docked # compact (default), expanded, docked, hidden
| Field | Values | Default | Description |
|---|---|---|---|
placement |
grid, floating |
grid |
floating claims no grid cell; the map belongs to the whole tab family |
floating_initial_state |
compact, expanded, docked, hidden |
compact |
The state the panel opens in. Ignored when placement: grid |
State is remembered per viewer
floating_initial_state only sets where the panel starts. Once a viewer moves, resizes
or folds it, their own choice is remembered for that dashboard family.
Validation¶
The CLI validates YAML files in two passes:
┌──────────────────────────────────────────────────────────────┐
│ Pass 1 — Schema + Domain (always, no server needed) │
│ │
│ ✓ YAML syntax parsing │
│ ✓ Required fields (title, component required fields) │
│ ✓ visu_type enum (scatter, line, bar, box, histogram, ...) │
│ ✓ mode/code_content cross-field rule │
│ ✓ selection_enabled/selection_column cross-field rule │
│ ✓ aggregation × column_type compatibility (if provided) │
│ ✓ interactive_type × column_type compatibility (if provided)│
│ ✓ MultiQC: selected_module + selected_plot both required │
│ ✓ Image: image_column required │
├──────────────────────────────────────────────────────────────┤
│ Pass 2 — Server Schema (with --config, skip: --offline) │
│ │
│ ✓ Resolves workflow_tag + data_collection_tag → DC schema │
│ ✓ Checks column_name exists in delta table schema │
│ ✓ Infers column_type from schema → validates aggregation │
│ and interactive_component_type against inferred type │
└──────────────────────────────────────────────────────────────┘
Error output is a clean per-component table — each invalid field gets its own row:
Validation Errors
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Component ┃ Field ┃ Message ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ image-missing-column │ image_column │ Field required │
│ multiqc-missing-module │ selected_module │ Field required │
│ multiqc-missing-plot │ selected_plot │ Field required │
└────────────────────────┴─────────────────┴────────────────┘
Best Practices¶
File Organization¶
project/
├── project.yaml # Project configuration
├── dashboards/
│ ├── overview.yaml # Main overview dashboard
│ ├── qc_metrics.yaml # QC-specific dashboard
│ └── samples.yaml # Sample analysis dashboard
└── README.md
Component Naming¶
Use descriptive tags that indicate purpose:
# Good: Descriptive tags
- tag: box-variety-sepal-length # Chart type + data
- tag: sepal-length-average # Metric + aggregation
- tag: variety-filter # Column + purpose
# Avoid: Generic tags
- tag: figure-1
- tag: card-2
Incremental Validation Workflow¶
# Step 1 — check schema and domain constraints (no server needed)
depictio-cli dashboard validate my.yaml
# Step 2 — full validation including column names
depictio-cli dashboard validate my.yaml --config ~/.depictio/admin_config.yaml
# Step 3 — dry import (schema check only, no write)
depictio-cli dashboard import my.yaml --dry-run
# Step 4 — actual import
depictio-cli dashboard import my.yaml --config ~/.depictio/admin_config.yaml
# Step 5 — roundtrip check (export back and diff)
depictio-cli dashboard export <id> -o out.yaml
diff my.yaml out.yaml
Version Control¶
- Do version control dashboard YAML files
- Use meaningful commit messages describing dashboard changes
- Review diffs before merging dashboard changes
- Tag releases when deploying to production