dataface 0.3.2.dev22__py3-none-any.whl → 0.3.2.dev111__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.
- dataface/__init__.py +70 -23
- dataface/agent_api/__init__.py +162 -68
- dataface/agent_api/_paths.py +9 -3
- dataface/agent_api/docs/yaml-reference.md +240 -106
- dataface/agent_api/init.py +1 -1
- dataface/agent_api/project_session.py +2 -1
- dataface/agent_api/serve.py +115 -0
- dataface/ai/agent.py +28 -2
- dataface/cli/_project.py +100 -1
- dataface/cli/commands/board_artifact.py +5 -2
- dataface/cli/commands/describe.py +7 -3
- dataface/cli/commands/docs.py +12 -3
- dataface/cli/commands/init.py +7 -14
- dataface/cli/commands/inspect.py +6 -1
- dataface/cli/commands/mcp_init.py +23 -43
- dataface/cli/commands/migrate.py +8 -3
- dataface/cli/commands/query.py +11 -8
- dataface/cli/commands/render.py +20 -9
- dataface/cli/commands/search.py +8 -2
- dataface/cli/commands/serve.py +26 -76
- dataface/cli/commands/skills_init.py +2 -19
- dataface/cli/commands/validate.py +7 -2
- dataface/cli/filesystem_project.py +5 -4
- dataface/cli/main.py +2 -19
- dataface/core/__init__.py +73 -28
- dataface/core/{compile/colors.py → colors.py} +20 -5
- dataface/core/compile/compiler.py +97 -34
- dataface/core/compile/data_table.py +7 -2
- dataface/core/compile/enrich.py +18 -44
- dataface/core/compile/face_warnings.py +46 -8
- dataface/core/compile/format.py +47 -1
- dataface/core/compile/inherit_graph.py +3 -3
- dataface/core/compile/inherit_registry.yaml +1 -1
- dataface/core/compile/migrations.py +112 -9
- dataface/core/compile/models/chart/normalized/kpi.py +0 -4
- dataface/core/compile/models/chart/resolved/_base.py +28 -10
- dataface/core/compile/models/chart/resolved/callout.py +2 -3
- dataface/core/compile/models/chart/resolved/kpi.py +7 -3
- dataface/core/compile/models/chart/resolved/table.py +16 -2
- dataface/core/compile/models/markers.py +1 -1
- dataface/core/compile/models/primitives.py +175 -2
- dataface/core/compile/models/source.py +5 -5
- dataface/core/compile/models/style/authored/__init__.py +32 -8
- dataface/core/compile/models/style/authored/_base.py +126 -69
- dataface/core/compile/models/style/authored/table.py +61 -3
- dataface/core/compile/models/style/resolved/__init__.py +12 -2
- dataface/core/compile/models/style/resolved/_base.py +142 -57
- dataface/core/compile/models/style/resolved/_cartesian.py +6 -11
- dataface/core/compile/models/style/resolved/_cascade.py +141 -54
- dataface/core/compile/models/style/resolved/area.py +1 -1
- dataface/core/compile/models/style/resolved/bar.py +1 -1
- dataface/core/compile/models/style/resolved/line.py +1 -1
- dataface/core/compile/models/style/resolved/scatter.py +3 -2
- dataface/core/compile/models/style/theme/__init__.py +36 -14
- dataface/core/compile/models/style/theme/_chart_base.py +17 -9
- dataface/core/compile/models/style/theme/axis.py +432 -312
- dataface/core/compile/models/style/theme/charts.py +10 -6
- dataface/core/compile/models/style/theme/kpi.py +2 -1
- dataface/core/compile/models/style/theme/page.py +5 -2
- dataface/core/compile/models/style/theme/table.py +2 -2
- dataface/core/compile/models/vega_lite/config.py +1 -1
- dataface/core/compile/normalize_charts.py +6 -2
- dataface/core/compile/normalize_queries.py +21 -7
- dataface/core/compile/resolve/__init__.py +2 -0
- dataface/core/compile/resolve/_axes.py +147 -44
- dataface/core/compile/resolve/_channels.py +1 -1
- dataface/core/compile/resolve/_dispatch.py +1 -1
- dataface/core/compile/resolve/_domain.py +49 -32
- dataface/core/compile/resolve/_kwargs.py +39 -12
- dataface/core/compile/resolve/_marks.py +8 -3
- dataface/core/compile/resolve/_palette.py +7 -3
- dataface/core/compile/resolve/_table.py +124 -33
- dataface/core/compile/resolve/area.py +48 -18
- dataface/core/compile/resolve/bar.py +245 -64
- dataface/core/compile/resolve/geo.py +10 -3
- dataface/core/compile/resolve/heatmap.py +16 -8
- dataface/core/compile/resolve/line.py +35 -12
- dataface/core/compile/resolve/pie.py +4 -1
- dataface/core/compile/resolve/pie_attachment.py +1 -1
- dataface/core/compile/resolve/scatter.py +25 -13
- dataface/core/compile/resolve/simple.py +25 -2
- dataface/core/compile/schema_renderers/prompt.py +1 -1
- dataface/core/compile/schema_renderers/textmate_grammar.py +8 -1
- dataface/core/compile/source_map.py +211 -28
- dataface/core/compile/style_cascade.py +126 -55
- dataface/core/compile/yaml_error_formatter.py +1 -1
- dataface/core/connections.py +10 -3
- dataface/core/dashboard.py +24 -18
- dataface/core/defaults/themes/_base.yaml +49 -39
- dataface/core/defaults/themes/cream.yaml +4 -4
- dataface/core/defaults/themes/diagnostics-title-baseline.yaml +1 -1
- dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +1 -1
- dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +1 -1
- dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +1 -1
- dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +1 -1
- dataface/core/defaults/themes/editorial.yaml +6 -6
- dataface/core/defaults/themes/neon.yaml +15 -8
- dataface/core/defaults/themes/plain.yaml +6 -4
- dataface/core/defaults/themes/stark.yaml +16 -7
- dataface/core/defaults/themes/vivid.yaml +15 -8
- dataface/core/diagnostics/__init__.py +2 -2
- dataface/core/diagnostics/codes_compile.py +13 -31
- dataface/core/diagnostics/codes_execute.py +79 -0
- dataface/core/diagnostics/codes_render.py +87 -28
- dataface/core/diagnostics/diagnostic.py +30 -0
- dataface/core/diagnostics/hints.py +19 -0
- dataface/core/dialects/base.py +17 -0
- dataface/core/dialects/postgres.py +14 -0
- dataface/core/dialects/redshift.py +5 -0
- dataface/core/execute/__init__.py +59 -14
- dataface/core/execute/adapters/dbt_adapter.py +4 -1
- dataface/core/execute/adapters/dbt_adapter_factory.py +19 -0
- dataface/core/execute/adapters/dbt_utils.py +84 -20
- dataface/core/execute/adapters/postgres_connection_manager.py +48 -0
- dataface/core/execute/adapters/sql_adapter.py +72 -4
- dataface/core/execute/dbt_jinja.py +65 -10
- dataface/core/execute/executor.py +69 -16
- dataface/core/font_measure.py +28 -0
- dataface/core/fonts.py +8 -5
- dataface/core/inspect/__init__.py +46 -6
- dataface/core/project.py +13 -1
- dataface/core/render/chart/data_table_attachment.py +14 -12
- dataface/core/render/chart/emitters/_cartesian.py +21 -18
- dataface/core/render/chart/emitters/_channels.py +56 -8
- dataface/core/render/chart/emitters/_label_overlap.py +18 -15
- dataface/core/render/chart/emitters/_measured_label_padding.py +4 -4
- dataface/core/render/chart/emitters/area.py +3 -3
- dataface/core/render/chart/emitters/bar.py +60 -35
- dataface/core/render/chart/emitters/geo.py +8 -13
- dataface/core/render/chart/emitters/heatmap.py +20 -26
- dataface/core/render/chart/emitters/line.py +2 -2
- dataface/core/render/chart/emitters/scatter.py +7 -30
- dataface/core/render/chart/features/baseline.py +22 -9
- dataface/core/render/chart/features/endpoint_labels.py +55 -32
- dataface/core/render/chart/features/mirror_axis.py +12 -9
- dataface/core/render/chart/features/value_labels.py +1 -1
- dataface/core/render/chart/kpi.py +11 -90
- dataface/core/render/chart/presentation.py +6 -8
- dataface/core/render/chart/rendering.py +3 -12
- dataface/core/render/chart/session.py +10 -0
- dataface/core/render/chart/spec.py +3 -0
- dataface/core/render/chart/spec_builders.py +18 -18
- dataface/core/render/chart/table.py +81 -36
- dataface/core/render/chart/table_support.py +2 -53
- dataface/core/render/chart/time_unit_detect.py +3 -2
- dataface/core/render/chart/translate.py +82 -44
- dataface/core/render/chart/type_inference.py +45 -25
- dataface/core/render/chart/validation.py +91 -0
- dataface/core/render/chart/vega_lite.py +30 -11
- dataface/core/render/chart/vl_field_maps.py +111 -76
- dataface/core/render/converters/chart.py +16 -6
- dataface/core/render/faces.py +3 -2
- dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.woff2 +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.woff2 +0 -0
- dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -93
- dataface/core/render/fonts/_font_face.css +10 -0
- dataface/core/render/layout_sizing.py +267 -238
- dataface/core/render/numeral_expr.py +80 -0
- dataface/core/render/warnings/bar_band_width_too_narrow.py +64 -6
- dataface/core/render/warnings/layered_chart_shared_y_axis_scale_mismatch.py +25 -3
- dataface/core/render/warnings/likely_currency_or_percent_missing_formatter.py +12 -6
- dataface/core/render/warnings/palette_unsupported.py +6 -0
- dataface/core/render/warnings/pie_dominant_segment.py +1 -0
- dataface/core/render/warnings/pie_too_many_segments.py +1 -0
- dataface/core/render/warnings/point_map_out_of_projection.py +1 -0
- dataface/core/render/warnings/query_returned_zero_rows.py +1 -0
- dataface/core/render/warnings/redundant_encoding.py +20 -1
- dataface/core/render/warnings/registry.py +7 -3
- dataface/core/render/warnings/temporal_single_point.py +1 -0
- dataface/core/render/warnings/too_many_color_categories.py +1 -0
- dataface/core/render/warnings/too_many_x_categories.py +18 -2
- dataface/core/render/warnings/value_labels_crowd_width.py +9 -0
- dataface/core/render/warnings/y_encoding_mostly_null.py +1 -0
- dataface/core/render_format.py +18 -0
- dataface/core/text/format_d3.py +56 -0
- dataface/core/text/numeral_scale.py +218 -0
- dataface/core/utils.py +103 -10
- dataface/data/schemas/board-resolved/board-resolved.schema.json +9487 -7978
- dataface/data/schemas/yaml/0.3.2.json +1 -0
- dataface/data/schemas/yaml/manifest.json +7 -0
- {dataface-0.3.2.dev22.dist-info → dataface-0.3.2.dev111.dist-info}/METADATA +1 -1
- {dataface-0.3.2.dev22.dist-info → dataface-0.3.2.dev111.dist-info}/RECORD +185 -177
- {dataface-0.3.2.dev22.dist-info → dataface-0.3.2.dev111.dist-info}/WHEEL +0 -0
- {dataface-0.3.2.dev22.dist-info → dataface-0.3.2.dev111.dist-info}/entry_points.txt +0 -0
- {dataface-0.3.2.dev22.dist-info → dataface-0.3.2.dev111.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,7 +11,7 @@ Public surface:
|
|
|
11
11
|
resolve_mark() — merge global + family-level mark defaults
|
|
12
12
|
insert_emoji_family() — insert emoji font into a CSS font-family stack
|
|
13
13
|
apply_emoji_to_family() — conditionally insert emoji font by mode
|
|
14
|
-
build_resolved_axis() — build a ResolvedAxisStyle from
|
|
14
|
+
build_resolved_axis() — build a ResolvedAxisStyle from a BaseAxisStyle
|
|
15
15
|
clear_resolve_style_cache() — evict the no-patch cache after config reloads
|
|
16
16
|
|
|
17
17
|
Private helpers are prefixed with _ and not intended for callers outside
|
|
@@ -34,13 +34,18 @@ from dataface.core.compile.models.primitives import FontStyle, ResolvedFontStyle
|
|
|
34
34
|
from dataface.core.compile.models.style.authored import PaginationConfig
|
|
35
35
|
from dataface.core.compile.models.style.theme import (
|
|
36
36
|
AxisLabelOverlapConfig,
|
|
37
|
-
|
|
37
|
+
AxisXStyle,
|
|
38
|
+
AxisYStyle,
|
|
39
|
+
BaseScaleStyle,
|
|
38
40
|
CalloutChartStyle,
|
|
39
41
|
ChartsStyle,
|
|
42
|
+
DimensionLabelStyle,
|
|
43
|
+
DimensionTicksStyle,
|
|
40
44
|
LegendStyle,
|
|
41
45
|
SparkStyle,
|
|
42
46
|
Style,
|
|
43
47
|
TitleStyle,
|
|
48
|
+
XScaleStyle,
|
|
44
49
|
font_weight_as_css,
|
|
45
50
|
)
|
|
46
51
|
from dataface.core.compile.vega_lite.mapping import effective_vega_config
|
|
@@ -49,16 +54,21 @@ from dataface.core.compile.vega_lite.mapping import effective_vega_config
|
|
|
49
54
|
from dataface.core.fonts import NOTO_COLOR_EMOJI_FONT_FAMILY, NOTO_EMOJI_FONT_FAMILY
|
|
50
55
|
|
|
51
56
|
from ._base import (
|
|
52
|
-
ResolvedAxisDomainStyle,
|
|
53
57
|
ResolvedAxisElementStyle,
|
|
54
58
|
ResolvedAxisGridStyle,
|
|
55
59
|
ResolvedAxisGridZeroStyle,
|
|
56
60
|
ResolvedAxisLabelOverlapConfig,
|
|
61
|
+
ResolvedAxisLineStyle,
|
|
57
62
|
ResolvedAxisStyle,
|
|
58
63
|
ResolvedAxisTicksStyle,
|
|
59
64
|
ResolvedChartsStyle,
|
|
60
65
|
ResolvedLegendElementStyle,
|
|
61
66
|
ResolvedLegendStyle,
|
|
67
|
+
ResolvedScaleContinuousStyle,
|
|
68
|
+
ResolvedScaleLogStyle,
|
|
69
|
+
ResolvedScalePowStyle,
|
|
70
|
+
ResolvedScaleStyle,
|
|
71
|
+
ResolvedScaleSymlogStyle,
|
|
62
72
|
ResolvedStyle,
|
|
63
73
|
)
|
|
64
74
|
from .callout import ResolvedCalloutElementStyle, ResolvedCalloutStyle
|
|
@@ -440,30 +450,36 @@ def _seed_spark_colors(style: Style) -> Style:
|
|
|
440
450
|
return style.model_copy(update={"charts": new_charts})
|
|
441
451
|
|
|
442
452
|
|
|
443
|
-
# Fields on
|
|
444
|
-
# inherited from parent axis to child (axis_x/y/etc.) via the InheritGraph,
|
|
445
|
-
# then carried through build_resolved_axis to ResolvedAxisElementStyle.
|
|
453
|
+
# Fields on AxisLabelStyle (base) that are optional VL passthroughs.
|
|
446
454
|
# "overlap" is handled explicitly (AxisLabelOverlapConfig → ResolvedAxisLabelOverlapConfig).
|
|
447
455
|
# "align" is handled explicitly too (_resolve_own_side_align) — its authored
|
|
448
456
|
# type carries inward/outward, which must be mapped against the axis's final
|
|
449
457
|
# edge before it can land on the narrower resolved Literal["left","right"].
|
|
450
|
-
|
|
458
|
+
_LABEL_PASSTHROUGH = (
|
|
451
459
|
"max_width",
|
|
452
460
|
"angle",
|
|
453
|
-
"
|
|
454
|
-
"separation",
|
|
461
|
+
"min_gap",
|
|
455
462
|
"visible",
|
|
456
|
-
"time_unit",
|
|
457
463
|
"expr",
|
|
458
464
|
"bound",
|
|
459
465
|
"flush",
|
|
460
466
|
"offset",
|
|
461
|
-
"
|
|
462
|
-
|
|
467
|
+
"format",
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Additional passthrough fields only on DimensionLabelStyle (AxisXStyle.labels).
|
|
471
|
+
# Absent from AxisLabelStyle (used by AxisYStyle.labels and axis_quantitative/band).
|
|
472
|
+
_ELEM_X_LABEL_PASSTHROUGH = (
|
|
473
|
+
"time_unit",
|
|
463
474
|
"tilt_increments",
|
|
464
475
|
"values",
|
|
465
476
|
)
|
|
466
477
|
|
|
478
|
+
# AxisTitleStyle is deliberately thin (font/padding/angle/align/visible only)
|
|
479
|
+
# — a title is one short static string, not a per-tick label stream, so it
|
|
480
|
+
# has none of the label-overlap/VL-passthrough machinery above.
|
|
481
|
+
_TITLE_PASSTHROUGH = ("padding", "angle", "visible")
|
|
482
|
+
|
|
467
483
|
|
|
468
484
|
def _resolve_own_side_align(
|
|
469
485
|
align: Literal["left", "right", "center", "inward", "outward"] | None,
|
|
@@ -503,24 +519,77 @@ def _resolve_overlap_config(
|
|
|
503
519
|
return None
|
|
504
520
|
if overlap.tilt is None or overlap.skip is None:
|
|
505
521
|
raise ValueError(
|
|
506
|
-
f"axis.
|
|
522
|
+
f"axis.labels.overlap has None fields after cascade: {overlap!r}; "
|
|
507
523
|
"theme must supply both bools (tilt, skip) via _base.yaml"
|
|
508
524
|
)
|
|
509
525
|
return ResolvedAxisLabelOverlapConfig(tilt=overlap.tilt, skip=overlap.skip)
|
|
510
526
|
|
|
511
527
|
|
|
528
|
+
def build_resolved_scale(
|
|
529
|
+
scale: BaseScaleStyle | XScaleStyle | None,
|
|
530
|
+
) -> ResolvedScaleStyle | None:
|
|
531
|
+
"""Convert authored BaseScaleStyle/XScaleStyle to ResolvedScaleStyle.
|
|
532
|
+
|
|
533
|
+
Returns None when no scale was authored (axis or chart has no scale override).
|
|
534
|
+
continuous is None when not authored. x_reverse is populated only from
|
|
535
|
+
XScaleStyle; None on all other inputs.
|
|
536
|
+
"""
|
|
537
|
+
if scale is None:
|
|
538
|
+
return None
|
|
539
|
+
return ResolvedScaleStyle(
|
|
540
|
+
round=scale.round,
|
|
541
|
+
clamp=scale.clamp,
|
|
542
|
+
nice=scale.nice,
|
|
543
|
+
padding=scale.padding,
|
|
544
|
+
headroom=scale.headroom,
|
|
545
|
+
values=scale.values,
|
|
546
|
+
continuous=(
|
|
547
|
+
ResolvedScaleContinuousStyle(
|
|
548
|
+
zero=scale.continuous.zero,
|
|
549
|
+
type=scale.continuous.type,
|
|
550
|
+
domain=scale.continuous.domain,
|
|
551
|
+
domain_strategy=scale.continuous.domain_strategy,
|
|
552
|
+
log=(
|
|
553
|
+
ResolvedScaleLogStyle(base=scale.continuous.log.base)
|
|
554
|
+
if scale.continuous.log is not None
|
|
555
|
+
else None
|
|
556
|
+
),
|
|
557
|
+
pow=(
|
|
558
|
+
ResolvedScalePowStyle(exponent=scale.continuous.pow.exponent)
|
|
559
|
+
if scale.continuous.pow is not None
|
|
560
|
+
else None
|
|
561
|
+
),
|
|
562
|
+
symlog=(
|
|
563
|
+
ResolvedScaleSymlogStyle(constant=scale.continuous.symlog.constant)
|
|
564
|
+
if scale.continuous.symlog is not None
|
|
565
|
+
else None
|
|
566
|
+
),
|
|
567
|
+
)
|
|
568
|
+
if scale.continuous is not None
|
|
569
|
+
else None
|
|
570
|
+
),
|
|
571
|
+
x_reverse=scale.x_reverse if isinstance(scale, XScaleStyle) else None,
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
|
|
512
575
|
def build_resolved_axis(
|
|
513
|
-
axis:
|
|
576
|
+
axis: AxisXStyle | AxisYStyle,
|
|
514
577
|
*,
|
|
578
|
+
band_position: float | None = None,
|
|
515
579
|
edge: Literal["left", "right"] | None = None,
|
|
516
580
|
tick_values: tuple[float, ...] = (),
|
|
517
581
|
domain_max: float | EllipsisType = ...,
|
|
518
582
|
domain_min: float | EllipsisType = ...,
|
|
519
583
|
) -> ResolvedAxisStyle:
|
|
520
|
-
"""Build
|
|
584
|
+
"""Build ResolvedAxisStyle from a channel-typed AxisXStyle or AxisYStyle.
|
|
585
|
+
|
|
586
|
+
Accepts AxisXStyle or AxisYStyle (after resolved_axis_style's merge chain).
|
|
587
|
+
band_position is passed explicitly since BandAxisStyle is structurally absent
|
|
588
|
+
from AxisXStyle/AxisYStyle — the caller extracts it from BandAxisStylePatch.
|
|
521
589
|
|
|
522
|
-
``edge`` is the axis's final left/right placement (None for a
|
|
523
|
-
axis
|
|
590
|
+
``edge`` is the axis's final left/right placement, when known (None for a
|
|
591
|
+
bottom/top axis, or when the caller hasn't determined the edge yet — see
|
|
592
|
+
``resolved_axis_style``'s docstring). It resolves ``labels.align``/
|
|
524
593
|
``title.align``'s inward/outward directives to concrete left/right (or
|
|
525
594
|
None) via ``_resolve_own_side_align`` — the only place that mapping
|
|
526
595
|
happens, so the render layer only ever sees left/right/None.
|
|
@@ -533,6 +602,26 @@ def build_resolved_axis(
|
|
|
533
602
|
)
|
|
534
603
|
return value
|
|
535
604
|
|
|
605
|
+
# grid.zero only exists on y-axis (AxisYStyle.grid is MeasureGridStyle, not BaseAxisGridStyle).
|
|
606
|
+
if isinstance(axis, AxisYStyle):
|
|
607
|
+
grid_zero: ResolvedAxisGridZeroStyle | None = (
|
|
608
|
+
ResolvedAxisGridZeroStyle(
|
|
609
|
+
color=_require(axis.grid.zero.color, "charts.axis_y.grid.zero.color"),
|
|
610
|
+
width=_require(axis.grid.zero.width, "charts.axis_y.grid.zero.width"),
|
|
611
|
+
)
|
|
612
|
+
if axis.grid.zero is not None
|
|
613
|
+
else None
|
|
614
|
+
)
|
|
615
|
+
else:
|
|
616
|
+
grid_zero = None
|
|
617
|
+
|
|
618
|
+
# label passthrough: x-axis adds tilt_increments/values/time_unit from DimensionLabelStyle.
|
|
619
|
+
label_kwargs = {f: getattr(axis.labels, f) for f in _LABEL_PASSTHROUGH}
|
|
620
|
+
if isinstance(axis.labels, DimensionLabelStyle):
|
|
621
|
+
label_kwargs.update(
|
|
622
|
+
{f: getattr(axis.labels, f) for f in _ELEM_X_LABEL_PASSTHROUGH}
|
|
623
|
+
)
|
|
624
|
+
|
|
536
625
|
return ResolvedAxisStyle(
|
|
537
626
|
grid=ResolvedAxisGridStyle(
|
|
538
627
|
visible=_require(axis.grid.visible, "charts.axis.grid.visible"),
|
|
@@ -540,57 +629,52 @@ def build_resolved_axis(
|
|
|
540
629
|
width=_require(axis.grid.width, "charts.axis.grid.width"),
|
|
541
630
|
color=_require(axis.grid.color, "charts.axis.grid.color"),
|
|
542
631
|
dash=axis.grid.dash,
|
|
543
|
-
zero=
|
|
544
|
-
color=_require(
|
|
545
|
-
axis.grid.zero.color if axis.grid.zero else None,
|
|
546
|
-
"charts.axis.grid.zero.color",
|
|
547
|
-
),
|
|
548
|
-
width=_require(
|
|
549
|
-
axis.grid.zero.width if axis.grid.zero else None,
|
|
550
|
-
"charts.axis.grid.zero.width",
|
|
551
|
-
),
|
|
552
|
-
),
|
|
632
|
+
zero=grid_zero,
|
|
553
633
|
),
|
|
554
|
-
|
|
555
|
-
visible=_require(axis.
|
|
556
|
-
width=_require(axis.
|
|
557
|
-
color=_require(axis.
|
|
634
|
+
line=ResolvedAxisLineStyle(
|
|
635
|
+
visible=_require(axis.line.visible, "charts.axis.line.visible"),
|
|
636
|
+
width=_require(axis.line.width, "charts.axis.line.width"),
|
|
637
|
+
color=_require(axis.line.color, "charts.axis.line.color"),
|
|
558
638
|
),
|
|
559
639
|
ticks=ResolvedAxisTicksStyle(
|
|
560
640
|
visible=_require(axis.ticks.visible, "charts.axis.ticks.visible"),
|
|
561
641
|
color=_require(axis.ticks.color, "charts.axis.ticks.color"),
|
|
562
642
|
width=axis.ticks.width,
|
|
563
|
-
|
|
643
|
+
length=axis.ticks.length,
|
|
644
|
+
offset=axis.ticks.offset,
|
|
564
645
|
count=axis.ticks.count,
|
|
565
|
-
interval=axis.ticks.interval,
|
|
566
646
|
step=axis.ticks.step,
|
|
647
|
+
time_unit=(
|
|
648
|
+
axis.ticks.time_unit
|
|
649
|
+
if isinstance(axis.ticks, DimensionTicksStyle)
|
|
650
|
+
else None
|
|
651
|
+
),
|
|
567
652
|
),
|
|
568
|
-
|
|
569
|
-
font=resolve_cascaded_font(axis.
|
|
570
|
-
padding=_require(axis.
|
|
571
|
-
align=_resolve_own_side_align(axis.
|
|
572
|
-
overlap=_resolve_overlap_config(axis.
|
|
573
|
-
**
|
|
653
|
+
labels=ResolvedAxisElementStyle(
|
|
654
|
+
font=resolve_cascaded_font(axis.labels.font, "charts.axis.labels.font"),
|
|
655
|
+
padding=_require(axis.labels.padding, "charts.axis.labels.padding"),
|
|
656
|
+
align=_resolve_own_side_align(axis.labels.align, edge),
|
|
657
|
+
overlap=_resolve_overlap_config(axis.labels.overlap),
|
|
658
|
+
**label_kwargs,
|
|
574
659
|
),
|
|
575
660
|
title=ResolvedAxisElementStyle(
|
|
576
661
|
font=resolve_cascaded_font(axis.title.font, "charts.axis.title.font"),
|
|
577
|
-
padding=_require(axis.title.padding, "charts.axis.title.padding"),
|
|
578
662
|
align=_resolve_own_side_align(axis.title.align, edge),
|
|
579
|
-
|
|
580
|
-
**{f: getattr(axis.title, f) for f in _ELEM_PASSTHROUGH},
|
|
663
|
+
**{f: getattr(axis.title, f) for f in _TITLE_PASSTHROUGH},
|
|
581
664
|
),
|
|
582
665
|
position=axis.position,
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
666
|
+
mirror=axis.mirror if isinstance(axis, AxisYStyle) else None,
|
|
667
|
+
band_position=band_position,
|
|
668
|
+
scale=build_resolved_scale(axis.scale),
|
|
669
|
+
fill=axis.fill if isinstance(axis, AxisXStyle) else None,
|
|
670
|
+
time_unit=axis.time_unit if isinstance(axis, AxisXStyle) else None,
|
|
671
|
+
type=axis.type if isinstance(axis, AxisXStyle) else None,
|
|
672
|
+
# fiscal_year_start_month is x-only (year/yearquarter bucket
|
|
673
|
+
# anchoring); non-x axes get the neutral calendar-convention default
|
|
674
|
+
# (1 = January) since the resolved field stays a required int.
|
|
675
|
+
fiscal_year_start_month=(
|
|
676
|
+
axis.fiscal_year_start_month if isinstance(axis, AxisXStyle) else 1
|
|
677
|
+
),
|
|
594
678
|
tick_values=tick_values,
|
|
595
679
|
domain_max=None if domain_max is ... else domain_max,
|
|
596
680
|
domain_min=None if domain_min is ... else domain_min,
|
|
@@ -731,7 +815,10 @@ def _build_resolved_charts(
|
|
|
731
815
|
single_series_palette=resolved_single_series_palette,
|
|
732
816
|
requested_alias_palette=_categorical_obj.requested_alias_palette,
|
|
733
817
|
dashes=charts.dashes if charts.dashes is not None else [],
|
|
734
|
-
axis
|
|
818
|
+
# axis is a raw BaseAxisStyle passthrough — no eager resolution here.
|
|
819
|
+
# resolved_axis_style() in style_cascade.py merges it with channel-typed
|
|
820
|
+
# axis_x/axis_y at emit time, seeding channel-specific fields from the typed value.
|
|
821
|
+
axis=charts.axis,
|
|
735
822
|
axis_x=charts.axis_x,
|
|
736
823
|
axis_y=charts.axis_y,
|
|
737
824
|
axis_quantitative=charts.axis_quantitative,
|
|
@@ -14,7 +14,7 @@ class ResolvedAreaStyle(_SeriesCartesianResolvedStyle):
|
|
|
14
14
|
"""Area family style slice — self-contained, globals merged down.
|
|
15
15
|
|
|
16
16
|
Every field is concrete after resolve; the area emitter reads only these.
|
|
17
|
-
Inherits axis_x, axis_y, tooltip_format,
|
|
17
|
+
Inherits axis_x, axis_y, tooltip_format, series_label,
|
|
18
18
|
endpoint_labels, single_series_fill, label_usable_ratio
|
|
19
19
|
from the cartesian base hierarchy.
|
|
20
20
|
"""
|
|
@@ -16,7 +16,7 @@ class ResolvedBarStyle(_SeriesCartesianResolvedStyle):
|
|
|
16
16
|
"""Bar family style slice — self-contained, globals merged down.
|
|
17
17
|
|
|
18
18
|
Every field is concrete after resolve; the bar emitter reads only these.
|
|
19
|
-
Inherits axis_x, axis_y, tooltip_format,
|
|
19
|
+
Inherits axis_x, axis_y, tooltip_format, series_label,
|
|
20
20
|
endpoint_labels, single_series_fill, label_usable_ratio
|
|
21
21
|
from the cartesian base hierarchy.
|
|
22
22
|
"""
|
|
@@ -14,7 +14,7 @@ class ResolvedLineStyle(_SeriesCartesianResolvedStyle):
|
|
|
14
14
|
"""Line family style slice — self-contained, globals merged down.
|
|
15
15
|
|
|
16
16
|
Every field is concrete after resolve; the line emitter reads only these.
|
|
17
|
-
Inherits axis_x, axis_y, tooltip_format,
|
|
17
|
+
Inherits axis_x, axis_y, tooltip_format, series_label,
|
|
18
18
|
endpoint_labels, single_series_fill, label_usable_ratio
|
|
19
19
|
from the cartesian base hierarchy.
|
|
20
20
|
"""
|
|
@@ -4,7 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from pydantic import ConfigDict, Field
|
|
6
6
|
|
|
7
|
-
from dataface.core.compile.models.style.
|
|
7
|
+
from dataface.core.compile.models.style.resolved._base import ResolvedScaleStyle
|
|
8
|
+
from dataface.core.compile.models.style.theme import PointMarkStyle
|
|
8
9
|
|
|
9
10
|
from ._cartesian import _CartesianResolvedStyle
|
|
10
11
|
|
|
@@ -23,7 +24,7 @@ class ResolvedScatterStyle(_CartesianResolvedStyle):
|
|
|
23
24
|
single_series_fill: str = Field(
|
|
24
25
|
description="Fill color for single-series points (ink palette slot 0)."
|
|
25
26
|
)
|
|
26
|
-
scale:
|
|
27
|
+
scale: ResolvedScaleStyle | None = Field(
|
|
27
28
|
default=None,
|
|
28
29
|
description="Board-level chart scale override; None = no override.",
|
|
29
30
|
)
|
|
@@ -49,22 +49,33 @@ from dataface.core.compile.models.style.theme.area import (
|
|
|
49
49
|
AreaLineStyle,
|
|
50
50
|
)
|
|
51
51
|
from dataface.core.compile.models.style.theme.axis import (
|
|
52
|
-
AxisDomainStyle,
|
|
53
|
-
AxisElementStyle,
|
|
54
|
-
AxisGridStyle,
|
|
55
52
|
AxisGridZeroStyle,
|
|
56
53
|
AxisLabelOverlapConfig,
|
|
54
|
+
AxisLabelStyle,
|
|
55
|
+
AxisLineStyle,
|
|
57
56
|
AxisMirrorStyle,
|
|
58
|
-
AxisStyle,
|
|
59
|
-
AxisTicksCadenceValidationMixin,
|
|
60
57
|
AxisTicksStyle,
|
|
61
|
-
|
|
58
|
+
AxisTitleStyle,
|
|
59
|
+
AxisXStyle,
|
|
60
|
+
AxisYStyle,
|
|
61
|
+
BandAxisStyle,
|
|
62
|
+
BaseAxisGridStyle,
|
|
63
|
+
BaseAxisStyle,
|
|
64
|
+
BaseScaleStyle,
|
|
65
|
+
DimensionLabelStyle,
|
|
66
|
+
DimensionTicksStyle,
|
|
67
|
+
MeasureGridStyle,
|
|
68
|
+
QuantitativeAxisStyle,
|
|
69
|
+
ScaleContinuousStyle,
|
|
62
70
|
ScaleDomainValidationMixin,
|
|
63
|
-
|
|
71
|
+
ScaleLogStyle,
|
|
72
|
+
ScalePowStyle,
|
|
73
|
+
ScaleSymlogStyle,
|
|
64
74
|
TooltipBorderStyle,
|
|
65
75
|
TooltipShadowStyle,
|
|
66
76
|
TooltipSlotStyle,
|
|
67
77
|
TooltipStyle,
|
|
78
|
+
XScaleStyle,
|
|
68
79
|
)
|
|
69
80
|
from dataface.core.compile.models.style.theme.bar import (
|
|
70
81
|
BarChartMarksStyle,
|
|
@@ -243,15 +254,28 @@ __all__ = [
|
|
|
243
254
|
"AreaLayerStyle",
|
|
244
255
|
"AreaLineStyle",
|
|
245
256
|
"AreaMarkStyle",
|
|
246
|
-
"AxisDomainStyle",
|
|
247
|
-
"AxisElementStyle",
|
|
248
|
-
"AxisGridStyle",
|
|
249
257
|
"AxisGridZeroStyle",
|
|
250
258
|
"AxisLabelOverlapConfig",
|
|
259
|
+
"AxisLabelStyle",
|
|
260
|
+
"AxisLineStyle",
|
|
251
261
|
"AxisMirrorStyle",
|
|
252
|
-
"AxisStyle",
|
|
253
|
-
"AxisTicksCadenceValidationMixin",
|
|
254
262
|
"AxisTicksStyle",
|
|
263
|
+
"AxisTitleStyle",
|
|
264
|
+
"AxisXStyle",
|
|
265
|
+
"AxisYStyle",
|
|
266
|
+
"BandAxisStyle",
|
|
267
|
+
"BaseAxisGridStyle",
|
|
268
|
+
"BaseAxisStyle",
|
|
269
|
+
"BaseScaleStyle",
|
|
270
|
+
"DimensionLabelStyle",
|
|
271
|
+
"DimensionTicksStyle",
|
|
272
|
+
"MeasureGridStyle",
|
|
273
|
+
"QuantitativeAxisStyle",
|
|
274
|
+
"ScaleContinuousStyle",
|
|
275
|
+
"ScaleLogStyle",
|
|
276
|
+
"ScalePowStyle",
|
|
277
|
+
"ScaleSymlogStyle",
|
|
278
|
+
"XScaleStyle",
|
|
255
279
|
"BarChartMarksStyle",
|
|
256
280
|
"BarChartStyle",
|
|
257
281
|
"BarLayerStyle",
|
|
@@ -321,9 +345,7 @@ __all__ = [
|
|
|
321
345
|
"RectMarkStyle",
|
|
322
346
|
"RootFontStyle",
|
|
323
347
|
"RuleMarkStyle",
|
|
324
|
-
"ScaleBandStyle",
|
|
325
348
|
"ScaleDomainValidationMixin",
|
|
326
|
-
"ScaleStyle",
|
|
327
349
|
"ScatterChartMarksStyle",
|
|
328
350
|
"ScatterChartStyle",
|
|
329
351
|
"ScatterLayerStyle",
|
|
@@ -10,8 +10,12 @@ if TYPE_CHECKING:
|
|
|
10
10
|
# finishes executing). The import here is TYPE_CHECKING-only to give mypy and
|
|
11
11
|
# ruff the static definitions they need without creating a circular import.
|
|
12
12
|
from dataface.core.compile.models.style.authored import ( # noqa: PLC0415
|
|
13
|
-
|
|
13
|
+
AxisXStylePatch,
|
|
14
|
+
AxisYStylePatch,
|
|
15
|
+
BandAxisStylePatch,
|
|
16
|
+
BaseAxisStylePatch,
|
|
14
17
|
DataTableStylePatch,
|
|
18
|
+
QuantitativeAxisStylePatch,
|
|
15
19
|
TooltipStylePatch,
|
|
16
20
|
)
|
|
17
21
|
|
|
@@ -32,7 +36,7 @@ from dataface.core.compile.models.primitives import (
|
|
|
32
36
|
StaticGradientColorStyle,
|
|
33
37
|
)
|
|
34
38
|
from dataface.core.compile.models.style.theme.axis import (
|
|
35
|
-
|
|
39
|
+
BaseScaleStyle,
|
|
36
40
|
TooltipStyle,
|
|
37
41
|
)
|
|
38
42
|
from dataface.core.compile.models.style.theme.board import (
|
|
@@ -148,28 +152,30 @@ class _CartesianChartStyle(_ChartStyleBaseAllOptional):
|
|
|
148
152
|
# inherits the global axis at render time via resolved_axis_style's merge over
|
|
149
153
|
# the fully-resolved base axis. Without this, apply_inherit slot-fills these
|
|
150
154
|
# patches from the generic charts.font (prose ink) — so merely authoring an
|
|
151
|
-
# unrelated field like bar.axis_x.
|
|
155
|
+
# unrelated field like bar.axis_x.labels.padding materializes labels.font and
|
|
152
156
|
# drags prose ink into the label color, overriding the theme's muted axis
|
|
153
157
|
# color at the merge. Mirrors the `title` sentinel above (chart-local title
|
|
154
158
|
# is likewise a skip-slots sparse patch). The axis element font/color/family
|
|
155
159
|
# cascade is owned by the global axis nodes, not the per-family override.
|
|
156
|
-
axis: Annotated[
|
|
160
|
+
axis: Annotated[BaseAxisStylePatch | None, SkipInheritSlots()] = Field(
|
|
157
161
|
default=None,
|
|
158
162
|
description="Override applied to both x and y axes; None inherits the global axis at render.",
|
|
159
163
|
)
|
|
160
|
-
axis_x: Annotated[
|
|
164
|
+
axis_x: Annotated[AxisXStylePatch | None, SkipInheritSlots()] = Field(
|
|
161
165
|
default=None,
|
|
162
166
|
description="Per-chart-type x-axis style overrides; None inherits the global axis_x at render.",
|
|
163
167
|
)
|
|
164
|
-
axis_y: Annotated[
|
|
168
|
+
axis_y: Annotated[AxisYStylePatch | None, SkipInheritSlots()] = Field(
|
|
165
169
|
default=None,
|
|
166
170
|
description="Per-chart-type y-axis style overrides; None inherits the global axis_y at render.",
|
|
167
171
|
)
|
|
168
|
-
axis_quantitative: Annotated[
|
|
172
|
+
axis_quantitative: Annotated[
|
|
173
|
+
QuantitativeAxisStylePatch | None, SkipInheritSlots()
|
|
174
|
+
] = Field(
|
|
169
175
|
default=None,
|
|
170
176
|
description="Per-chart-type quantitative-axis overrides; None inherits the global axis_quantitative at render.",
|
|
171
177
|
)
|
|
172
|
-
axis_band: Annotated[
|
|
178
|
+
axis_band: Annotated[BandAxisStylePatch | None, SkipInheritSlots()] = Field(
|
|
173
179
|
default=None,
|
|
174
180
|
description="Per-chart-type categorical (band) axis overrides; None inherits the global band axis at render.",
|
|
175
181
|
)
|
|
@@ -181,7 +187,9 @@ class _CartesianChartStyle(_ChartStyleBaseAllOptional):
|
|
|
181
187
|
default=None,
|
|
182
188
|
description="Default time format for temporal axes (D3 time format string); None inherits from theme.",
|
|
183
189
|
)
|
|
184
|
-
|
|
190
|
+
# BaseScaleStyle (not XScaleStyle): this slot merges onto both x and y axes,
|
|
191
|
+
# so it must not carry x_reverse (which is structurally absent on BaseScaleStyle).
|
|
192
|
+
scale: BaseScaleStyle | None = Field(
|
|
185
193
|
default=None,
|
|
186
194
|
description="Chart-type encoding scale overrides applied to both x and y; None means no override.",
|
|
187
195
|
)
|