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.
Files changed (455) hide show
  1. d3_format/__init__.py +14 -0
  2. d3_format/errors.py +19 -0
  3. d3_format/format.py +551 -0
  4. d3_format/spec.py +159 -0
  5. dataface/DATAFACE_SYNTAX.md +1135 -0
  6. dataface/__init__.py +93 -0
  7. dataface/_docs_site.py +20 -0
  8. dataface/_install_hint.py +26 -0
  9. dataface/agent_api/__init__.py +79 -0
  10. dataface/agent_api/_init_templates/__init__.py +0 -0
  11. dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
  12. dataface/agent_api/_init_templates/dataface.yml +15 -0
  13. dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
  14. dataface/agent_api/_init_templates/index.md +24 -0
  15. dataface/agent_api/_paths.py +118 -0
  16. dataface/agent_api/_project_agents_md.py +43 -0
  17. dataface/agent_api/_session_store.py +486 -0
  18. dataface/agent_api/_state.py +28 -0
  19. dataface/agent_api/chat.py +221 -0
  20. dataface/agent_api/dashboards.py +257 -0
  21. dataface/agent_api/describe.py +366 -0
  22. dataface/agent_api/describe_query.py +120 -0
  23. dataface/agent_api/docs/__init__.py +25 -0
  24. dataface/agent_api/docs/_loader.py +292 -0
  25. dataface/agent_api/docs/yaml-reference.md +2757 -0
  26. dataface/agent_api/file_refs.py +118 -0
  27. dataface/agent_api/init.py +126 -0
  28. dataface/agent_api/inspect.py +128 -0
  29. dataface/agent_api/mcp_install.py +170 -0
  30. dataface/agent_api/query.py +274 -0
  31. dataface/agent_api/schema.py +658 -0
  32. dataface/agent_api/schema_search.py +284 -0
  33. dataface/agent_api/search.py +270 -0
  34. dataface/agent_api/skill_install.py +141 -0
  35. dataface/agent_api/skill_render.py +90 -0
  36. dataface/agent_api/skills.py +293 -0
  37. dataface/agent_api/surface_aliases.yaml +128 -0
  38. dataface/agent_api/validate.py +175 -0
  39. dataface/agent_api/validate_query.py +84 -0
  40. dataface/ai/__init__.py +39 -0
  41. dataface/ai/agent.py +139 -0
  42. dataface/ai/context.py +45 -0
  43. dataface/ai/events.py +62 -0
  44. dataface/ai/external_mcp.py +610 -0
  45. dataface/ai/generate_sql.py +96 -0
  46. dataface/ai/llm.py +403 -0
  47. dataface/ai/mcp/__init__.py +51 -0
  48. dataface/ai/mcp/server.py +289 -0
  49. dataface/ai/memories.py +85 -0
  50. dataface/ai/prompts.py +177 -0
  51. dataface/ai/schema_context.py +138 -0
  52. dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
  53. dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
  54. dataface/ai/skills/dashboard-build/SKILL.md +212 -0
  55. dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
  56. dataface/ai/skills/dashboard-design/SKILL.md +182 -0
  57. dataface/ai/skills/dashboard-review/SKILL.md +113 -0
  58. dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
  59. dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
  60. dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
  61. dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
  62. dataface/ai/skills/drill-down-link/SKILL.md +112 -0
  63. dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
  64. dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
  65. dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
  66. dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
  67. dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
  68. dataface/ai/skills/kpi-row/SKILL.md +101 -0
  69. dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
  70. dataface/ai/skills/report-design/SKILL.md +184 -0
  71. dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
  72. dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
  73. dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
  74. dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
  75. dataface/ai/skills/time-series-trend/SKILL.md +93 -0
  76. dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
  77. dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
  78. dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
  79. dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
  80. dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
  81. dataface/ai/tool_schemas.py +132 -0
  82. dataface/ai/tools/__init__.py +312 -0
  83. dataface/ai/yaml_utils.py +57 -0
  84. dataface/cli/__init__.py +3 -0
  85. dataface/cli/_console.py +48 -0
  86. dataface/cli/_error_format.py +83 -0
  87. dataface/cli/_extras.py +190 -0
  88. dataface/cli/_json_output.py +8 -0
  89. dataface/cli/_parsing.py +17 -0
  90. dataface/cli/_version_info.py +56 -0
  91. dataface/cli/commands/__init__.py +3 -0
  92. dataface/cli/commands/_agent_input.py +205 -0
  93. dataface/cli/commands/_agent_server.py +115 -0
  94. dataface/cli/commands/chat.py +645 -0
  95. dataface/cli/commands/describe.py +107 -0
  96. dataface/cli/commands/docs.py +131 -0
  97. dataface/cli/commands/extension.py +179 -0
  98. dataface/cli/commands/init.py +240 -0
  99. dataface/cli/commands/inspect.py +94 -0
  100. dataface/cli/commands/mcp_init.py +167 -0
  101. dataface/cli/commands/query.py +386 -0
  102. dataface/cli/commands/render.py +291 -0
  103. dataface/cli/commands/schema.py +411 -0
  104. dataface/cli/commands/search.py +49 -0
  105. dataface/cli/commands/serve.py +114 -0
  106. dataface/cli/commands/skills.py +133 -0
  107. dataface/cli/commands/skills_init.py +161 -0
  108. dataface/cli/commands/validate.py +63 -0
  109. dataface/cli/main.py +1501 -0
  110. dataface/core/__init__.py +75 -0
  111. dataface/core/compile/__init__.py +244 -0
  112. dataface/core/compile/_jinja_helpers.py +78 -0
  113. dataface/core/compile/channel.py +222 -0
  114. dataface/core/compile/chart_focus.py +101 -0
  115. dataface/core/compile/chart_resolved.py +169 -0
  116. dataface/core/compile/chart_type_detection.py +489 -0
  117. dataface/core/compile/chart_update.py +261 -0
  118. dataface/core/compile/colors.py +64 -0
  119. dataface/core/compile/compiler.py +904 -0
  120. dataface/core/compile/config.py +823 -0
  121. dataface/core/compile/custom_chart_types.py +208 -0
  122. dataface/core/compile/data_table_attachment.py +1287 -0
  123. dataface/core/compile/detect.py +110 -0
  124. dataface/core/compile/errors.py +302 -0
  125. dataface/core/compile/filter_injection.py +319 -0
  126. dataface/core/compile/introspection.py +527 -0
  127. dataface/core/compile/jinja.py +511 -0
  128. dataface/core/compile/labels_env.py +52 -0
  129. dataface/core/compile/markdown.py +154 -0
  130. dataface/core/compile/meta.py +388 -0
  131. dataface/core/compile/models/__init__.py +0 -0
  132. dataface/core/compile/models/chart/__init__.py +0 -0
  133. dataface/core/compile/models/chart/authored.py +2137 -0
  134. dataface/core/compile/models/chart/compiled.py +398 -0
  135. dataface/core/compile/models/config.py +347 -0
  136. dataface/core/compile/models/face/__init__.py +0 -0
  137. dataface/core/compile/models/face/authored.py +659 -0
  138. dataface/core/compile/models/face/compiled.py +522 -0
  139. dataface/core/compile/models/factories.py +201 -0
  140. dataface/core/compile/models/markers.py +40 -0
  141. dataface/core/compile/models/palette.py +36 -0
  142. dataface/core/compile/models/primitives.py +415 -0
  143. dataface/core/compile/models/query/__init__.py +0 -0
  144. dataface/core/compile/models/query/authored.py +246 -0
  145. dataface/core/compile/models/query/compiled.py +710 -0
  146. dataface/core/compile/models/refs.py +137 -0
  147. dataface/core/compile/models/source.py +611 -0
  148. dataface/core/compile/models/style/__init__.py +0 -0
  149. dataface/core/compile/models/style/authored.py +481 -0
  150. dataface/core/compile/models/style/compiled.py +3399 -0
  151. dataface/core/compile/models/style/merged.py +1682 -0
  152. dataface/core/compile/models/theme.py +362 -0
  153. dataface/core/compile/models/variable/__init__.py +0 -0
  154. dataface/core/compile/models/variable/authored.py +254 -0
  155. dataface/core/compile/models/vega_lite/__init__.py +0 -0
  156. dataface/core/compile/models/vega_lite/config.py +510 -0
  157. dataface/core/compile/models/vega_lite/contracts.py +171 -0
  158. dataface/core/compile/normalize_charts.py +494 -0
  159. dataface/core/compile/normalize_layout.py +1000 -0
  160. dataface/core/compile/normalize_queries.py +297 -0
  161. dataface/core/compile/normalize_variables.py +489 -0
  162. dataface/core/compile/normalizer.py +543 -0
  163. dataface/core/compile/palette.py +1100 -0
  164. dataface/core/compile/parameterized.py +658 -0
  165. dataface/core/compile/parser.py +228 -0
  166. dataface/core/compile/schema.py +20 -0
  167. dataface/core/compile/schema_renderers/__init__.py +0 -0
  168. dataface/core/compile/schema_renderers/json_schema.py +163 -0
  169. dataface/core/compile/schema_renderers/prompt.py +152 -0
  170. dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
  171. dataface/core/compile/sizing.py +2126 -0
  172. dataface/core/compile/sources.py +518 -0
  173. dataface/core/compile/sql_authoring_lint.py +56 -0
  174. dataface/core/compile/style_cascade.py +471 -0
  175. dataface/core/compile/typography.py +299 -0
  176. dataface/core/compile/validator.py +301 -0
  177. dataface/core/compile/variables.py +53 -0
  178. dataface/core/compile/vega_config.py +98 -0
  179. dataface/core/compile/vega_lite/__init__.py +6 -0
  180. dataface/core/compile/vega_lite/validation.py +95 -0
  181. dataface/core/compile/yaml_error_formatter.py +838 -0
  182. dataface/core/connections.py +38 -0
  183. dataface/core/dashboard.py +358 -0
  184. dataface/core/defaults/default_config.yml +101 -0
  185. dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
  186. dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
  187. dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
  188. dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
  189. dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
  190. dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
  191. dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
  192. dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
  193. dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
  194. dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
  195. dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
  196. dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
  197. dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
  198. dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
  199. dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
  200. dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
  201. dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
  202. dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
  203. dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
  204. dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
  205. dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
  206. dataface/core/defaults/palettes/sequential/amber.yml +22 -0
  207. dataface/core/defaults/palettes/sequential/blue.yml +22 -0
  208. dataface/core/defaults/palettes/sequential/brown.yml +22 -0
  209. dataface/core/defaults/palettes/sequential/gray.yml +22 -0
  210. dataface/core/defaults/palettes/sequential/green.yml +22 -0
  211. dataface/core/defaults/palettes/sequential/purple.yml +22 -0
  212. dataface/core/defaults/palettes/sequential/rust.yml +22 -0
  213. dataface/core/defaults/palettes/sequential/teal.yml +22 -0
  214. dataface/core/defaults/palettes/tone/negative.yml +32 -0
  215. dataface/core/defaults/palettes/tone/positive.yml +22 -0
  216. dataface/core/defaults/palettes/tone/warning.yml +22 -0
  217. dataface/core/defaults/themes/_base.yaml +786 -0
  218. dataface/core/defaults/themes/bi.yaml +16 -0
  219. dataface/core/defaults/themes/carbong100.yaml +41 -0
  220. dataface/core/defaults/themes/cream.yaml +122 -0
  221. dataface/core/defaults/themes/dark.yaml +40 -0
  222. dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
  223. dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
  224. dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
  225. dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
  226. dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
  227. dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
  228. dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
  229. dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
  230. dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
  231. dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
  232. dataface/core/defaults/themes/editorial.yaml +147 -0
  233. dataface/core/defaults/themes/light.yaml +30 -0
  234. dataface/core/defaults/themes/looker.yaml +17 -0
  235. dataface/core/defaults/themes/stark.yaml +134 -0
  236. dataface/core/errors/__init__.py +67 -0
  237. dataface/core/errors/codes_compile.py +56 -0
  238. dataface/core/errors/codes_execute.py +177 -0
  239. dataface/core/errors/codes_render.py +106 -0
  240. dataface/core/errors/codes_unknown.py +15 -0
  241. dataface/core/errors/hints.py +74 -0
  242. dataface/core/errors/registry.py +42 -0
  243. dataface/core/errors/structured.py +92 -0
  244. dataface/core/execute/__init__.py +91 -0
  245. dataface/core/execute/adapters/__init__.py +49 -0
  246. dataface/core/execute/adapters/adapter_registry.py +400 -0
  247. dataface/core/execute/adapters/base.py +245 -0
  248. dataface/core/execute/adapters/csv_adapter.py +239 -0
  249. dataface/core/execute/adapters/dbt_adapter.py +283 -0
  250. dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
  251. dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
  252. dataface/core/execute/adapters/dbt_utils.py +150 -0
  253. dataface/core/execute/adapters/http_adapter.py +224 -0
  254. dataface/core/execute/adapters/metricflow_adapter.py +94 -0
  255. dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
  256. dataface/core/execute/adapters/sql_adapter.py +710 -0
  257. dataface/core/execute/adapters/values_adapter.py +58 -0
  258. dataface/core/execute/batch.py +744 -0
  259. dataface/core/execute/cache_backend.py +135 -0
  260. dataface/core/execute/cache_keys.py +66 -0
  261. dataface/core/execute/dbt_jinja.py +21 -0
  262. dataface/core/execute/dialects/__init__.py +121 -0
  263. dataface/core/execute/dialects/athena.py +75 -0
  264. dataface/core/execute/dialects/base.py +302 -0
  265. dataface/core/execute/dialects/bigquery.py +38 -0
  266. dataface/core/execute/dialects/databricks.py +68 -0
  267. dataface/core/execute/dialects/duckdb.py +35 -0
  268. dataface/core/execute/dialects/mysql.py +68 -0
  269. dataface/core/execute/dialects/postgres.py +39 -0
  270. dataface/core/execute/dialects/redshift.py +12 -0
  271. dataface/core/execute/dialects/snowflake.py +51 -0
  272. dataface/core/execute/dialects/sqlserver.py +92 -0
  273. dataface/core/execute/duckdb_cache.py +712 -0
  274. dataface/core/execute/duckdb_config.py +26 -0
  275. dataface/core/execute/errors.py +213 -0
  276. dataface/core/execute/executor.py +1249 -0
  277. dataface/core/execute/parallel.py +162 -0
  278. dataface/core/execute/setup_sql.py +58 -0
  279. dataface/core/execute/source_registry.py +72 -0
  280. dataface/core/execute/source_resolver.py +255 -0
  281. dataface/core/execute/sql_guard.py +387 -0
  282. dataface/core/execute/sql_literals.py +199 -0
  283. dataface/core/fonts.py +52 -0
  284. dataface/core/inspect/__init__.py +32 -0
  285. dataface/core/inspect/cache_factory.py +98 -0
  286. dataface/core/inspect/db_types.py +162 -0
  287. dataface/core/inspect/dbt_schema.py +96 -0
  288. dataface/core/inspect/defaults.yml +37 -0
  289. dataface/core/inspect/fanout_risk.py +109 -0
  290. dataface/core/inspect/manifest_utils.py +77 -0
  291. dataface/core/inspect/partials/categorical.yml +40 -0
  292. dataface/core/inspect/partials/date.yml +40 -0
  293. dataface/core/inspect/partials/numeric.yml +55 -0
  294. dataface/core/inspect/partition_types.py +38 -0
  295. dataface/core/inspect/query_validator.py +975 -0
  296. dataface/core/inspect/renderer.py +354 -0
  297. dataface/core/inspect/resolver.py +808 -0
  298. dataface/core/inspect/search.py +461 -0
  299. dataface/core/inspect/sources/__init__.py +32 -0
  300. dataface/core/inspect/sources/dbt.py +738 -0
  301. dataface/core/inspect/sources/duckdb_utils.py +66 -0
  302. dataface/core/inspect/templates/__init__.py +1 -0
  303. dataface/core/inspect/templates/categorical_column.yml +196 -0
  304. dataface/core/inspect/templates/charts.yml +109 -0
  305. dataface/core/inspect/templates/date_column.yml +248 -0
  306. dataface/core/inspect/templates/model.yml +138 -0
  307. dataface/core/inspect/templates/numeric_column.yml +261 -0
  308. dataface/core/inspect/templates/quality.yml +80 -0
  309. dataface/core/inspect/templates/string_column.yml +263 -0
  310. dataface/core/project_roots.py +165 -0
  311. dataface/core/render/__init__.py +87 -0
  312. dataface/core/render/board_links.py +176 -0
  313. dataface/core/render/chart/__init__.py +27 -0
  314. dataface/core/render/chart/arc_attached_table.py +251 -0
  315. dataface/core/render/chart/artifacts.py +16 -0
  316. dataface/core/render/chart/callout.py +225 -0
  317. dataface/core/render/chart/decisions.py +358 -0
  318. dataface/core/render/chart/geo.py +700 -0
  319. dataface/core/render/chart/kpi.py +916 -0
  320. dataface/core/render/chart/labels.py +76 -0
  321. dataface/core/render/chart/pipeline.py +818 -0
  322. dataface/core/render/chart/presentation.py +36 -0
  323. dataface/core/render/chart/profile.py +3438 -0
  324. dataface/core/render/chart/render_single.py +347 -0
  325. dataface/core/render/chart/renderers.py +193 -0
  326. dataface/core/render/chart/rendering.py +565 -0
  327. dataface/core/render/chart/serialization.py +90 -0
  328. dataface/core/render/chart/spark.py +496 -0
  329. dataface/core/render/chart/spark_bar.py +370 -0
  330. dataface/core/render/chart/spec_builders.py +154 -0
  331. dataface/core/render/chart/standard_renderer.py +2645 -0
  332. dataface/core/render/chart/table.py +2957 -0
  333. dataface/core/render/chart/table_support.py +1452 -0
  334. dataface/core/render/chart/tick_values.py +66 -0
  335. dataface/core/render/chart/time_unit_detect.py +809 -0
  336. dataface/core/render/chart/title_overflow.py +157 -0
  337. dataface/core/render/chart/type_inference.py +122 -0
  338. dataface/core/render/chart/validation.py +99 -0
  339. dataface/core/render/chart/vega_lite.py +125 -0
  340. dataface/core/render/chart/vega_lite_types.py +268 -0
  341. dataface/core/render/chart/vl_field_maps.py +346 -0
  342. dataface/core/render/chart_interactivity.py +24 -0
  343. dataface/core/render/control_registry.py +287 -0
  344. dataface/core/render/converters/__init__.py +24 -0
  345. dataface/core/render/converters/chart.py +276 -0
  346. dataface/core/render/converters/html.py +98 -0
  347. dataface/core/render/converters/pdf.py +40 -0
  348. dataface/core/render/converters/png.py +41 -0
  349. dataface/core/render/errors.py +144 -0
  350. dataface/core/render/face_api.py +160 -0
  351. dataface/core/render/faces.py +1194 -0
  352. dataface/core/render/font_measurement.py +48 -0
  353. dataface/core/render/font_support.py +197 -0
  354. dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
  355. dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
  356. dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
  357. dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
  358. dataface/core/render/fonts/InterVariable.ttf +0 -0
  359. dataface/core/render/fonts/InterVariable.woff2 +0 -0
  360. dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
  361. dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
  362. dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
  363. dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
  364. dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
  365. dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
  366. dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
  367. dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
  368. dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
  369. dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
  370. dataface/core/render/fonts/_emoji_font_face.css +43 -0
  371. dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
  372. dataface/core/render/format_utils.py +329 -0
  373. dataface/core/render/geo_defaults.yml +28 -0
  374. dataface/core/render/json_format.py +146 -0
  375. dataface/core/render/layout_sizing.py +865 -0
  376. dataface/core/render/layouts.py +541 -0
  377. dataface/core/render/markdown_defaults.yml +16 -0
  378. dataface/core/render/missing_vars_prompt.py +79 -0
  379. dataface/core/render/placeholder.py +389 -0
  380. dataface/core/render/render_result.py +14 -0
  381. dataface/core/render/renderer.py +467 -0
  382. dataface/core/render/script_embedding.py +16 -0
  383. dataface/core/render/svg_utils.py +212 -0
  384. dataface/core/render/template_loader.py +69 -0
  385. dataface/core/render/templates/controls/_styles.css +606 -0
  386. dataface/core/render/templates/controls/checkbox.html +16 -0
  387. dataface/core/render/templates/controls/date.html +16 -0
  388. dataface/core/render/templates/controls/number.html +19 -0
  389. dataface/core/render/templates/controls/readonly.html +9 -0
  390. dataface/core/render/templates/controls/select.html +21 -0
  391. dataface/core/render/templates/controls/slider.html +22 -0
  392. dataface/core/render/templates/controls/text.html +16 -0
  393. dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
  394. dataface/core/render/templates/scripts/variables.js +976 -0
  395. dataface/core/render/templates/svg/grid_pattern.svg +3 -0
  396. dataface/core/render/templates/svg/styles.css +51 -0
  397. dataface/core/render/terminal.py +311 -0
  398. dataface/core/render/terminal_charts.py +563 -0
  399. dataface/core/render/terminal_defaults.yml +2 -0
  400. dataface/core/render/terminal_layouts.py +299 -0
  401. dataface/core/render/terminal_text.py +31 -0
  402. dataface/core/render/text/__init__.py +1 -0
  403. dataface/core/render/text/case.py +113 -0
  404. dataface/core/render/text_format.py +129 -0
  405. dataface/core/render/utils.py +106 -0
  406. dataface/core/render/variable_controls.py +946 -0
  407. dataface/core/render/variable_input_refinement.py +140 -0
  408. dataface/core/render/warnings/__init__.py +15 -0
  409. dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
  410. dataface/core/render/warnings/base.py +44 -0
  411. dataface/core/render/warnings/fanout_risk.py +15 -0
  412. dataface/core/render/warnings/from_query_diagnostic.py +56 -0
  413. dataface/core/render/warnings/missing_join_predicate.py +13 -0
  414. dataface/core/render/warnings/query_parse_error.py +14 -0
  415. dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
  416. dataface/core/render/warnings/reaggregation.py +14 -0
  417. dataface/core/render/warnings/registry.py +45 -0
  418. dataface/core/render/warnings/suppression.py +46 -0
  419. dataface/core/render/warnings/temporal_single_point.py +63 -0
  420. dataface/core/render/warnings/unreferenced_chart.py +15 -0
  421. dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
  422. dataface/core/render/yaml_format.py +167 -0
  423. dataface/core/resolve_face.py +195 -0
  424. dataface/core/schema/__init__.py +0 -0
  425. dataface/core/schema/guidance.py +151 -0
  426. dataface/core/scoped_paths.py +59 -0
  427. dataface/core/serve/__init__.py +14 -0
  428. dataface/core/serve/bootstrap.py +39 -0
  429. dataface/core/serve/embedded.py +57 -0
  430. dataface/core/serve/port.py +129 -0
  431. dataface/core/serve/server.py +938 -0
  432. dataface/core/serve/templates/__init__.py +0 -0
  433. dataface/core/serve/templates/directory.yml +6 -0
  434. dataface/core/serve/templates/error.html.j2 +217 -0
  435. dataface/core/utils.py +121 -0
  436. dataface/core/validate.py +64 -0
  437. dataface/integrations/__init__.py +0 -0
  438. dataface/integrations/highlighting.py +351 -0
  439. dataface/integrations/markdown.py +537 -0
  440. dataface/py.typed +0 -0
  441. dataface-0.1.2.dist-info/METADATA +375 -0
  442. dataface-0.1.2.dist-info/RECORD +455 -0
  443. dataface-0.1.2.dist-info/WHEEL +4 -0
  444. dataface-0.1.2.dist-info/entry_points.txt +2 -0
  445. dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
  446. mdsvg/__init__.py +168 -0
  447. mdsvg/fonts.py +656 -0
  448. mdsvg/images.py +299 -0
  449. mdsvg/parser.py +629 -0
  450. mdsvg/playground.py +284 -0
  451. mdsvg/py.typed +2 -0
  452. mdsvg/renderer.py +1623 -0
  453. mdsvg/style.py +355 -0
  454. mdsvg/types.py +200 -0
  455. mdsvg/utils.py +86 -0
