dataface 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- d3_format/__init__.py +14 -0
- d3_format/errors.py +19 -0
- d3_format/format.py +551 -0
- d3_format/spec.py +159 -0
- dataface/DATAFACE_SYNTAX.md +1135 -0
- dataface/__init__.py +93 -0
- dataface/_docs_site.py +20 -0
- dataface/_install_hint.py +26 -0
- dataface/agent_api/__init__.py +79 -0
- dataface/agent_api/_init_templates/__init__.py +0 -0
- dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
- dataface/agent_api/_init_templates/dataface.yml +15 -0
- dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
- dataface/agent_api/_init_templates/index.md +24 -0
- dataface/agent_api/_paths.py +118 -0
- dataface/agent_api/_project_agents_md.py +43 -0
- dataface/agent_api/_session_store.py +486 -0
- dataface/agent_api/_state.py +28 -0
- dataface/agent_api/chat.py +221 -0
- dataface/agent_api/dashboards.py +257 -0
- dataface/agent_api/describe.py +366 -0
- dataface/agent_api/describe_query.py +120 -0
- dataface/agent_api/docs/__init__.py +25 -0
- dataface/agent_api/docs/_loader.py +292 -0
- dataface/agent_api/docs/yaml-reference.md +2757 -0
- dataface/agent_api/file_refs.py +118 -0
- dataface/agent_api/init.py +126 -0
- dataface/agent_api/inspect.py +128 -0
- dataface/agent_api/mcp_install.py +170 -0
- dataface/agent_api/query.py +274 -0
- dataface/agent_api/schema.py +658 -0
- dataface/agent_api/schema_search.py +284 -0
- dataface/agent_api/search.py +270 -0
- dataface/agent_api/skill_install.py +141 -0
- dataface/agent_api/skill_render.py +90 -0
- dataface/agent_api/skills.py +293 -0
- dataface/agent_api/surface_aliases.yaml +128 -0
- dataface/agent_api/validate.py +175 -0
- dataface/agent_api/validate_query.py +84 -0
- dataface/ai/__init__.py +39 -0
- dataface/ai/agent.py +139 -0
- dataface/ai/context.py +45 -0
- dataface/ai/events.py +62 -0
- dataface/ai/external_mcp.py +610 -0
- dataface/ai/generate_sql.py +96 -0
- dataface/ai/llm.py +403 -0
- dataface/ai/mcp/__init__.py +51 -0
- dataface/ai/mcp/server.py +289 -0
- dataface/ai/memories.py +85 -0
- dataface/ai/prompts.py +177 -0
- dataface/ai/schema_context.py +138 -0
- dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
- dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
- dataface/ai/skills/dashboard-build/SKILL.md +212 -0
- dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
- dataface/ai/skills/dashboard-design/SKILL.md +182 -0
- dataface/ai/skills/dashboard-review/SKILL.md +113 -0
- dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
- dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
- dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
- dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
- dataface/ai/skills/drill-down-link/SKILL.md +112 -0
- dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
- dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
- dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
- dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
- dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
- dataface/ai/skills/kpi-row/SKILL.md +101 -0
- dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
- dataface/ai/skills/report-design/SKILL.md +184 -0
- dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
- dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
- dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
- dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
- dataface/ai/skills/time-series-trend/SKILL.md +93 -0
- dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
- dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
- dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
- dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
- dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
- dataface/ai/tool_schemas.py +132 -0
- dataface/ai/tools/__init__.py +312 -0
- dataface/ai/yaml_utils.py +57 -0
- dataface/cli/__init__.py +3 -0
- dataface/cli/_console.py +48 -0
- dataface/cli/_error_format.py +83 -0
- dataface/cli/_extras.py +190 -0
- dataface/cli/_json_output.py +8 -0
- dataface/cli/_parsing.py +17 -0
- dataface/cli/_version_info.py +56 -0
- dataface/cli/commands/__init__.py +3 -0
- dataface/cli/commands/_agent_input.py +205 -0
- dataface/cli/commands/_agent_server.py +115 -0
- dataface/cli/commands/chat.py +645 -0
- dataface/cli/commands/describe.py +107 -0
- dataface/cli/commands/docs.py +131 -0
- dataface/cli/commands/extension.py +179 -0
- dataface/cli/commands/init.py +240 -0
- dataface/cli/commands/inspect.py +94 -0
- dataface/cli/commands/mcp_init.py +167 -0
- dataface/cli/commands/query.py +386 -0
- dataface/cli/commands/render.py +291 -0
- dataface/cli/commands/schema.py +411 -0
- dataface/cli/commands/search.py +49 -0
- dataface/cli/commands/serve.py +114 -0
- dataface/cli/commands/skills.py +133 -0
- dataface/cli/commands/skills_init.py +161 -0
- dataface/cli/commands/validate.py +63 -0
- dataface/cli/main.py +1501 -0
- dataface/core/__init__.py +75 -0
- dataface/core/compile/__init__.py +244 -0
- dataface/core/compile/_jinja_helpers.py +78 -0
- dataface/core/compile/channel.py +222 -0
- dataface/core/compile/chart_focus.py +101 -0
- dataface/core/compile/chart_resolved.py +169 -0
- dataface/core/compile/chart_type_detection.py +489 -0
- dataface/core/compile/chart_update.py +261 -0
- dataface/core/compile/colors.py +64 -0
- dataface/core/compile/compiler.py +904 -0
- dataface/core/compile/config.py +823 -0
- dataface/core/compile/custom_chart_types.py +208 -0
- dataface/core/compile/data_table_attachment.py +1287 -0
- dataface/core/compile/detect.py +110 -0
- dataface/core/compile/errors.py +302 -0
- dataface/core/compile/filter_injection.py +319 -0
- dataface/core/compile/introspection.py +527 -0
- dataface/core/compile/jinja.py +511 -0
- dataface/core/compile/labels_env.py +52 -0
- dataface/core/compile/markdown.py +154 -0
- dataface/core/compile/meta.py +388 -0
- dataface/core/compile/models/__init__.py +0 -0
- dataface/core/compile/models/chart/__init__.py +0 -0
- dataface/core/compile/models/chart/authored.py +2137 -0
- dataface/core/compile/models/chart/compiled.py +398 -0
- dataface/core/compile/models/config.py +347 -0
- dataface/core/compile/models/face/__init__.py +0 -0
- dataface/core/compile/models/face/authored.py +659 -0
- dataface/core/compile/models/face/compiled.py +522 -0
- dataface/core/compile/models/factories.py +201 -0
- dataface/core/compile/models/markers.py +40 -0
- dataface/core/compile/models/palette.py +36 -0
- dataface/core/compile/models/primitives.py +415 -0
- dataface/core/compile/models/query/__init__.py +0 -0
- dataface/core/compile/models/query/authored.py +246 -0
- dataface/core/compile/models/query/compiled.py +710 -0
- dataface/core/compile/models/refs.py +137 -0
- dataface/core/compile/models/source.py +611 -0
- dataface/core/compile/models/style/__init__.py +0 -0
- dataface/core/compile/models/style/authored.py +481 -0
- dataface/core/compile/models/style/compiled.py +3399 -0
- dataface/core/compile/models/style/merged.py +1682 -0
- dataface/core/compile/models/theme.py +362 -0
- dataface/core/compile/models/variable/__init__.py +0 -0
- dataface/core/compile/models/variable/authored.py +254 -0
- dataface/core/compile/models/vega_lite/__init__.py +0 -0
- dataface/core/compile/models/vega_lite/config.py +510 -0
- dataface/core/compile/models/vega_lite/contracts.py +171 -0
- dataface/core/compile/normalize_charts.py +494 -0
- dataface/core/compile/normalize_layout.py +1000 -0
- dataface/core/compile/normalize_queries.py +297 -0
- dataface/core/compile/normalize_variables.py +489 -0
- dataface/core/compile/normalizer.py +543 -0
- dataface/core/compile/palette.py +1100 -0
- dataface/core/compile/parameterized.py +658 -0
- dataface/core/compile/parser.py +228 -0
- dataface/core/compile/schema.py +20 -0
- dataface/core/compile/schema_renderers/__init__.py +0 -0
- dataface/core/compile/schema_renderers/json_schema.py +163 -0
- dataface/core/compile/schema_renderers/prompt.py +152 -0
- dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
- dataface/core/compile/sizing.py +2126 -0
- dataface/core/compile/sources.py +518 -0
- dataface/core/compile/sql_authoring_lint.py +56 -0
- dataface/core/compile/style_cascade.py +471 -0
- dataface/core/compile/typography.py +299 -0
- dataface/core/compile/validator.py +301 -0
- dataface/core/compile/variables.py +53 -0
- dataface/core/compile/vega_config.py +98 -0
- dataface/core/compile/vega_lite/__init__.py +6 -0
- dataface/core/compile/vega_lite/validation.py +95 -0
- dataface/core/compile/yaml_error_formatter.py +838 -0
- dataface/core/connections.py +38 -0
- dataface/core/dashboard.py +358 -0
- dataface/core/defaults/default_config.yml +101 -0
- dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
- dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
- dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
- dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
- dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
- dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
- dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
- dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
- dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
- dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
- dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
- dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
- dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
- dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
- dataface/core/defaults/palettes/sequential/amber.yml +22 -0
- dataface/core/defaults/palettes/sequential/blue.yml +22 -0
- dataface/core/defaults/palettes/sequential/brown.yml +22 -0
- dataface/core/defaults/palettes/sequential/gray.yml +22 -0
- dataface/core/defaults/palettes/sequential/green.yml +22 -0
- dataface/core/defaults/palettes/sequential/purple.yml +22 -0
- dataface/core/defaults/palettes/sequential/rust.yml +22 -0
- dataface/core/defaults/palettes/sequential/teal.yml +22 -0
- dataface/core/defaults/palettes/tone/negative.yml +32 -0
- dataface/core/defaults/palettes/tone/positive.yml +22 -0
- dataface/core/defaults/palettes/tone/warning.yml +22 -0
- dataface/core/defaults/themes/_base.yaml +786 -0
- dataface/core/defaults/themes/bi.yaml +16 -0
- dataface/core/defaults/themes/carbong100.yaml +41 -0
- dataface/core/defaults/themes/cream.yaml +122 -0
- dataface/core/defaults/themes/dark.yaml +40 -0
- dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
- dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
- dataface/core/defaults/themes/editorial.yaml +147 -0
- dataface/core/defaults/themes/light.yaml +30 -0
- dataface/core/defaults/themes/looker.yaml +17 -0
- dataface/core/defaults/themes/stark.yaml +134 -0
- dataface/core/errors/__init__.py +67 -0
- dataface/core/errors/codes_compile.py +56 -0
- dataface/core/errors/codes_execute.py +177 -0
- dataface/core/errors/codes_render.py +106 -0
- dataface/core/errors/codes_unknown.py +15 -0
- dataface/core/errors/hints.py +74 -0
- dataface/core/errors/registry.py +42 -0
- dataface/core/errors/structured.py +92 -0
- dataface/core/execute/__init__.py +91 -0
- dataface/core/execute/adapters/__init__.py +49 -0
- dataface/core/execute/adapters/adapter_registry.py +400 -0
- dataface/core/execute/adapters/base.py +245 -0
- dataface/core/execute/adapters/csv_adapter.py +239 -0
- dataface/core/execute/adapters/dbt_adapter.py +283 -0
- dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
- dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
- dataface/core/execute/adapters/dbt_utils.py +150 -0
- dataface/core/execute/adapters/http_adapter.py +224 -0
- dataface/core/execute/adapters/metricflow_adapter.py +94 -0
- dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
- dataface/core/execute/adapters/sql_adapter.py +710 -0
- dataface/core/execute/adapters/values_adapter.py +58 -0
- dataface/core/execute/batch.py +744 -0
- dataface/core/execute/cache_backend.py +135 -0
- dataface/core/execute/cache_keys.py +66 -0
- dataface/core/execute/dbt_jinja.py +21 -0
- dataface/core/execute/dialects/__init__.py +121 -0
- dataface/core/execute/dialects/athena.py +75 -0
- dataface/core/execute/dialects/base.py +302 -0
- dataface/core/execute/dialects/bigquery.py +38 -0
- dataface/core/execute/dialects/databricks.py +68 -0
- dataface/core/execute/dialects/duckdb.py +35 -0
- dataface/core/execute/dialects/mysql.py +68 -0
- dataface/core/execute/dialects/postgres.py +39 -0
- dataface/core/execute/dialects/redshift.py +12 -0
- dataface/core/execute/dialects/snowflake.py +51 -0
- dataface/core/execute/dialects/sqlserver.py +92 -0
- dataface/core/execute/duckdb_cache.py +712 -0
- dataface/core/execute/duckdb_config.py +26 -0
- dataface/core/execute/errors.py +213 -0
- dataface/core/execute/executor.py +1249 -0
- dataface/core/execute/parallel.py +162 -0
- dataface/core/execute/setup_sql.py +58 -0
- dataface/core/execute/source_registry.py +72 -0
- dataface/core/execute/source_resolver.py +255 -0
- dataface/core/execute/sql_guard.py +387 -0
- dataface/core/execute/sql_literals.py +199 -0
- dataface/core/fonts.py +52 -0
- dataface/core/inspect/__init__.py +32 -0
- dataface/core/inspect/cache_factory.py +98 -0
- dataface/core/inspect/db_types.py +162 -0
- dataface/core/inspect/dbt_schema.py +96 -0
- dataface/core/inspect/defaults.yml +37 -0
- dataface/core/inspect/fanout_risk.py +109 -0
- dataface/core/inspect/manifest_utils.py +77 -0
- dataface/core/inspect/partials/categorical.yml +40 -0
- dataface/core/inspect/partials/date.yml +40 -0
- dataface/core/inspect/partials/numeric.yml +55 -0
- dataface/core/inspect/partition_types.py +38 -0
- dataface/core/inspect/query_validator.py +975 -0
- dataface/core/inspect/renderer.py +354 -0
- dataface/core/inspect/resolver.py +808 -0
- dataface/core/inspect/search.py +461 -0
- dataface/core/inspect/sources/__init__.py +32 -0
- dataface/core/inspect/sources/dbt.py +738 -0
- dataface/core/inspect/sources/duckdb_utils.py +66 -0
- dataface/core/inspect/templates/__init__.py +1 -0
- dataface/core/inspect/templates/categorical_column.yml +196 -0
- dataface/core/inspect/templates/charts.yml +109 -0
- dataface/core/inspect/templates/date_column.yml +248 -0
- dataface/core/inspect/templates/model.yml +138 -0
- dataface/core/inspect/templates/numeric_column.yml +261 -0
- dataface/core/inspect/templates/quality.yml +80 -0
- dataface/core/inspect/templates/string_column.yml +263 -0
- dataface/core/project_roots.py +165 -0
- dataface/core/render/__init__.py +87 -0
- dataface/core/render/board_links.py +176 -0
- dataface/core/render/chart/__init__.py +27 -0
- dataface/core/render/chart/arc_attached_table.py +251 -0
- dataface/core/render/chart/artifacts.py +16 -0
- dataface/core/render/chart/callout.py +225 -0
- dataface/core/render/chart/decisions.py +358 -0
- dataface/core/render/chart/geo.py +700 -0
- dataface/core/render/chart/kpi.py +916 -0
- dataface/core/render/chart/labels.py +76 -0
- dataface/core/render/chart/pipeline.py +818 -0
- dataface/core/render/chart/presentation.py +36 -0
- dataface/core/render/chart/profile.py +3438 -0
- dataface/core/render/chart/render_single.py +347 -0
- dataface/core/render/chart/renderers.py +193 -0
- dataface/core/render/chart/rendering.py +565 -0
- dataface/core/render/chart/serialization.py +90 -0
- dataface/core/render/chart/spark.py +496 -0
- dataface/core/render/chart/spark_bar.py +370 -0
- dataface/core/render/chart/spec_builders.py +154 -0
- dataface/core/render/chart/standard_renderer.py +2645 -0
- dataface/core/render/chart/table.py +2957 -0
- dataface/core/render/chart/table_support.py +1452 -0
- dataface/core/render/chart/tick_values.py +66 -0
- dataface/core/render/chart/time_unit_detect.py +809 -0
- dataface/core/render/chart/title_overflow.py +157 -0
- dataface/core/render/chart/type_inference.py +122 -0
- dataface/core/render/chart/validation.py +99 -0
- dataface/core/render/chart/vega_lite.py +125 -0
- dataface/core/render/chart/vega_lite_types.py +268 -0
- dataface/core/render/chart/vl_field_maps.py +346 -0
- dataface/core/render/chart_interactivity.py +24 -0
- dataface/core/render/control_registry.py +287 -0
- dataface/core/render/converters/__init__.py +24 -0
- dataface/core/render/converters/chart.py +276 -0
- dataface/core/render/converters/html.py +98 -0
- dataface/core/render/converters/pdf.py +40 -0
- dataface/core/render/converters/png.py +41 -0
- dataface/core/render/errors.py +144 -0
- dataface/core/render/face_api.py +160 -0
- dataface/core/render/faces.py +1194 -0
- dataface/core/render/font_measurement.py +48 -0
- dataface/core/render/font_support.py +197 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/InterVariable.ttf +0 -0
- dataface/core/render/fonts/InterVariable.woff2 +0 -0
- dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
- dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
- dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
- dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
- dataface/core/render/fonts/_emoji_font_face.css +43 -0
- dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
- dataface/core/render/format_utils.py +329 -0
- dataface/core/render/geo_defaults.yml +28 -0
- dataface/core/render/json_format.py +146 -0
- dataface/core/render/layout_sizing.py +865 -0
- dataface/core/render/layouts.py +541 -0
- dataface/core/render/markdown_defaults.yml +16 -0
- dataface/core/render/missing_vars_prompt.py +79 -0
- dataface/core/render/placeholder.py +389 -0
- dataface/core/render/render_result.py +14 -0
- dataface/core/render/renderer.py +467 -0
- dataface/core/render/script_embedding.py +16 -0
- dataface/core/render/svg_utils.py +212 -0
- dataface/core/render/template_loader.py +69 -0
- dataface/core/render/templates/controls/_styles.css +606 -0
- dataface/core/render/templates/controls/checkbox.html +16 -0
- dataface/core/render/templates/controls/date.html +16 -0
- dataface/core/render/templates/controls/number.html +19 -0
- dataface/core/render/templates/controls/readonly.html +9 -0
- dataface/core/render/templates/controls/select.html +21 -0
- dataface/core/render/templates/controls/slider.html +22 -0
- dataface/core/render/templates/controls/text.html +16 -0
- dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
- dataface/core/render/templates/scripts/variables.js +976 -0
- dataface/core/render/templates/svg/grid_pattern.svg +3 -0
- dataface/core/render/templates/svg/styles.css +51 -0
- dataface/core/render/terminal.py +311 -0
- dataface/core/render/terminal_charts.py +563 -0
- dataface/core/render/terminal_defaults.yml +2 -0
- dataface/core/render/terminal_layouts.py +299 -0
- dataface/core/render/terminal_text.py +31 -0
- dataface/core/render/text/__init__.py +1 -0
- dataface/core/render/text/case.py +113 -0
- dataface/core/render/text_format.py +129 -0
- dataface/core/render/utils.py +106 -0
- dataface/core/render/variable_controls.py +946 -0
- dataface/core/render/variable_input_refinement.py +140 -0
- dataface/core/render/warnings/__init__.py +15 -0
- dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
- dataface/core/render/warnings/base.py +44 -0
- dataface/core/render/warnings/fanout_risk.py +15 -0
- dataface/core/render/warnings/from_query_diagnostic.py +56 -0
- dataface/core/render/warnings/missing_join_predicate.py +13 -0
- dataface/core/render/warnings/query_parse_error.py +14 -0
- dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
- dataface/core/render/warnings/reaggregation.py +14 -0
- dataface/core/render/warnings/registry.py +45 -0
- dataface/core/render/warnings/suppression.py +46 -0
- dataface/core/render/warnings/temporal_single_point.py +63 -0
- dataface/core/render/warnings/unreferenced_chart.py +15 -0
- dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
- dataface/core/render/yaml_format.py +167 -0
- dataface/core/resolve_face.py +195 -0
- dataface/core/schema/__init__.py +0 -0
- dataface/core/schema/guidance.py +151 -0
- dataface/core/scoped_paths.py +59 -0
- dataface/core/serve/__init__.py +14 -0
- dataface/core/serve/bootstrap.py +39 -0
- dataface/core/serve/embedded.py +57 -0
- dataface/core/serve/port.py +129 -0
- dataface/core/serve/server.py +938 -0
- dataface/core/serve/templates/__init__.py +0 -0
- dataface/core/serve/templates/directory.yml +6 -0
- dataface/core/serve/templates/error.html.j2 +217 -0
- dataface/core/utils.py +121 -0
- dataface/core/validate.py +64 -0
- dataface/integrations/__init__.py +0 -0
- dataface/integrations/highlighting.py +351 -0
- dataface/integrations/markdown.py +537 -0
- dataface/py.typed +0 -0
- dataface-0.1.2.dist-info/METADATA +375 -0
- dataface-0.1.2.dist-info/RECORD +455 -0
- dataface-0.1.2.dist-info/WHEEL +4 -0
- dataface-0.1.2.dist-info/entry_points.txt +2 -0
- dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
- mdsvg/__init__.py +168 -0
- mdsvg/fonts.py +656 -0
- mdsvg/images.py +299 -0
- mdsvg/parser.py +629 -0
- mdsvg/playground.py +284 -0
- mdsvg/py.typed +2 -0
- mdsvg/renderer.py +1623 -0
- mdsvg/style.py +355 -0
- mdsvg/types.py +200 -0
- mdsvg/utils.py +86 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: before-after-comparison
|
|
3
|
+
kind: pattern
|
|
4
|
+
description: >
|
|
5
|
+
Pattern for placing two metric series on the same axis to compare baseline
|
|
6
|
+
vs current, plan vs actual, or A vs B. Use when the question is "how does
|
|
7
|
+
current compare to baseline?" for the same set of categories or time periods.
|
|
8
|
+
Triggers on: 'compare', 'baseline vs current', 'plan vs actual', 'before
|
|
9
|
+
after', 'A/B', 'target vs actual', 'layered bars'. Both series share the same
|
|
10
|
+
x-axis encoding. Do NOT use for time-series trend (use time-series-trend).
|
|
11
|
+
Do NOT use for more than 3 series (chart becomes unreadable).
|
|
12
|
+
metadata:
|
|
13
|
+
author: fivetran
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Before-After Comparison
|
|
17
|
+
|
|
18
|
+
Two series rendered on the same bar or line chart, sharing the x-axis, so the
|
|
19
|
+
viewer can compare baseline vs current or plan vs actual across categories or
|
|
20
|
+
time periods. Use `y: [series_a, series_b]` for layered bars, or `color:` for
|
|
21
|
+
grouped multi-series.
|
|
22
|
+
|
|
23
|
+
## When to reach for this
|
|
24
|
+
|
|
25
|
+
- "How does Q4 compare to Q3 for each region?"
|
|
26
|
+
- "Are we above or below plan by category?"
|
|
27
|
+
- The comparison dimension is the same set of x values for both series
|
|
28
|
+
|
|
29
|
+
## When NOT to use this
|
|
30
|
+
|
|
31
|
+
- Trend over time on a single metric → `time-series-trend`
|
|
32
|
+
- More than 3 series → too cluttered; split into separate charts
|
|
33
|
+
- Composition (parts of a whole) → stacked area in `faceted-small-multiples`
|
|
34
|
+
|
|
35
|
+
## The pattern
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
queries:
|
|
39
|
+
plan_vs_actual:
|
|
40
|
+
sql: |
|
|
41
|
+
SELECT category,
|
|
42
|
+
SUM(actual_revenue) AS actual,
|
|
43
|
+
SUM(planned_revenue) AS plan
|
|
44
|
+
FROM budget
|
|
45
|
+
GROUP BY category
|
|
46
|
+
ORDER BY actual DESC
|
|
47
|
+
|
|
48
|
+
charts:
|
|
49
|
+
comparison:
|
|
50
|
+
type: bar
|
|
51
|
+
query: plan_vs_actual
|
|
52
|
+
x: category
|
|
53
|
+
y: [actual, plan] # two series, same x
|
|
54
|
+
title: Actual vs Plan by Category
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For time-based comparisons, use two separate columns in one query and map with
|
|
58
|
+
`color:` instead:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
queries:
|
|
62
|
+
by_month:
|
|
63
|
+
columns: [month, current, prior]
|
|
64
|
+
values: ...
|
|
65
|
+
|
|
66
|
+
charts:
|
|
67
|
+
trend_compare:
|
|
68
|
+
type: line
|
|
69
|
+
query: by_month
|
|
70
|
+
x: month
|
|
71
|
+
y: [current, prior]
|
|
72
|
+
title: Current vs Prior Period
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
See `examples/before-after-comparison.yml` for the inline-data worked example.
|
|
76
|
+
|
|
77
|
+
## Variations
|
|
78
|
+
|
|
79
|
+
| Variation | YAML knob | When |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| Layered bars | `y: [a, b]` | Side-by-side bars per category |
|
|
82
|
+
| Two line series | `y: [a, b]` on `type: line` | Time-based trend comparison |
|
|
83
|
+
| Multiple categories | keep `x:` categorical | Natural for department/region comparisons |
|
|
84
|
+
| Delta column | add a computed delta in SQL | Explicitly show the gap |
|
|
85
|
+
|
|
86
|
+
## Common pitfalls
|
|
87
|
+
|
|
88
|
+
| Pitfall | Why it breaks | Fix |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| Series on different scales | Misleading visual; one series dwarfs the other | Use matching units or a secondary axis |
|
|
91
|
+
| Too many series (`y: [a, b, c, d]`) | Legend and bars both unreadable | Cap at 2–3 series; combine the rest |
|
|
92
|
+
| Different x-values per series | Chart gaps or misaligned bars | Ensure both series have a value for every x |
|
|
93
|
+
| Swapped series order | Baseline visually dominates current | Put the primary/current series first in `y:` |
|
|
94
|
+
|
|
95
|
+
## Worked example
|
|
96
|
+
|
|
97
|
+
See `examples/before-after-comparison.yml` — four departments comparing
|
|
98
|
+
current vs baseline spend. Inline data, no warehouse needed.
|
|
99
|
+
|
|
100
|
+
## YAML Reference
|
|
101
|
+
|
|
102
|
+
For syntax and field details: {{ s_yaml_reference_footer }}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
title: Q4 Budget vs Actual
|
|
2
|
+
description: Before-after comparison pattern — two series (current and baseline) on the same bar chart
|
|
3
|
+
|
|
4
|
+
queries:
|
|
5
|
+
budget_vs_actual:
|
|
6
|
+
description: Current quarter spend vs prior-quarter baseline by department
|
|
7
|
+
columns: [department, current, baseline]
|
|
8
|
+
values:
|
|
9
|
+
- [Engineering, 420000, 380000]
|
|
10
|
+
- [Marketing, 185000, 210000]
|
|
11
|
+
- [Sales, 340000, 295000]
|
|
12
|
+
- [Support, 95000, 105000]
|
|
13
|
+
|
|
14
|
+
charts:
|
|
15
|
+
comparison_bar:
|
|
16
|
+
description: Current vs baseline spend — bars sit side by side per department
|
|
17
|
+
type: bar
|
|
18
|
+
query: budget_vs_actual
|
|
19
|
+
x: department
|
|
20
|
+
y: [current, baseline]
|
|
21
|
+
title: Q4 Actual vs Prior Quarter by Department
|
|
22
|
+
|
|
23
|
+
rows:
|
|
24
|
+
- comparison_bar
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dashboard-build
|
|
3
|
+
kind: workflow
|
|
4
|
+
description: >
|
|
5
|
+
Core workflow for building dashboards and reports with Dataface. Use when
|
|
6
|
+
creating new dashboards, editing existing YAML, adding charts, writing
|
|
7
|
+
queries, iterating on layout, or when the user says 'build a dashboard',
|
|
8
|
+
'create a report', 'add a chart', 'write a query'. Covers the
|
|
9
|
+
build-test-iterate cycle, parameterized queries, caching, and incremental
|
|
10
|
+
development. Do NOT use for diagnosing errors after something breaks (use
|
|
11
|
+
dataface-troubleshooting). Do NOT use for design decisions about
|
|
12
|
+
chart types or layout patterns (use dashboard-design or
|
|
13
|
+
report-design).
|
|
14
|
+
metadata:
|
|
15
|
+
author: fivetran
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Building Dataface Dashboards
|
|
19
|
+
|
|
20
|
+
Build dashboards and reports **incrementally** — one chart at a time, validating at every step. Never one-shot an entire dashboard.
|
|
21
|
+
|
|
22
|
+
## Companion Skills
|
|
23
|
+
|
|
24
|
+
- **`{{ s_skill_design_dashboard }}`** — chart-type, layout, and color decisions
|
|
25
|
+
- **`{{ s_skill_design_report }}`** — narrative reports (text + charts)
|
|
26
|
+
- **`{{ s_skill_review }}`** — self-review checklist run at delivery
|
|
27
|
+
- **`{{ s_skill_troubleshooting }}`** — when something breaks
|
|
28
|
+
|
|
29
|
+
{{ s_docs_discovery }}
|
|
30
|
+
|
|
31
|
+
## Metadata Requirement
|
|
32
|
+
|
|
33
|
+
Fill `description` on every named object — agents downstream rely on it for context and search:
|
|
34
|
+
|
|
35
|
+
- `queries.*.description` — what the query returns and why it exists
|
|
36
|
+
- `charts.*.description` — what question the chart answers
|
|
37
|
+
- `variables.*.description` — how the variable should be used
|
|
38
|
+
- Layout objects (`rows`/`cols`/`grid.items`/`tabs.items`) — section intent when useful
|
|
39
|
+
|
|
40
|
+
Keep each description short and factual (one sentence).
|
|
41
|
+
|
|
42
|
+
## The Workflow
|
|
43
|
+
|
|
44
|
+
### Step 1 — Explore the Data
|
|
45
|
+
|
|
46
|
+
{{ s_explore_schema_first }}
|
|
47
|
+
|
|
48
|
+
Use `{{ s_execute_query }}` to verify cardinality and sample values before writing any YAML:
|
|
49
|
+
|
|
50
|
+
```sql
|
|
51
|
+
SELECT status, COUNT(*) FROM orders GROUP BY status;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Do not skip this step.** Writing SQL against assumed column names is the #1 source of errors.
|
|
55
|
+
|
|
56
|
+
### Step 2 — Build One Chart
|
|
57
|
+
|
|
58
|
+
Write a minimal YAML with a single query and chart:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
source: my_profile
|
|
62
|
+
queries:
|
|
63
|
+
revenue:
|
|
64
|
+
sql: SELECT date, SUM(amount) AS total FROM orders GROUP BY date ORDER BY date
|
|
65
|
+
charts:
|
|
66
|
+
revenue_trend:
|
|
67
|
+
query: revenue
|
|
68
|
+
type: line
|
|
69
|
+
x: date
|
|
70
|
+
y: total
|
|
71
|
+
rows:
|
|
72
|
+
- revenue_trend
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Then verify with two calls:
|
|
76
|
+
|
|
77
|
+
1. `{{ s_execute_query }}` — confirm the data shape and columns
|
|
78
|
+
2. `{{ s_render_dashboard }}` — compile + render to see the visual
|
|
79
|
+
|
|
80
|
+
### Step 3 — Iterate on That Chart
|
|
81
|
+
|
|
82
|
+
Adjust SQL, chart type, labels, colors. {{ s_render_to_verify }}
|
|
83
|
+
|
|
84
|
+
### Step 4 — Add the Next Chart
|
|
85
|
+
|
|
86
|
+
Repeat steps 2–3 for each additional chart. One at a time.
|
|
87
|
+
|
|
88
|
+
### Step 5 — Compose the Layout
|
|
89
|
+
|
|
90
|
+
Once all charts work individually, arrange them in `rows:` / `cols:`. The layout is the easy part — getting the queries right is the hard part.
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
rows:
|
|
94
|
+
- cols: [kpi_revenue, kpi_users, kpi_orders]
|
|
95
|
+
- cols: [revenue_trend, 2] # 2 = column span
|
|
96
|
+
- cols: [by_region, by_product]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 6 — Save the Final YAML
|
|
100
|
+
|
|
101
|
+
Write the YAML under `faces/` with your normal file-edit mechanism, then:
|
|
102
|
+
|
|
103
|
+
{{ s_validate_example }}
|
|
104
|
+
|
|
105
|
+
Fix any errors `{{ s_validate_dashboard }}` reports, then re-run until it passes.
|
|
106
|
+
|
|
107
|
+
## Parameterized Queries — Use From the Start
|
|
108
|
+
|
|
109
|
+
Use `{{ variable_name }}` syntax for any configurable values, even during exploration:
|
|
110
|
+
|
|
111
|
+
```sql
|
|
112
|
+
SELECT * FROM orders WHERE region = '{{ region }}' AND date >= '{{ start_date }}'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Pass concrete values via the `variables` parameter when testing. When the query moves into dashboard YAML it works identically — and results are already cached.
|
|
116
|
+
|
|
117
|
+
**If you hardcode values during exploration and switch to variables later, the cache won't help because the SQL template changed.**
|
|
118
|
+
|
|
119
|
+
## Validate Early and Often
|
|
120
|
+
|
|
121
|
+
| Tool | When | What It Catches |
|
|
122
|
+
|------|------|-----------------|
|
|
123
|
+
| `{{ s_execute_query }}` | While drafting raw SQL | SQL errors, missing tables, wrong column names |
|
|
124
|
+
| `{{ s_validate_dashboard }}` | After every YAML edit | YAML schema errors, unknown fields, broken chart/query/layout references |
|
|
125
|
+
| `{{ s_query_face }}` | After saving YAML with named queries | Actual named-query columns and sample rows |
|
|
126
|
+
| `{{ s_render_dashboard }}` | Before delivery | Query execution, render errors, layout issues, misleading visuals |
|
|
127
|
+
|
|
128
|
+
These tools are fast. Use them after every change, not just at the end.
|
|
129
|
+
|
|
130
|
+
## Self-Review Before Delivering
|
|
131
|
+
|
|
132
|
+
Run the review skill as the final step before declaring the face done:
|
|
133
|
+
|
|
134
|
+
- {{ s_review_pointer }}
|
|
135
|
+
|
|
136
|
+
It orchestrates structural ({{ s_validate_dashboard }}) and visual (PNG + vision) passes and returns a ranked findings list. Fix each `blocker`, then re-run the review. Rendering and validation are cached — the loop is cheap.
|
|
137
|
+
|
|
138
|
+
## Data Requirements Per Chart Type
|
|
139
|
+
|
|
140
|
+
Each chart type expects data in a specific shape. Dataface validates this and errors fast — no silent magic.
|
|
141
|
+
|
|
142
|
+
| Chart Type | Expected Data | Key Fields |
|
|
143
|
+
|------------|---------------|------------|
|
|
144
|
+
| `kpi` | **Exactly 1 row** with a value column | `value` (column reference) |
|
|
145
|
+
| `line` | Multiple rows, temporal x + numeric y | `x`, `y` |
|
|
146
|
+
| `bar` | One row per category, numeric y | `x`, `y` — categorical x auto-flips to horizontal; override with `style.orientation: vertical` only when needed |
|
|
147
|
+
| `area` | Multiple rows, temporal x + numeric y | `x`, `y` |
|
|
148
|
+
| `scatter` | Multiple rows, both x and y numeric | `x`, `y` |
|
|
149
|
+
| `pie` | One row per segment (pre-aggregated) | `theta` (numeric) + `color` (category) |
|
|
150
|
+
| `heatmap` | One row per cell (pre-aggregated) | `x`, `y`, `color` |
|
|
151
|
+
| `table` | Any number of rows and columns | Use `style.columns` for per-column formatting: `- column: amount` / `format: currency_whole` / `label: Amount` / `align: right` / `width: 120` |
|
|
152
|
+
|
|
153
|
+
**Critical rules:**
|
|
154
|
+
|
|
155
|
+
- **KPI charts require exactly 1 row.** Aggregate to a single row: `SELECT SUM(amount) AS total FROM orders`. Multiple KPIs need separate single-row queries (or one query with multiple columns).
|
|
156
|
+
- **Pie and heatmap expect pre-aggregated data.** Use `GROUP BY` in the query. Dataface does NOT aggregate for you.
|
|
157
|
+
|
|
158
|
+
## Formatting Numbers
|
|
159
|
+
|
|
160
|
+
Dataface auto-detects number format from column name and DB type — omit `format:` when auto-detection would produce the correct result (e.g. a column named `conversion_rate` already renders as a percentage).
|
|
161
|
+
|
|
162
|
+
When you do need an explicit format, use a named preset instead of a raw D3 string:
|
|
163
|
+
|
|
164
|
+
| Preset | Example output |
|
|
165
|
+
|--------|---------------|
|
|
166
|
+
| `integer` | `1,234` |
|
|
167
|
+
| `currency_whole` | `$1,234` |
|
|
168
|
+
| `currency_compact` | `$1.2M` |
|
|
169
|
+
| `percent` | `2.3%` — input is decimal fraction (0.023) |
|
|
170
|
+
| `percent_number` | `2.3%` — input is whole-number percent (2.3) |
|
|
171
|
+
| `percent_delta` | `+2.3%` — input is decimal fraction |
|
|
172
|
+
| `percent_number_delta` | `+2.3%` — input is whole-number (2.3) |
|
|
173
|
+
|
|
174
|
+
Full preset list and auto-detection rules: see `dashboard-structural-review`.
|
|
175
|
+
|
|
176
|
+
## Common Mistakes
|
|
177
|
+
|
|
178
|
+
| Mistake | Fix |
|
|
179
|
+
|---------|-----|
|
|
180
|
+
| Building the entire dashboard in one pass | Build one chart at a time |
|
|
181
|
+
| Writing SQL without checking column names | Use `{{ s_schema }}`, `{{ s_schema_search }}`, or `{{ s_execute_query }}` first |
|
|
182
|
+
| Hardcoding values during exploration | Use `{{ variables }}` from the start so the query cache survives |
|
|
183
|
+
| Skipping validation between changes | `{{ s_validate_dashboard }}` after every YAML edit |
|
|
184
|
+
| Too many charts (>8) | Split into multiple dashboards |
|
|
185
|
+
| Using chart-type names as keys in layout | `table:` or `bar:` as keys cause parse errors — use descriptive names like `revenue_table` |
|
|
186
|
+
| Referencing query names in layout | Layout references charts, not queries — create a chart that wraps the query |
|
|
187
|
+
| KPI query returns multiple rows | Use `SUM()`/`COUNT()`/`AVG()` to aggregate to 1 row |
|
|
188
|
+
| Pie with raw unaggregated data | `GROUP BY` in query to aggregate before charting |
|
|
189
|
+
| Putting `height:` or `aspect_ratio:` under `style:` | Move them to chart root: `charts.my_chart.height: 400` — `style:` is paint only |
|
|
190
|
+
| Writing raw D3 format strings (`"$,.2s"`, `".1%"`) | Use a named preset (`currency_compact`, `percent`) — clearer and theme-consistent |
|
|
191
|
+
| Setting `format:` when auto-detection already matches | Omit `format:` for columns like `*_pct`, `*_rate`, `*revenue*` — auto handles them |
|
|
192
|
+
| Nesting `columns`/`values` under `sql:` for inline data | `sql:` is a string — inline data lives directly under the query name: `queries.my_data.columns: [...]` and `queries.my_data.values: [[...]]` |
|
|
193
|
+
| Filtering a multiselect with `{{ plans \| map('tojson') \| join(', ') }}` | `tojson` produces double-quoted strings that SQL treats as column refs — silent empty result, `dft render` exits 0. Use `{{ filter('plan', plans) }}` instead. |
|
|
194
|
+
|
|
195
|
+
## Rationalizations to Resist
|
|
196
|
+
|
|
197
|
+
| Excuse | Reality |
|
|
198
|
+
|--------|---------|
|
|
199
|
+
| "User asked for the whole dashboard at once" | Build incrementally anyway. Iterate to the result, don't one-shot it. |
|
|
200
|
+
| "I know what the columns are called" | You don't. Check with `{{ s_schema }}`, `{{ s_schema_search }}`, or `{{ s_execute_query }}`. |
|
|
201
|
+
| "Validation is slow, I'll do it at the end" | Validation is instant. Skipping it costs more time debugging later. |
|
|
202
|
+
| "It's just a quick chart, no need for variables" | Variables cost nothing and enable caching. Use them. |
|
|
203
|
+
| "User wants 15 charts on one dashboard" | 8 max. Propose splitting into focused dashboards. |
|
|
204
|
+
|
|
205
|
+
## Red Flags — STOP
|
|
206
|
+
|
|
207
|
+
- About to write SQL without having explored the actual schema first
|
|
208
|
+
- Building more than one new chart before validating the previous one
|
|
209
|
+
- Dashboard has more than 8 visualizations
|
|
210
|
+
- A chart exists without a clear question it answers
|
|
211
|
+
- Using hardcoded values that should be variables
|
|
212
|
+
- Delivering without running the self-review checklist
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dashboard-design
|
|
3
|
+
kind: workflow
|
|
4
|
+
description: >
|
|
5
|
+
Design principles for Dataface dashboards — at-a-glance monitoring displays.
|
|
6
|
+
Use when choosing chart types, designing dashboard layouts, picking colors,
|
|
7
|
+
deciding dashboard vs report, or when the user says 'what chart type',
|
|
8
|
+
'how should I lay this out', 'dashboard design'. Covers information
|
|
9
|
+
hierarchy, chart selection, layout patterns, and visual design. Do NOT
|
|
10
|
+
use for reports or narrative analyses (use report-design). Do
|
|
11
|
+
NOT use for the build-test-iterate workflow (use
|
|
12
|
+
dashboard-build). Do NOT use for fixing errors (use
|
|
13
|
+
dataface-troubleshooting).
|
|
14
|
+
metadata:
|
|
15
|
+
author: fivetran
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Dashboard Design
|
|
19
|
+
|
|
20
|
+
Design dashboards for **at-a-glance monitoring** — clear, scannable, action-oriented displays.
|
|
21
|
+
|
|
22
|
+
> Implementing in YAML? Switch to `{{ s_skill_build }}` for the build-test-iterate workflow.
|
|
23
|
+
|
|
24
|
+
## Dashboard vs. Report
|
|
25
|
+
|
|
26
|
+
| | Dashboard | Report |
|
|
27
|
+
|--|-----------|--------|
|
|
28
|
+
| **Purpose** | Monitor status at a glance | Answer a question, tell a story |
|
|
29
|
+
| **Frequency** | Daily / continuous | One-time or periodic |
|
|
30
|
+
| **Text** | Minimal — titles and labels | Extensive — narrative + recommendations |
|
|
31
|
+
| **Charts** | Primary content | Supporting evidence for the narrative |
|
|
32
|
+
| **Interaction** | Scan in seconds | Read in minutes |
|
|
33
|
+
|
|
34
|
+
If the user needs a narrative analysis, use the `report-design` skill instead.
|
|
35
|
+
|
|
36
|
+
## Core Principles
|
|
37
|
+
|
|
38
|
+
1. **Single screen** — no scrolling. If it doesn't fit, split into multiple dashboards.
|
|
39
|
+
2. **Scannable in seconds** — a glance should convey status.
|
|
40
|
+
3. **Every element earns its place** — remove anything that doesn't aid understanding.
|
|
41
|
+
4. **Context for every number** — a number without comparison (trend, target, prior period) is meaningless.
|
|
42
|
+
5. **Purpose-driven** — every chart answers a specific question.
|
|
43
|
+
|
|
44
|
+
## Metadata Requirement
|
|
45
|
+
|
|
46
|
+
Whenever you output or edit Dataface YAML, add `description` metadata:
|
|
47
|
+
|
|
48
|
+
- `queries.*.description` for query intent
|
|
49
|
+
- `charts.*.description` for chart intent
|
|
50
|
+
- `variables.*.description` for filter semantics
|
|
51
|
+
- Layout object `description` fields (`rows`/`cols`/`grid.items`/`tabs.items`) when they add context
|
|
52
|
+
|
|
53
|
+
Descriptions should be concise and optimized for AI retrieval.
|
|
54
|
+
|
|
55
|
+
## Thinking Process
|
|
56
|
+
|
|
57
|
+
Before designing, work through these in order:
|
|
58
|
+
|
|
59
|
+
### 1. Audience & Purpose
|
|
60
|
+
|
|
61
|
+
- **Who** views this? (executive, analyst, operator)
|
|
62
|
+
- **When** do they view it? (morning standup, weekly review, always-on monitor)
|
|
63
|
+
- **What decision** does this inform?
|
|
64
|
+
|
|
65
|
+
### 2. Information Hierarchy
|
|
66
|
+
|
|
67
|
+
- What is the **#1 most important metric**? → top-left, largest
|
|
68
|
+
- What are the **3-5 supporting KPIs**? → KPI row
|
|
69
|
+
- What **trends** matter? → line/area charts
|
|
70
|
+
- What **comparisons** are useful? → bar charts
|
|
71
|
+
- What **detail** supports drill-down? → tables at the bottom
|
|
72
|
+
|
|
73
|
+
### 3. Chart Selection
|
|
74
|
+
|
|
75
|
+
| Question | Chart Type | Notes |
|
|
76
|
+
|----------|-----------|-------|
|
|
77
|
+
| Current value? | `kpi` | Big number, prominent position |
|
|
78
|
+
| Trending over time? | `line` | Continuous data, time on x-axis |
|
|
79
|
+
| Category comparison? | `bar` | Categorical x-axis, include zero baseline |
|
|
80
|
+
| Composition over time? | `area` (stacked) | Parts of a whole changing |
|
|
81
|
+
| Portion of whole? | `pie` | **Only for 2-3 segments** — use bar for more |
|
|
82
|
+
| Relationship? | `scatter` | Two numeric variables |
|
|
83
|
+
| Precise values? | `table` | When exact numbers matter |
|
|
84
|
+
|
|
85
|
+
**Avoid:**
|
|
86
|
+
- Pie for >3 categories (humans compare angles poorly — use bar)
|
|
87
|
+
- Multiple chart types for visual variety (consistency aids scanning)
|
|
88
|
+
- Scrolling layouts (if it scrolls, it's a report)
|
|
89
|
+
|
|
90
|
+
### 4. Layout — Inverted Pyramid
|
|
91
|
+
|
|
92
|
+
Most important information first, following Western reading pattern (top-left → bottom-right):
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
┌──────────────────────────────────────────────┐
|
|
96
|
+
│ KPI 1 │ KPI 2 │ KPI 3 │ KPI 4 │ ← HEADLINE
|
|
97
|
+
├──────────────────────────────────────────────┤
|
|
98
|
+
│ Primary trend chart (line/area) │ ← STORY
|
|
99
|
+
├──────────────────────┬───────────────────────┤
|
|
100
|
+
│ Comparison chart │ Comparison chart │ ← CONTEXT
|
|
101
|
+
├──────────────────────┴───────────────────────┤
|
|
102
|
+
│ Detail table (if needed) │ ← EVIDENCE
|
|
103
|
+
└──────────────────────────────────────────────┘
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- **4-8 total visualizations maximum**
|
|
107
|
+
- Related metrics grouped by proximity
|
|
108
|
+
- Consistent styling throughout
|
|
109
|
+
|
|
110
|
+
### 5. Color & Visual Design
|
|
111
|
+
|
|
112
|
+
- **Gray is default** — muted everything, ONE accent color for emphasis
|
|
113
|
+
- **Color carries meaning** — same color = same meaning everywhere
|
|
114
|
+
- **Direct labels** on charts when possible, not separate legends
|
|
115
|
+
- **Maximize data-ink ratio** — every pixel should represent data
|
|
116
|
+
|
|
117
|
+
### 6. Numeric Display
|
|
118
|
+
|
|
119
|
+
Apply standard numeric-display judgment (two-numeral rule, no false precision, tabular numerals in columns). Dataface-specific defaults:
|
|
120
|
+
|
|
121
|
+
- **Use format aliases, not raw d3 specs.** `format: currency_whole`, `format: percent`, `format: percent_delta`, `format: integer`, `format: compact`. Raw d3 (`"$,.0f"`) only when no alias fits.
|
|
122
|
+
- **Drop cents above $10.** `format: currency_whole` is the dashboard default. Reserve `format: currency` (with cents) for reconciliation surfaces — billing, financial statements.
|
|
123
|
+
- **Notation family: analytic for chrome, narrative for prose.** Analytic (`$2.5 M`, space, uppercase K/M/B) for axes, KPIs, tables, tooltips. Narrative (`$2.5mn`, no space, lowercase) only for text cards, titles, annotations. Independent of theme choice.
|
|
124
|
+
- **Zero strips trailing decimals even when siblings have them.** A `$0` KPI uses `currency_whole` even if its partner uses `currency`. A `0%` KPI uses `percent_whole` even if its partner uses `.2%`. The rule generalizes to any unit.
|
|
125
|
+
- **Percent precision is a group decision.** Default by magnitude: ≥20% → `.0%`; 1–20% → `.1%`; <1% → `.2%`. **Modulate by surface:** a single KPI or short rail can afford one more decimal; a long table column or axis wants the simpler form. **Override:** when tenths carry signal regardless of magnitude (A/B rates, churn, conversion in a tight range), use `format: ".2%"`.
|
|
126
|
+
- **Compaction is a group decision, not per-value.** Compact when ≥4 similar-magnitude values exceed 10,000, or when surface density demands it. Adjacent surfaces showing the same metric may compact differently — a reconciliation table can show full precision while the headline KPI uses `currency_compact`.
|
|
127
|
+
- **NULL renders as `—` (em-dash), never `0`.** Different claims about the data.
|
|
128
|
+
- **Tables anchor the currency symbol.** Default `symbol_mode: anchors` — first row carries the `$`, rows below don't.
|
|
129
|
+
|
|
130
|
+
### 7. Variables & Interactivity
|
|
131
|
+
|
|
132
|
+
Add variables when the dashboard serves different time windows or segments:
|
|
133
|
+
|
|
134
|
+
- Date ranges → `daterange` input
|
|
135
|
+
- Categorical filters → `select` input
|
|
136
|
+
- Set sensible defaults (last 30 days, most common category)
|
|
137
|
+
- **NOT for executive dashboards** — those show the single most important view
|
|
138
|
+
|
|
139
|
+
## Dashboard Patterns
|
|
140
|
+
|
|
141
|
+
### Executive Dashboard
|
|
142
|
+
4-6 KPIs → main trend → 2-3 breakdowns. No interaction. Show the single most important view.
|
|
143
|
+
|
|
144
|
+
### Operational Dashboard
|
|
145
|
+
Status KPIs with alerts → recent activity → issues table. Emphasize what needs attention now.
|
|
146
|
+
|
|
147
|
+
### Analytical Dashboard
|
|
148
|
+
KPIs → trends with filters → comparisons across dimensions → detail table. Include `variables:` for interactive filtering.
|
|
149
|
+
|
|
150
|
+
## Quality Checklist
|
|
151
|
+
|
|
152
|
+
Before delivering:
|
|
153
|
+
|
|
154
|
+
- [ ] Fits on one screen (≤8 visualizations, no scrolling)
|
|
155
|
+
- [ ] KPIs are first and most prominent (top row)
|
|
156
|
+
- [ ] Every number has context (comparison, trend, or target)
|
|
157
|
+
- [ ] Chart types match the analytical question
|
|
158
|
+
- [ ] Related metrics grouped by proximity
|
|
159
|
+
- [ ] Color is purposeful, not decorative
|
|
160
|
+
- [ ] Titles are informative ("Revenue by Region, Last 30 Days" not "Chart 1")
|
|
161
|
+
- [ ] User's most important question answered at a glance
|
|
162
|
+
- [ ] Query/chart/variable/layout `description` metadata is filled for AI context
|
|
163
|
+
|
|
164
|
+
## Common Mistakes
|
|
165
|
+
|
|
166
|
+
| Mistake | Fix |
|
|
167
|
+
|---------|-----|
|
|
168
|
+
| Too many charts (>8) | Split into multiple focused dashboards |
|
|
169
|
+
| KPIs without context | Add comparison period, trend, or target |
|
|
170
|
+
| Pie chart with 7 segments | Use a bar chart instead |
|
|
171
|
+
| Decorative color | Color must encode data or meaning |
|
|
172
|
+
| Generic titles | Titles should state what the chart answers |
|
|
173
|
+
| Scrolling dashboard | Reduce charts or split dashboards |
|
|
174
|
+
|
|
175
|
+
## Rationalizations to Resist
|
|
176
|
+
|
|
177
|
+
| Excuse | Reality |
|
|
178
|
+
|--------|---------|
|
|
179
|
+
| "User asked for 12 metrics on one page" | 8 max. Propose splitting into focused dashboards. |
|
|
180
|
+
| "Pie chart is fine for 6 categories" | It's not — humans compare angles poorly. Use bar. |
|
|
181
|
+
| "The legend explains the colors" | Direct labels are always better than legends. |
|
|
182
|
+
| "More charts = more value" | More charts = more noise. Each must earn its place. |
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dashboard-review
|
|
3
|
+
kind: workflow
|
|
4
|
+
description: >
|
|
5
|
+
Primary entry point for reviewing a Dataface face. Runs
|
|
6
|
+
`dashboard-structural-review` first, then runs `dashboard-visual-review` when
|
|
7
|
+
the user asked for visual review or when structural surfaced ambiguous
|
|
8
|
+
"feels wrong" findings. Synthesizes both passes into a single ranked,
|
|
9
|
+
deduplicated findings list. Use when asked to 'review this dashboard',
|
|
10
|
+
'review this face', 'is this dashboard good', or after building / editing a
|
|
11
|
+
face before delivery. Do NOT use when only one pass is needed — invoke the
|
|
12
|
+
leaf skill directly. Do NOT use for comparing two versions of a face (use
|
|
13
|
+
the looker-compare-diff pattern).
|
|
14
|
+
metadata:
|
|
15
|
+
author: fivetran
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Dashboard Review
|
|
19
|
+
|
|
20
|
+
Orchestrate `dashboard-structural-review` and `dashboard-visual-review` into a
|
|
21
|
+
single ranked findings list. This is the default entry point — most "review"
|
|
22
|
+
requests should land here, not on either leaf skill.
|
|
23
|
+
|
|
24
|
+
## When to use
|
|
25
|
+
|
|
26
|
+
- Any open-ended "review this dashboard" request
|
|
27
|
+
- Pre-delivery final pass
|
|
28
|
+
- After a substantive edit (new chart, new query, layout change)
|
|
29
|
+
|
|
30
|
+
## When NOT to use
|
|
31
|
+
|
|
32
|
+
- The user explicitly asked for only structural OR only visual — invoke that
|
|
33
|
+
leaf skill directly
|
|
34
|
+
- Comparing two versions of a face — use the `looker-compare-diff` pattern
|
|
35
|
+
|
|
36
|
+
## Protocol
|
|
37
|
+
|
|
38
|
+
### Step 1: Always run structural review
|
|
39
|
+
|
|
40
|
+
Invoke `dashboard-structural-review` first. It's cheap (no rendering, no
|
|
41
|
+
vision tokens) and catches every problem that's visible in the YAML.
|
|
42
|
+
|
|
43
|
+
### Step 2: Decide whether to run visual review
|
|
44
|
+
|
|
45
|
+
Run `dashboard-visual-review` when **any** of the following is true:
|
|
46
|
+
|
|
47
|
+
- The user asked for visual review explicitly ("how does it look", "review the
|
|
48
|
+
rendered output", "visual review", "check the design")
|
|
49
|
+
- Structural review surfaced a finding that hints at a visual problem (KPI
|
|
50
|
+
precision, generic title that may collide with axis labels, dense chart
|
|
51
|
+
count that may crowd the canvas)
|
|
52
|
+
- Structural review returned `**No findings.**` and the user asked for a
|
|
53
|
+
thorough review — do the visual pass to confirm
|
|
54
|
+
|
|
55
|
+
Skip visual review when:
|
|
56
|
+
|
|
57
|
+
- Structural review surfaced `blocker` findings — fix those first; rendering
|
|
58
|
+
may be misleading until the YAML is correct
|
|
59
|
+
- The user asked for a quick / cheap review
|
|
60
|
+
- `{{ s_validate_dashboard }}` failed inside
|
|
61
|
+
structural review — there's nothing valid to render yet
|
|
62
|
+
|
|
63
|
+
### Step 3: Synthesize
|
|
64
|
+
|
|
65
|
+
Merge findings from both passes into a single list:
|
|
66
|
+
|
|
67
|
+
1. **Deduplicate.** If both passes surface the same issue (e.g. structural
|
|
68
|
+
notes the KPI has no format spec and visual notes the rendered number is
|
|
69
|
+
`1247392.74`), keep the more concrete finding.
|
|
70
|
+
2. **Order by severity.** All `blocker` findings before `warning` before
|
|
71
|
+
`nit`. Within a severity, keep the order each pass produced.
|
|
72
|
+
3. **Cap at 5** by default. If you have to drop findings, drop `nit` first,
|
|
73
|
+
then `warning`. Never drop a `blocker`.
|
|
74
|
+
4. **Tag the source** so the user knows which pass surfaced what.
|
|
75
|
+
|
|
76
|
+
## Output format
|
|
77
|
+
|
|
78
|
+
```markdown
|
|
79
|
+
**Dashboard review**
|
|
80
|
+
|
|
81
|
+
- `blocker` [structural] `charts.revenue_kpi`: query returns 12 rows but
|
|
82
|
+
`type: kpi` requires 1. Aggregate with `SUM()`.
|
|
83
|
+
- `warning` [visual] `charts.regions_bar`: x-axis labels overlap at rendered
|
|
84
|
+
width. Rotate to -45° or shorten.
|
|
85
|
+
- `warning` [structural] `queries.orders`: no `description:` field. Add one
|
|
86
|
+
sentence stating intent.
|
|
87
|
+
- `nit` [visual] `charts.users_pie`: muted palette would reduce visual noise.
|
|
88
|
+
|
|
89
|
+
**Passes run:** structural, visual
|
|
90
|
+
**Skipped:** —
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If neither pass found anything: emit `**Dashboard review: no findings.**`.
|
|
94
|
+
|
|
95
|
+
If a pass was skipped, name it in `**Skipped:**` with a one-phrase reason
|
|
96
|
+
(`Skipped: visual — blockers in structural pass`).
|
|
97
|
+
|
|
98
|
+
## Common mistakes
|
|
99
|
+
|
|
100
|
+
| Mistake | Fix |
|
|
101
|
+
|---|---|
|
|
102
|
+
| Running visual review before structural | Always structural first. Visual depends on a render that won't be meaningful until the YAML is valid. |
|
|
103
|
+
| Skipping structural because "it's just visual" | The YAML is the source of truth — never skip structural. |
|
|
104
|
+
| Padding the synthesized list to fill a cap | If both passes agreed there are only 2 findings, return 2. |
|
|
105
|
+
| Forgetting to tag pass source | The user needs `[structural]` / `[visual]` to know where to look. |
|
|
106
|
+
|
|
107
|
+
## Rationalizations to resist
|
|
108
|
+
|
|
109
|
+
| Excuse | Reality |
|
|
110
|
+
|---|---|
|
|
111
|
+
| "User said 'review' — they probably only want a quick check" | Default to thorough. The user can ask for cheap explicitly. |
|
|
112
|
+
| "Visual review is slow, let's skip it" | If a render is fast on this face (most are), do both passes by default. Cost is a real concern only at scale. |
|
|
113
|
+
| "Both passes are saying the same thing, I'll keep both" | Dedupe. Showing the same issue twice erodes trust. |
|