@@ -0,0 +1,38 @@
1
+ """Public dft-core connection API.
2
+
3
+ Single exported symbol: test_connection(source_config) → (bool, str).
4
+
5
+ All DB connection machinery lives in execute/adapters/dbt_adapter_factory.py.
6
+ Cloud and other consumers call this, not dbt.adapters directly.
7
+ """
8
+
9
+ from typing import Any
10
+
11
+
12
+ def test_connection(source_config: dict[str, Any]) -> tuple[bool, str]:
13
+ """Verify that source_config can reach the database.
14
+
15
+ Constructs a fresh adapter, pings with SELECT 1, and lets GC clean up
16
+ when the local reference drops at function exit. The temp target dir is
17
+ removed by the weakref.finalize registered in build_adapter.
18
+
19
+ Args:
20
+ source_config: Dict with a 'type' key and warehouse-specific fields.
21
+ Example: {"type": "duckdb", "path": ":memory:"}
22
+
23
+ Returns:
24
+ (True, "Connection successful") on success.
25
+ (False, "<error message>") on any failure — driver missing, bad creds,
26
+ network unreachable, unsupported type, etc.
27
+ """
28
+ from dataface.core.execute.adapters.dbt_adapter_factory import build_adapter
29
+
30
+ try:
31
+ adapter = build_adapter(source_config)
32
+ with adapter.connection_named("test"):
33
+ adapter.execute("SELECT 1", auto_begin=True, fetch=True)
34
+ return True, "Connection successful"
35
+ except (
36
+ Exception # noqa: BLE001
37
+ ) as e: # broad on purpose — surfaces driver-level errors as messages
38
+ return False, str(e) or type(e).__name__
@@ -0,0 +1,358 @@
1
+ """Compile + execute + render orchestrator that returns a typed envelope.
2
+
3
+ Counterpart to `core.render.face_api.render_face`, which raises on failure
4
+ and returns raw output for external integrations (MkDocs, Sphinx). This
5
+ module's `render_dashboard` packages compile errors, chart errors, and
6
+ warnings into a `RenderedDashboard` Pydantic model — the shape the CLI
7
+ render verb, the MCP tool, and the embedded HTTP server all consume.
8
+
9
+ The agent_api dashboards module re-exports the public names so callers
10
+ reach them via `dataface.agent_api.dashboards` (the typed-verb surface).
11
+ The implementation lives here — top-level under `core` rather than under
12
+ `core/render/` — so `core.serve.server` can call it without inverting the
13
+ layer stack, and so the `dataface.core.render` function-vs-submodule name
14
+ collision doesn't break `mock.patch("dataface.core.X.dashboard.Y")` on
15
+ Python 3.10 (a real CI failure we hit when this module lived at
16
+ `core/render/dashboard.py`).
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import importlib.util as _importlib_util
22
+ from pathlib import Path
23
+ from typing import Any, Literal, get_args
24
+
25
+ from pydantic import BaseModel
26
+
27
+ from dataface.core.compile import compile, compile_file, get_project_warnings_ignore
28
+ from dataface.core.compile.errors import DatafaceError
29
+ from dataface.core.errors import (
30
+ DF_RENDER_FORMAT_UNSUPPORTED,
31
+ DF_RENDER_INPUT_INVALID,
32
+ DF_UNKNOWN_INTERNAL,
33
+ StructuredError,
34
+ )
35
+ from dataface.core.errors.structured import NextCommand
36
+ from dataface.core.execute import ExecutionError, Executor
37
+ from dataface.core.execute.adapters import AdapterRegistry
38
+ from dataface.core.execute.duckdb_cache import DuckDBCache
39
+ from dataface.core.render.warnings.base import RenderWarning
40
+ from dataface.core.render.warnings.suppression import partition as _partition_warnings
41
+
42
+ # Probe once at import time: avoids repeated find_spec calls and avoids
43
+ # the `try/except ImportError` antipattern on our own modules.
44
+ _SUPER_SCHEMA_AVAILABLE = _importlib_util.find_spec("dataface_super_schema") is not None
45
+
46
+
47
+ def _enrich_fanout_warnings_if_available(result: Any) -> None:
48
+ """Enrich compiled queries with fanout warnings when private pkg is installed."""
49
+ if not _SUPER_SCHEMA_AVAILABLE:
50
+ return
51
+ from dataface_super_schema.inspect.relationship_warnings import ( # noqa: PLC0415
52
+ enrich_dashboard_fanout_warnings,
53
+ )
54
+
55
+ enrich_dashboard_fanout_warnings(result)
56
+
57
+
58
+ from dataface.core.render import RenderError, render
59
+ from dataface.core.render.board_links import LinkContext
60
+ from dataface.core.scoped_paths import project_root_for, resolve_scoped_path
61
+
62
+ RenderFormat = Literal["svg", "html", "png", "pdf", "terminal", "json", "text", "yaml"]
63
+
64
+
65
+ class RenderedDashboard(BaseModel):
66
+ success: bool
67
+ # bytes for binary formats (png/pdf); str for text-based; dict for json.
68
+ # MCP callers should not request binary formats — `model_dump_json()` /
69
+ # `json.dumps()` in the MCP dispatcher will fail on bytes at the wire
70
+ # boundary, which is correct behaviour.
71
+ data: dict[str, Any] | str | bytes | None = None
72
+ validation_errors: list[StructuredError] = []
73
+ warnings: list[RenderWarning] = []
74
+ suppressed_warnings: list[RenderWarning] = []
75
+ chart_errors: list[StructuredError] = []
76
+ face_error: StructuredError | None = None
77
+ url: str | None = None
78
+
79
+
80
+ def _view_url(
81
+ path: Path,
82
+ variables: dict[str, Any] | None = None,
83
+ *,
84
+ port: int | None,
85
+ project_dir: Path | None = None,
86
+ ) -> str | None:
87
+ if port is None:
88
+ return None
89
+ from urllib.parse import urlencode
90
+
91
+ route_path = path
92
+ if path.is_absolute():
93
+ if project_dir is None:
94
+ return None
95
+ root = project_dir.resolve()
96
+ try:
97
+ route_path = path.resolve().relative_to(root)
98
+ except ValueError:
99
+ return None
100
+
101
+ url_path = route_path.with_suffix("").as_posix()
102
+ if url_path.startswith("faces/"):
103
+ url_path = url_path.removeprefix("faces/")
104
+ qs = "?" + urlencode(variables) if variables else ""
105
+ return f"http://localhost:{port}/{url_path}{qs}"
106
+
107
+
108
+ def _stamp_file_commands(
109
+ errors: list[StructuredError],
110
+ file_path: Path,
111
+ ) -> list[StructuredError]:
112
+ """Return errors with a 'dft validate <file>' next_command added to each.
113
+
114
+ The compile path produces StructuredErrors without file context. When we
115
+ know the file that was compiled, stamp each error so the serve/HTML layer
116
+ can render the validate button.
117
+ """
118
+ cmd = NextCommand(label="Validate", command=f"dft validate {file_path}")
119
+ return [
120
+ (
121
+ err.model_copy(update={"next_commands": [cmd]})
122
+ if not err.next_commands
123
+ else err
124
+ )
125
+ for err in errors
126
+ ]
127
+
128
+
129
+ def _input_error(message: str) -> RenderedDashboard:
130
+ """Build a RenderedDashboard failure from a plain input-validation message.
131
+
132
+ Stamped with DF-RENDER-INPUT-INVALID so consumers can distinguish user-supplied
133
+ bad arguments from internal failures.
134
+ """
135
+ return RenderedDashboard(
136
+ success=False,
137
+ validation_errors=[
138
+ DatafaceError.from_code(
139
+ DF_RENDER_INPUT_INVALID, message=message
140
+ ).to_structured()
141
+ ],
142
+ )
143
+
144
+
145
+ def render_dashboard(
146
+ path: Path | None = None,
147
+ yaml_content: str | None = None,
148
+ project_dir: Path | None = None,
149
+ variables: dict[str, Any] | None = None,
150
+ *,
151
+ adapter_registry: AdapterRegistry | None = None,
152
+ format: str = "json",
153
+ server_port: int | None = None,
154
+ use_cache: bool = True,
155
+ scale: float | None = None,
156
+ as_link: bool = False,
157
+ link_context: LinkContext | None = None,
158
+ duckdb_cache: DuckDBCache | None = None,
159
+ ignore_codes: set[str] | None = None,
160
+ ) -> RenderedDashboard:
161
+ """Validate, compile, and render a Dataface dashboard."""
162
+ # as_link=True: compile-only path that returns a preview URL without
163
+ # executing queries — the cheap counterpart to a full render. Requires
164
+ # `path` (the URL points at the saved face on disk).
165
+ if as_link:
166
+ if not path:
167
+ return _input_error("as_link=True requires 'path'")
168
+ try:
169
+ link_file_path = resolve_scoped_path(path, project_dir)
170
+ except ValueError as exc:
171
+ return _input_error(str(exc))
172
+ if not link_file_path.exists():
173
+ return _input_error(f"File not found: {path}")
174
+ result = compile_file(link_file_path)
175
+ if not result.success:
176
+ return RenderedDashboard(
177
+ success=False,
178
+ validation_errors=_stamp_file_commands(result.errors, link_file_path),
179
+ warnings=list(result.warnings),
180
+ suppressed_warnings=list(result.suppressed_warnings),
181
+ )
182
+ return RenderedDashboard(
183
+ success=True,
184
+ warnings=list(result.warnings),
185
+ suppressed_warnings=list(result.suppressed_warnings),
186
+ url=_view_url(
187
+ link_file_path, variables, port=server_port, project_dir=project_dir
188
+ ),
189
+ )
190
+
191
+ if adapter_registry is None:
192
+ return _input_error(
193
+ "adapter_registry is required for full render "
194
+ "(or pass as_link=True with a path for link-only)"
195
+ )
196
+
197
+ allowed_formats = frozenset(get_args(RenderFormat))
198
+ if format not in allowed_formats:
199
+ return RenderedDashboard(
200
+ success=False,
201
+ validation_errors=[
202
+ DatafaceError.from_code(
203
+ DF_RENDER_FORMAT_UNSUPPORTED, format=format
204
+ ).to_structured()
205
+ ],
206
+ )
207
+ if not path and not yaml_content:
208
+ return _input_error("Must provide either 'path' or 'yaml_content'")
209
+ if path and yaml_content:
210
+ return _input_error("Provide only one of 'path' or 'yaml_content', not both")
211
+
212
+ file_path: Path | None = None
213
+ if path:
214
+ try:
215
+ file_path = resolve_scoped_path(path, project_dir)
216
+ except ValueError as exc:
217
+ return _input_error(str(exc))
218
+ if not file_path.exists():
219
+ # No `file=` — `dft validate <missing-file>` would itself fail; don't
220
+ # surface that as a next-command suggestion.
221
+ return _input_error(f"File not found: {path}")
222
+ result = compile_file(file_path)
223
+ else:
224
+ if yaml_content is None:
225
+ return _input_error("yaml_content is required when no path is provided")
226
+ resolved_base = project_root_for(project_dir)
227
+ result = compile(
228
+ yaml_content,
229
+ base_dir=resolved_base,
230
+ project_dir=resolved_base,
231
+ )
232
+
233
+ if not result.success:
234
+ errs = (
235
+ _stamp_file_commands(result.errors, file_path)
236
+ if file_path is not None
237
+ else list(result.errors)
238
+ )
239
+ return RenderedDashboard(
240
+ success=False,
241
+ validation_errors=errs,
242
+ warnings=list(result.warnings),
243
+ suppressed_warnings=list(result.suppressed_warnings),
244
+ )
245
+
246
+ _enrich_fanout_warnings_if_available(result)
247
+ face = result.face
248
+ if face is None:
249
+ return RenderedDashboard(
250
+ success=False,
251
+ face_error=DatafaceError.from_code(
252
+ DF_UNKNOWN_INTERNAL,
253
+ message="Compilation did not produce a face",
254
+ ).to_structured(file=str(file_path) if file_path else None),
255
+ )
256
+
257
+ # Honor DFT_CACHE_PATH unless the caller passed an owned cache.
258
+ # When `duckdb_cache` is provided, the caller manages its lifecycle
259
+ # (e.g. dft serve's module-level singleton) — don't close it here.
260
+ from dataface.core.execute.duckdb_cache import open_cache_from_env
261
+ from dataface.core.render.render_result import RenderResult as _RenderResult
262
+
263
+ own_cache = duckdb_cache is None
264
+ cache = duckdb_cache if duckdb_cache is not None else open_cache_from_env()
265
+ render_result: _RenderResult
266
+ try:
267
+ executor = Executor(
268
+ face,
269
+ adapter_registry=adapter_registry,
270
+ query_registry=result.query_registry,
271
+ use_cache=use_cache,
272
+ duckdb_cache=cache,
273
+ )
274
+ render_options: dict[str, Any] = {}
275
+ if scale is not None:
276
+ render_options["scale"] = scale
277
+ if link_context is not None:
278
+ render_options["link_context"] = link_context
279
+ render_result = render(
280
+ face,
281
+ executor,
282
+ format=format,
283
+ variables=variables or {},
284
+ ignore_codes=ignore_codes,
285
+ project_dir=project_dir,
286
+ **render_options,
287
+ )
288
+ # Compile-side warnings haven't passed through the render-time partition,
289
+ # so --ignore-warning / dataface.yml / per-chart codes have no effect on
290
+ # them yet. Apply the same three-layer partition here for symmetry.
291
+ compile_active, compile_suppressed = _partition_warnings(
292
+ list(result.warnings),
293
+ cli_codes=ignore_codes or set(),
294
+ project_codes=set(get_project_warnings_ignore(project_dir)),
295
+ per_chart_codes={
296
+ chart_id: set(chart.warnings_ignore)
297
+ for chart_id, chart in face.charts.items()
298
+ if chart.warnings_ignore
299
+ },
300
+ )
301
+ if render_result.face_error is not None:
302
+ return RenderedDashboard(
303
+ success=False,
304
+ face_error=render_result.face_error,
305
+ chart_errors=render_result.chart_errors,
306
+ warnings=[*compile_active, *render_result.render_warnings],
307
+ suppressed_warnings=[
308
+ *result.suppressed_warnings,
309
+ *compile_suppressed,
310
+ *render_result.suppressed_warnings,
311
+ ],
312
+ )
313
+ rendered_output = render_result.output
314
+ if rendered_output is None:
315
+ # face_error guard above returns early; this is unreachable in practice.
316
+ return RenderedDashboard(
317
+ success=False,
318
+ face_error=DatafaceError.from_code(
319
+ DF_UNKNOWN_INTERNAL, message="Render produced no output"
320
+ ).to_structured(),
321
+ )
322
+ if format == "json":
323
+ import json
324
+
325
+ data: dict[str, Any] | str | bytes = json.loads(rendered_output)
326
+ elif isinstance(rendered_output, bytes):
327
+ # Binary formats (png, pdf) — pass bytes through unchanged.
328
+ data = rendered_output
329
+ else:
330
+ data = rendered_output
331
+ except (ExecutionError, RenderError) as e:
332
+ # Executor creation failures and MissingRequiredVariablesError (a RenderError
333
+ # subclass) reach here — these are face-level fatals, not per-chart errors.
334
+ return RenderedDashboard(
335
+ success=False,
336
+ face_error=e.to_structured(file=str(file_path) if file_path else None),
337
+ )
338
+ finally:
339
+ if own_cache and cache is not None:
340
+ cache.close()
341
+
342
+ url = (
343
+ _view_url(file_path, variables, port=server_port, project_dir=project_dir)
344
+ if file_path is not None
345
+ else None
346
+ )
347
+ return RenderedDashboard(
348
+ success=True,
349
+ data=data,
350
+ chart_errors=render_result.chart_errors,
351
+ warnings=[*compile_active, *render_result.render_warnings],
352
+ suppressed_warnings=[
353
+ *result.suppressed_warnings,
354
+ *compile_suppressed,
355
+ *render_result.suppressed_warnings,
356
+ ],
357
+ url=url,
358
+ )
@@ -0,0 +1,101 @@
1
+ # Default Dataface Configuration
2
+ # ==============================
3
+ #
4
+ # STRUCTURE:
5
+ # style: Resolved from the base theme (authorable visual config)
6
+ # [everything else] Engine internals — not per-face authorable
7
+ #
8
+ # All visual/authorable config lives in themes/ files.
9
+ # See: themes/stark.yaml for the structural root style; themes/editorial.yaml is
10
+ # the shipped default and adds editorial voice on top.
11
+
12
+ # ============================================================================
13
+ # STYLE — resolved from theme files
14
+ # ============================================================================
15
+ # All visual/authorable properties live in themes/.
16
+ # The theme cascade: theme defaults → face style: → chart style:
17
+
18
+ style:
19
+ extends: editorial
20
+
21
+
22
+ # ============================================================================
23
+ # VEGA-LITE
24
+ # ============================================================================
25
+ # Engine internals for the Vega-Lite output channel. The schema URL is a
26
+ # Python constant (dataface.core.compile.vega_lite.VEGA_LITE_SCHEMA_URL) —
27
+ # bumping it requires code changes, so it is not authorable here.
28
+
29
+ vega:
30
+ default_theme: editorial
31
+
32
+
33
+ # ============================================================================
34
+ # CHART RENDERING CONSTANTS
35
+ # ============================================================================
36
+ # Algorithm constants for chart layout. Not per-face authorable — these
37
+ # control axis label sizing, tooltip formatting, and rendering heuristics.
38
+
39
+ chart_rendering:
40
+ default_width: 600
41
+ kpi:
42
+ # Spacing between value baseline and the title block. Title and support
43
+ # form a fixed 3-line block at one consistent rhythm — see
44
+ # ``_resolve_kpi_layout`` in ``core/render/chart/kpi.py``. Inner edge
45
+ # padding (top/bottom/left/right) all derive from
46
+ # ``style.charts.kpi.content_padding`` for a unified inset.
47
+ minimum_title_value_gap: 14.0
48
+ spark_bar:
49
+ title_height: 24.0
50
+ title_baseline_y: 16.0
51
+ more_rows_font_size: 10.0
52
+ more_rows_offset_y: 12.0
53
+ more_rows_bottom_padding: 8.0
54
+ text_baseline_offset: 4.0
55
+ side_padding: 4.0
56
+ avg_char_width_px: 7.0
57
+
58
+
59
+ # ============================================================================
60
+ # RENDERING / EXPORT DEFAULTS
61
+ # ============================================================================
62
+
63
+ rendering:
64
+ timestamp_visible: true
65
+ timestamp_format: "%Y-%m-%d %H:%M"
66
+ timestamp:
67
+ font:
68
+ size: 11
69
+ color: "#999999"
70
+ y: 14
71
+
72
+ # Page footer — right-aligned attribution at the bottom of every SVG-rendered
73
+ # face. Set footer_text to "" to disable. The terminal renderer does not emit
74
+ # a footer.
75
+ footer_text: "made with dataface"
76
+ footer:
77
+ font:
78
+ size: 11
79
+ color: "#999999"
80
+ y_offset: 14
81
+ rule:
82
+ color: "#e5e5e5"
83
+ stroke_width: 0.5
84
+
85
+ svg:
86
+ preserve_aspect_ratio: "xMidYMid meet"
87
+ background: null
88
+
89
+ png:
90
+ scale: 1.0
91
+ background: null
92
+
93
+ pdf:
94
+ background: null
95
+ page_size: "auto"
96
+
97
+ html:
98
+ background: "#ffffff"
99
+
100
+ terminal:
101
+ background: null
@@ -0,0 +1,32 @@
1
+ # Categorical palette — category-10-dark
2
+ #
3
+ # Dark companion to category-10. Each stop is the darker counterpart of the
4
+ # same slot in `category-10.yml` — used for direct labels that need higher
5
+ # contrast against light backgrounds (e.g. right-pane endpoint labels on
6
+ # multi-series lines, segment names on stacked bars).
7
+ #
8
+ # Pairing is positional: stop N here is the dark companion of stop N in
9
+ # category-10. Reviewers edit the trio (`category-10`, `category-10-dark`,
10
+ # `category-10-light`) together when the editorial palette changes — the
11
+ # light companion (`category-10-light.yml`) handles de-emphasis fading;
12
+ # this file handles direct-label inking.
13
+
14
+ name: category-10-dark
15
+ description: |
16
+ Dark companion to category-10. Ten slots, each darker than the matching
17
+ category-10 stop. Designed for direct-label color (chart endpoint labels,
18
+ right-pane segment names) where bright fills need a darker text counterpart
19
+ against light backgrounds. Pairing is positional: slot N here pairs with
20
+ slot N in category-10.
21
+
22
+ colors:
23
+ - "#235a8a" # 1 — blue (companion to #2d74b3)
24
+ - "#2f9fbd" # 2 — cyan (companion to #41c6e7)
25
+ - "#3d7a5e" # 3 — green (companion to #40a97b)
26
+ - "#684e33" # 4 — brown (companion to #7a5531)
27
+ - "#98772c" # 5 — gold (companion to #dea628)
28
+ - "#82568d" # 6 — purple (companion to #a46fb2)
29
+ - "#ad562d" # 7 — orange (companion to #da5a23)
30
+ - "#526836" # 8 — moss (companion to #6f9041)
31
+ - "#6c7685" # 9 — gray (companion to #949daa)
32
+ - "#404852" # 10 — charcoal (companion to #505b6b)
@@ -0,0 +1,43 @@
1
+ # Categorical palette — category-10-light
2
+ #
3
+ # Light de-emphasis companion to category-10. Each stop is the lighter,
4
+ # desaturated counterpart of the same slot in `category-10.yml` — used
5
+ # for fading out-of-focus members of a series so the highlighted member
6
+ # (rendered in its base color) reads forward. The intended use case is
7
+ # editorial highlight-columns / dim-the-chorus emphasis, where typically
8
+ # 1 series is emphasized and 1–2 are de-emphasized; this palette is sized
9
+ # to that case, not to a 10-bar chorus.
10
+ #
11
+ # Pairing is positional: stop N here is the light companion of stop N in
12
+ # category-10. Reviewers edit the trio (`category-10`, `category-10-dark`,
13
+ # `category-10-light`) together when the editorial palette changes.
14
+ #
15
+ # Derivation: option-B uniform OKLCH lift, settled at L=0.86 with chroma
16
+ # multiplied by 0.32 (per-slot hue preserved). Slot 6 (purple) is the
17
+ # calibration anchor — it lands at L=0.861 C=0.037 H=318.8, ~7° off from
18
+ # the source lavender swatch (#d3c8db, L=0.847 C=0.029 H=311.3) but on
19
+ # the same purple axis as base #a46fb2. Slot 10 (charcoal) is held at
20
+ # L=0.74 (main L − 0.12) so it stays visually distinct from slot 9
21
+ # (gray) — without that override the two near-neutral slots collapse
22
+ # into a single value at the uniform target L.
23
+
24
+ name: category-10-light
25
+ description: |
26
+ Light de-emphasis companion to category-10. Ten slots, each lighter and
27
+ more desaturated than the matching category-10 stop. Designed for fading
28
+ out-of-focus members of a series in highlight-columns / dim-the-chorus
29
+ emphasis design, where the highlighted member renders in its base color
30
+ and 1–2 others recede into the same hue at lower visual weight. Pairing
31
+ is positional: slot N here pairs with slot N in category-10.
32
+
33
+ colors:
34
+ - "#bed4ea" # 1 — blue (companion to #2d74b3)
35
+ - "#b6d8e2" # 2 — cyan (companion to #41c6e7)
36
+ - "#bcd9c9" # 3 — green (companion to #40a97b)
37
+ - "#dccec2" # 4 — brown (companion to #7a5531)
38
+ - "#e0cfaf" # 5 — gold (companion to #dea628)
39
+ - "#dccae1" # 6 — purple (companion to #a46fb2)
40
+ - "#f2c6b6" # 7 — orange (companion to #da5a23)
41
+ - "#cad6bd" # 8 — moss (companion to #6f9041)
42
+ - "#ced1d6" # 9 — gray (companion to #949daa)
43
+ - "#a7abb1" # 10 — charcoal (companion to #505b6b)
@@ -0,0 +1,31 @@
1
+ # Categorical palette — category-10
2
+ #
3
+ # Migrated from dataface/core/defaults/chart_defaults.yml > palettes > category-10
4
+ # Categorical palettes have no LUT, no surface variants, no interpolation.
5
+ # Stops are what you get — exactly as authored.
6
+ #
7
+ # Companions (positional pairing — slot N of the companion pairs with slot N
8
+ # here; reviewers edit the trio together when the editorial palette changes):
9
+ # - `category-10-dark.yml` — darker twin, used to ink direct labels (e.g.
10
+ # endpoint labels on multi-series lines) so the label sits a notch
11
+ # darker than its line.
12
+ # - `category-10-light.yml` — lighter, desaturated twin, used to fade
13
+ # out-of-focus members in highlight-columns / dim-the-chorus emphasis.
14
+
15
+ name: category-10
16
+ description: |
17
+ Default 10-color categorical palette for qualitative data encoding.
18
+ Blue-first; calm editorial posture; earth-and-neutral expansion after
19
+ the first five hues. Pre-M2 palette, retained unchanged.
20
+
21
+ colors:
22
+ - "#2d74b3" # 1 — blue (default single-series)
23
+ - "#41c6e7" # 2 — cyan
24
+ - "#40a97b" # 3 — green
25
+ - "#7a5531" # 4 — brown
26
+ - "#dea628" # 5 — gold
27
+ - "#a46fb2" # 6 — purple
28
+ - "#da5a23" # 7 — orange
29
+ - "#6f9041" # 8 — moss
30
+ - "#949daa" # 9 — gray
31
+ - "#505b6b" # 10 — charcoal
@@ -0,0 +1,22 @@
1
+ # Categorical palette — category-6-tonal-blue
2
+ #
3
+ # Single-hue categorical palette anchored on category-10 slot 0 (blue, H≈248.8°
4
+ # in OKLCH). Strict-safe core of 4 stops (color-alone CVD-safe under Leonardo
5
+ # ΔE ≥ 11) plus 2 extended stops that REQUIRE redundant form encoding
6
+ # (dash/marker/pattern) past slot 4. See docs/docs/guides/tonal-categorical-palette.md.
7
+
8
+ name: category-6-tonal-blue
9
+ description: |
10
+ Tonal monochromatic blue palette. 6 stops at fixed hue (H≈248.8°), all in
11
+ the blue family. Use for editorial / brand-restrained dashboards that want
12
+ one hue throughout. Strict-safe core: slots 0-3 (Leonardo ΔE ≥ 11 pairwise).
13
+ Extended: slots 4-5 (require dash, marker, or pattern redundancy past slot 4).
14
+ See docs/docs/guides/tonal-categorical-palette.md.
15
+
16
+ colors:
17
+ - "#0375c4" # 0 — bluish (anchor / default single-series)
18
+ - "#81b3e5" # 1 — carolina blue (light tint)
19
+ - "#004a7f" # 2 — prussian blue (dark saturated)
20
+ - "#002341" # 3 — marine (very dark)
21
+ - "#6f89a3" # 4 — blue/grey (extended; form-redundant)
22
+ - "#c2d3e4" # 5 — light blue grey (extended; form-redundant)
@@ -0,0 +1,29 @@
1
+ # Categorical palette — category-6-tonal-brown
2
+ #
3
+ # Single-hue categorical palette anchored on category-10 slot 3 (brown, H≈64°
4
+ # in OKLCH). Variant of the F template with a hue-wobble in extended slots
5
+ # (4-5) toward H≈78° to land in dft-creams territory — i.e., the lightest
6
+ # extended stops visually bridge into the cream theme's chrome.
7
+
8
+ name: category-6-tonal-brown
9
+ description: |
10
+ Tonal monochromatic brown palette. 6 stops in the brown family, designed
11
+ to bridge into the dft-creams scaffold for cream-themed dashboards.
12
+ Slots 0-3 are saturated browns at H≈64° (sepia, mushroom, brown, dark brown);
13
+ slots 4-5 wobble +14° to H≈78° to land between cream-30 and cream-60 in
14
+ perceptual space — the extended stops feel continuous with the cream-theme
15
+ chrome rather than as separate "near-neutrals."
16
+
17
+ Strict-safe core: slots 0-3 (Leonardo ΔE ≥ 11 pairwise).
18
+ Extended: slots 4-5 (require form redundancy past slot 4; live in cream
19
+ territory and may have low contrast against cream-025 / cream-theme
20
+ backgrounds — that's the bridge, not a bug).
21
+ See docs/docs/guides/tonal-categorical-palette.md.
22
+
23
+ colors:
24
+ - "#9a642b" # 0 — sepia (anchor)
25
+ - "#c9a687" # 1 — mushroom (light tan tint)
26
+ - "#683b01" # 2 — brown (dark saturated)
27
+ - "#321c04" # 3 — dark brown (very dark)
28
+ - "#908472" # 4 — brown grey (extended; cream-bridge)
29
+ - "#d8d0c3" # 5 — light grey (extended; cream-bridge)
@@ -0,0 +1,20 @@
1
+ # Categorical palette — category-6-tonal-green
2
+ #
3
+ # Single-hue categorical palette anchored on category-10 slot 2 (green, H≈161.3°
4
+ # in OKLCH). Same architecture as category-6-tonal-blue.
5
+
6
+ name: category-6-tonal-green
7
+ description: |
8
+ Tonal monochromatic green palette. 6 stops at fixed hue (H≈161.3°), all in
9
+ the green family. Use for editorial / brand-restrained dashboards that want
10
+ one hue throughout. Strict-safe core: slots 0-3 (Leonardo ΔE ≥ 11 pairwise).
11
+ Extended: slots 4-5 (require dash, marker, or pattern redundancy past slot 4).
12
+ See docs/docs/guides/tonal-categorical-palette.md.
13
+
14
+ colors:
15
+ - "#00875a" # 0 — dark sea green (anchor)
16
+ - "#78c09c" # 1 — pale teal (light tint)
17
+ - "#005638" # 2 — spruce (dark saturated)
18
+ - "#002a19" # 3 — dark forest green (very dark)
19
+ - "#6c907d" # 4 — slate green (extended; form-redundant)
20
+ - "#c1d7cb" # 5 — light grey (extended; form-redundant)