diff --git a/docs/schema/example-spec.json b/docs/schema/example-spec.json new file mode 100644 index 0000000..d3ce1b4 --- /dev/null +++ b/docs/schema/example-spec.json @@ -0,0 +1,62 @@ +{ + "$schema": "./flint-input.schema.json", + "semantic_types": { + "a": "Category", + "b": "Count" + }, + "data": { + "values": [ + { + "a": "A", + "b": 28 + }, + { + "a": "B", + "b": 55 + }, + { + "a": "C", + "b": 43 + }, + { + "a": "D", + "b": 91 + }, + { + "a": "E", + "b": 81 + }, + { + "a": "F", + "b": 53 + }, + { + "a": "G", + "b": 19 + }, + { + "a": "H", + "b": 87 + }, + { + "a": "I", + "b": 52 + } + ] + }, + "chart_spec": { + "canvasSize": { + "height": 600, + "width": 600 + }, + "chartType": "Bar Chart", + "encodings": { + "x": { + "field": "a" + }, + "y": { + "field": "b" + } + } + } +} \ No newline at end of file diff --git a/docs/schema/flint-input-chartjs.schema.json b/docs/schema/flint-input-chartjs.schema.json new file mode 100644 index 0000000..5f228f9 --- /dev/null +++ b/docs/schema/flint-input-chartjs.schema.json @@ -0,0 +1,1454 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/microsoft/flint-chart/docs/schema/flint-input-chartjs", + "title": "flint-input-chartjs", + "description": "Flint ChartAssemblyInput — Chart.js backend (all chart types).", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference URI (allows standalone .json files to declare their schema)." + }, + "data": { + "description": "Data source — provide inline rows via `values`, or a local file path via `url`.", + "oneOf": [ + { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Inline data rows (array of row objects)" + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Local file path to JSON/CSV/TSV data" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + } + ] + }, + "semantic_types": { + "type": "object", + "description": "Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).", + "additionalProperties": { + "$ref": "#/$defs/SemanticTypeValue" + } + }, + "chart_spec": { + "type": "object", + "description": "Chart specification — describes what to draw.", + "properties": { + "chartType": { + "type": "string", + "enum": [ + "Area Chart", + "Bar Chart", + "Bubble Chart", + "Bump Chart", + "Combo Chart", + "Connected Scatter Plot", + "Doughnut Chart", + "ECDF Plot", + "Gantt Chart", + "Grouped Bar Chart", + "Histogram", + "Line Chart", + "Pie Chart", + "Radar Chart", + "Range Area Chart", + "Rose Chart", + "Scatter Plot", + "Slope Chart", + "Stacked Bar Chart", + "Strip Plot", + "Waterfall Chart" + ], + "description": "Chart template name" + }, + "encodings": { + "type": "object", + "description": "Channel → encoding map. Valid channels depend on chartType.", + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + } + }, + "baseSize": { + "$ref": "#/$defs/Size", + "description": "Base (target) chart size in pixels (default: 400×320)" + }, + "canvasSize": { + "$ref": "#/$defs/Size", + "description": "Hard ceiling on rendered size in pixels (optional)" + }, + "chartProperties": { + "type": "object", + "description": "Template-specific configurable properties. Valid properties depend on chartType.", + "additionalProperties": true + } + }, + "required": [ + "chartType", + "encodings" + ], + "allOf": [ + { + "if": { + "properties": { + "chartType": { + "const": "Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 1 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Connected Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "order", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Connected Scatter Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bubble Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bubble Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.6 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Strip Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Strip Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "stepWidth": { + "type": "number", + "description": "Jitter", + "minimum": 10, + "maximum": 100, + "multipleOf": 5, + "default": 20 + }, + "pointSize": { + "type": "number", + "description": "Size", + "minimum": 0, + "maximum": 150, + "multipleOf": 5, + "default": 0 + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0, + "maximum": 1, + "multipleOf": 0.05, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Grouped Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "group", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Grouped Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Stacked Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Stacked Bar Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Combo Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Combo Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Histogram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Histogram" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Max Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Waterfall Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Waterfall Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gantt Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "x2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gantt Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "taskHeight": { + "type": "number", + "description": "Task height", + "minimum": 40, + "maximum": 90, + "multipleOf": 5, + "default": 70 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 2 + }, + "intervalLabels": { + "type": "boolean", + "description": "Labels", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Line Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Line Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bump Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bump Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Slope Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Slope Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.4 + }, + "stackMode": { + "description": "Stack", + "enum": [ + null, + "layered" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Range Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "y2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Range Area Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "ECDF Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for ECDF Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pie Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pie Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 0, + "maximum": 60, + "multipleOf": 5, + "default": 0 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Doughnut Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Doughnut Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Hole", + "minimum": 20, + "maximum": 80, + "multipleOf": 5, + "default": 55 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Radar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Radar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "filled": { + "description": "Fill", + "enum": [ + true, + false + ] + }, + "fillOpacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.05, + "maximum": 0.8, + "multipleOf": 0.05, + "default": 0.3 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Rose Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Rose Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "alignment": { + "description": "Alignment", + "enum": [ + "left", + "center" + ] + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + } + }, + "additionalProperties": true + } + } + } + } + ] + }, + "options": { + "$ref": "#/$defs/AssembleOptions" + }, + "field_display_names": { + "type": "object", + "description": "Field name → display label (used as axis titles and legend headers)", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "data", + "chart_spec" + ], + "additionalProperties": false, + "$defs": { + "ChartEncoding": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field (column) name from the data" + }, + "type": { + "type": "string", + "enum": [ + "quantitative", + "nominal", + "ordinal", + "temporal" + ], + "description": "Encoding type override" + }, + "aggregate": { + "type": "string", + "enum": [ + "count", + "sum", + "average", + "mean" + ], + "description": "Aggregation function" + }, + "sortOrder": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "Sort order for this channel" + }, + "sortBy": { + "type": "string", + "description": "Field name to sort by" + }, + "scheme": { + "type": "string", + "description": "Color scheme name (color channel)" + } + }, + "additionalProperties": false + }, + "RawEncodingValue": { + "description": "A channel encoding: an object, a bare field-name string shorthand, or an array (static series).", + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string", + "description": "Shorthand for { field: }" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string" + } + ] + }, + "description": "Static series array (multiple fields on the same channel)" + } + ] + }, + "SemanticAnnotation": { + "type": "object", + "properties": { + "semanticType": { + "type": "string", + "description": "Semantic type string (e.g. \"Amount\", \"Country\", \"Year\")" + }, + "intrinsicDomain": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "description": "Intrinsic domain [min, max] for bounded/scaled types" + }, + "unit": { + "type": "string", + "description": "Unit or currency code (e.g. \"USD\", \"°C\", \"kg\")" + }, + "sortOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Explicit ordinal ordering" + } + }, + "required": [ + "semanticType" + ], + "additionalProperties": false + }, + "SemanticTypeValue": { + "description": "A semantic type: either a string name or a SemanticAnnotation object.", + "oneOf": [ + { + "type": "string", + "enum": [ + "DateTime", + "Date", + "Time", + "Timestamp", + "Year", + "Quarter", + "Month", + "Week", + "Day", + "Hour", + "YearMonth", + "YearQuarter", + "YearWeek", + "Decade", + "Duration", + "Amount", + "Price", + "Quantity", + "Temperature", + "Percentage", + "Profit", + "PercentageChange", + "Sentiment", + "Correlation", + "Count", + "Number", + "Rank", + "Score", + "ID", + "Latitude", + "Longitude", + "Country", + "State", + "City", + "Region", + "Address", + "ZipCode", + "Category", + "Name", + "Status", + "Boolean", + "Direction", + "Range", + "Unknown" + ], + "description": "Registered semantic type name" + }, + { + "type": "string", + "description": "Custom/unregistered semantic type name" + }, + { + "$ref": "#/$defs/SemanticAnnotation" + } + ] + }, + "Size": { + "type": "object", + "properties": { + "width": { + "type": "number", + "minimum": 1, + "description": "Width in pixels" + }, + "height": { + "type": "number", + "minimum": 1, + "description": "Height in pixels" + } + }, + "required": [ + "width", + "height" + ], + "additionalProperties": false + }, + "AssembleOptions": { + "type": "object", + "description": "Layout tuning parameters. All optional with sensible defaults.", + "properties": { + "addTooltips": { + "type": "boolean", + "description": "Add tooltips (default: false)", + "default": false + }, + "stepPadding": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Inter-category padding fraction (default: 0.1)", + "default": 0.1 + }, + "elasticity": { + "type": "number", + "description": "Power-law exponent for discrete axis stretch (default: 0.5)", + "default": 0.5 + }, + "maxStretch": { + "type": "number", + "minimum": 1, + "description": "Maximum stretch multiplier (default: 2)", + "default": 2 + }, + "maxStretchX": { + "type": "number", + "minimum": 1, + "description": "Per-dimension X stretch cap" + }, + "maxStretchY": { + "type": "number", + "minimum": 1, + "description": "Per-dimension Y stretch cap" + }, + "facetElasticity": { + "type": "number", + "description": "Facet subplot stretch exponent (default: 0.3)", + "default": 0.3 + }, + "minStep": { + "type": "number", + "minimum": 1, + "description": "Min px per discrete axis item (default: 6)", + "default": 6 + }, + "maxColorValues": { + "type": "integer", + "minimum": 1, + "description": "Max distinct color values before truncation (default: 24)", + "default": 24 + }, + "minSubplotSize": { + "type": "number", + "minimum": 1, + "description": "Min facet subplot size in px (default: 60)", + "default": 60 + }, + "facetFixedPadding": { + "$ref": "#/$defs/Size", + "description": "Fixed overhead in px for axis labels/titles/legend" + }, + "facetGap": { + "type": "number", + "minimum": 0, + "description": "Gap between facet panels in px" + }, + "facetColumns": { + "type": "integer", + "minimum": 1, + "description": "Explicit facet column count (overrides auto-wrap)" + }, + "defaultBandSize": { + "type": "number", + "minimum": 1, + "description": "Base px per discrete category at 300px baseline (default: 20)", + "default": 20 + }, + "maxBandSize": { + "type": "number", + "minimum": 1, + "description": "Max px per discrete category (sparse expansion ceiling)" + }, + "baseLabelFontSize": { + "type": "number", + "minimum": 1, + "description": "Base tick label font size (default: 10)", + "default": 10 + }, + "baseTitleFontSize": { + "type": "number", + "minimum": 1, + "description": "Base header/title font size (default: 11)", + "default": 11 + }, + "maintainContinuousAxisRatio": { + "type": "boolean", + "description": "Lock continuous axes aspect ratio (default: false)", + "default": false + }, + "continuousMarkCrossSection": { + "description": "Gas-pressure tuning for continuous axes", + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "elasticity": { + "type": "number" + }, + "maxStretch": { + "type": "number" + }, + "seriesCountAxis": { + "type": "string", + "enum": [ + "x", + "y", + "auto" + ] + } + }, + "required": [ + "x", + "y" + ] + } + ] + }, + "facetAspectRatioResistance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Resistance to AR distortion when faceting (0–1)" + }, + "autoFacetWrap": { + "type": "boolean", + "description": "Auto-wrap column-only facets (default: true)", + "default": true + }, + "targetBandAR": { + "type": "number", + "description": "Target aspect ratio for a single band (0 = no correction)" + } + }, + "additionalProperties": false + } + } +} diff --git a/docs/schema/flint-input-echarts.schema.json b/docs/schema/flint-input-echarts.schema.json new file mode 100644 index 0000000..434fd4e --- /dev/null +++ b/docs/schema/flint-input-echarts.schema.json @@ -0,0 +1,2176 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/microsoft/flint-chart/docs/schema/flint-input-echarts", + "title": "flint-input-echarts", + "description": "Flint ChartAssemblyInput — ECharts backend (all chart types).", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference URI (allows standalone .json files to declare their schema)." + }, + "data": { + "description": "Data source — provide inline rows via `values`, or a local file path via `url`.", + "oneOf": [ + { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Inline data rows (array of row objects)" + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Local file path to JSON/CSV/TSV data" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + } + ] + }, + "semantic_types": { + "type": "object", + "description": "Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).", + "additionalProperties": { + "$ref": "#/$defs/SemanticTypeValue" + } + }, + "chart_spec": { + "type": "object", + "description": "Chart specification — describes what to draw.", + "properties": { + "chartType": { + "type": "string", + "enum": [ + "Area Chart", + "Bar Chart", + "Boxplot", + "Bullet Chart", + "Bump Chart", + "Calendar Heatmap", + "Candlestick Chart", + "Connected Scatter Plot", + "Density Plot", + "ECDF Plot", + "Funnel Chart", + "Gantt Chart", + "Gauge Chart", + "Grouped Bar Chart", + "Heatmap", + "Histogram", + "Line Chart", + "Lollipop Chart", + "Network Graph", + "Parallel Coordinates", + "Pie Chart", + "Pyramid Chart", + "Radar Chart", + "Range Area Chart", + "Ranged Dot Plot", + "Regression", + "Rose Chart", + "Sankey Diagram", + "Scatter Plot", + "Slope Chart", + "Stacked Bar Chart", + "Streamgraph", + "Strip Plot", + "Sunburst Chart", + "Tree", + "Treemap", + "Waterfall Chart" + ], + "description": "Chart template name" + }, + "encodings": { + "type": "object", + "description": "Channel → encoding map. Valid channels depend on chartType.", + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + } + }, + "baseSize": { + "$ref": "#/$defs/Size", + "description": "Base (target) chart size in pixels (default: 400×320)" + }, + "canvasSize": { + "$ref": "#/$defs/Size", + "description": "Hard ceiling on rendered size in pixels (optional)" + }, + "chartProperties": { + "type": "object", + "description": "Template-specific configurable properties. Valid properties depend on chartType.", + "additionalProperties": true + } + }, + "required": [ + "chartType", + "encodings" + ], + "allOf": [ + { + "if": { + "properties": { + "chartType": { + "const": "Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 1 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Regression" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Regression" + }, + "chartProperties": { + "type": "object", + "properties": { + "regressionMethod": { + "description": "Method", + "enum": [ + "linear", + "log", + "exp", + "pow", + "quad", + "poly" + ], + "default": "linear" + }, + "polyOrder": { + "type": "number", + "description": "Poly Order", + "minimum": 2, + "maximum": 10, + "multipleOf": 1, + "default": 3 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Connected Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "order", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Connected Scatter Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Ranged Dot Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Ranged Dot Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Boxplot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Boxplot" + }, + "chartProperties": { + "type": "object", + "properties": { + "whiskerMethod": { + "description": "Whiskers", + "enum": [ + "iqr", + "minmax" + ], + "default": "iqr" + }, + "showOutliers": { + "type": "boolean", + "description": "Outliers", + "default": true + }, + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Strip Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Strip Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Grouped Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "group", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Grouped Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Stacked Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Stacked Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Lollipop Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Lollipop Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dotSize": { + "type": "number", + "description": "Dot Size", + "minimum": 20, + "maximum": 300, + "multipleOf": 10, + "default": 80 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pyramid Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pyramid Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Heatmap" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Heatmap" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Calendar Heatmap" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Calendar Heatmap" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Line Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Line Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bump Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bump Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Slope Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Slope Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.7 + }, + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "center", + "layered" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Streamgraph" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Streamgraph" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Range Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "y2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Range Area Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pie Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pie Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 0, + "maximum": 60, + "multipleOf": 5, + "default": 0 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 10, + "multipleOf": 1, + "default": 0 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "labelType": { + "description": "Labels", + "enum": [ + "categoryPercent", + "category", + "value", + "percent", + "none" + ], + "default": "categoryPercent" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Funnel Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "size" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Funnel Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "sort": { + "description": "Sort", + "enum": [ + "descending", + "ascending", + "none" + ] + }, + "orient": { + "description": "Orient", + "enum": [ + "vertical", + "horizontal" + ] + }, + "gap": { + "type": "number", + "description": "Gap", + "minimum": 0, + "maximum": 20, + "multipleOf": 1, + "default": 2 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Treemap" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "color", + "size", + "detail" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Treemap" + }, + "chartProperties": { + "type": "object", + "properties": { + "breadcrumb": { + "description": "Breadcrumb", + "enum": [ + true, + false + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Sunburst Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "color", + "size", + "detail", + "group" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Sunburst Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Inner R", + "minimum": 0, + "maximum": 80, + "multipleOf": 5, + "default": 0 + }, + "labelRotate": { + "description": "Labels", + "enum": [ + "radial", + "tangential", + 0 + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Tree" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "color", + "detail", + "size" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Tree" + }, + "chartProperties": { + "type": "object", + "properties": { + "orient": { + "description": "Orient", + "enum": [ + "LR", + "TB" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Histogram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Histogram" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Max Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Density Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Density Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "bandwidth": { + "type": "number", + "description": "Bandwidth", + "minimum": 0.05, + "maximum": 2, + "multipleOf": 0.05, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "ECDF Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for ECDF Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Parallel Coordinates" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "color", + "detail" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Parallel Coordinates" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Candlestick Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "open", + "high", + "low", + "close", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Candlestick Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "showMA": { + "type": "boolean", + "description": "Moving average", + "default": false + }, + "maWindow": { + "type": "number", + "description": "Average window", + "minimum": 3, + "maximum": 30, + "multipleOf": 1, + "default": 5 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Waterfall Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Waterfall Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gantt Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "x2", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gantt Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "taskHeight": { + "type": "number", + "description": "Task height", + "minimum": 40, + "maximum": 90, + "multipleOf": 5, + "default": 70 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 2 + }, + "intervalLabels": { + "type": "boolean", + "description": "Labels", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bullet Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "goal", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bullet Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Radar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Radar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "shape": { + "description": "Grid", + "enum": [ + null, + "circle" + ] + }, + "filled": { + "description": "Fill", + "enum": [ + true, + false + ] + }, + "fillOpacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.05, + "maximum": 0.8, + "multipleOf": 0.05, + "default": 0.3 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Rose Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Rose Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "alignment": { + "description": "Alignment", + "enum": [ + "left", + "center" + ] + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gauge Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "column" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gauge Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "min": { + "type": "number", + "description": "Min", + "minimum": 0, + "maximum": 1000, + "multipleOf": 10, + "default": 0 + }, + "max": { + "type": "number", + "description": "Max", + "minimum": 0, + "maximum": 10000, + "multipleOf": 100, + "default": 100 + }, + "showProgress": { + "description": "Progress", + "enum": [ + true, + false + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Sankey Diagram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Sankey Diagram" + }, + "chartProperties": { + "type": "object", + "properties": { + "orient": { + "description": "Orient", + "enum": [ + "horizontal", + "vertical" + ] + }, + "nodeWidth": { + "type": "number", + "description": "Node Width", + "minimum": 5, + "maximum": 40, + "multipleOf": 5, + "default": 20 + }, + "nodeGap": { + "type": "number", + "description": "Node Gap", + "minimum": 2, + "maximum": 30, + "multipleOf": 2, + "default": 10 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Network Graph" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Network Graph" + }, + "chartProperties": { + "type": "object", + "properties": { + "layout": { + "description": "Layout", + "enum": [ + "circular", + "force" + ] + } + }, + "additionalProperties": true + } + } + } + } + ] + }, + "options": { + "$ref": "#/$defs/AssembleOptions" + }, + "field_display_names": { + "type": "object", + "description": "Field name → display label (used as axis titles and legend headers)", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "data", + "chart_spec" + ], + "additionalProperties": false, + "$defs": { + "ChartEncoding": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field (column) name from the data" + }, + "type": { + "type": "string", + "enum": [ + "quantitative", + "nominal", + "ordinal", + "temporal" + ], + "description": "Encoding type override" + }, + "aggregate": { + "type": "string", + "enum": [ + "count", + "sum", + "average", + "mean" + ], + "description": "Aggregation function" + }, + "sortOrder": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "Sort order for this channel" + }, + "sortBy": { + "type": "string", + "description": "Field name to sort by" + }, + "scheme": { + "type": "string", + "description": "Color scheme name (color channel)" + } + }, + "additionalProperties": false + }, + "RawEncodingValue": { + "description": "A channel encoding: an object, a bare field-name string shorthand, or an array (static series).", + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string", + "description": "Shorthand for { field: }" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string" + } + ] + }, + "description": "Static series array (multiple fields on the same channel)" + } + ] + }, + "SemanticAnnotation": { + "type": "object", + "properties": { + "semanticType": { + "type": "string", + "description": "Semantic type string (e.g. \"Amount\", \"Country\", \"Year\")" + }, + "intrinsicDomain": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "description": "Intrinsic domain [min, max] for bounded/scaled types" + }, + "unit": { + "type": "string", + "description": "Unit or currency code (e.g. \"USD\", \"°C\", \"kg\")" + }, + "sortOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Explicit ordinal ordering" + } + }, + "required": [ + "semanticType" + ], + "additionalProperties": false + }, + "SemanticTypeValue": { + "description": "A semantic type: either a string name or a SemanticAnnotation object.", + "oneOf": [ + { + "type": "string", + "enum": [ + "DateTime", + "Date", + "Time", + "Timestamp", + "Year", + "Quarter", + "Month", + "Week", + "Day", + "Hour", + "YearMonth", + "YearQuarter", + "YearWeek", + "Decade", + "Duration", + "Amount", + "Price", + "Quantity", + "Temperature", + "Percentage", + "Profit", + "PercentageChange", + "Sentiment", + "Correlation", + "Count", + "Number", + "Rank", + "Score", + "ID", + "Latitude", + "Longitude", + "Country", + "State", + "City", + "Region", + "Address", + "ZipCode", + "Category", + "Name", + "Status", + "Boolean", + "Direction", + "Range", + "Unknown" + ], + "description": "Registered semantic type name" + }, + { + "type": "string", + "description": "Custom/unregistered semantic type name" + }, + { + "$ref": "#/$defs/SemanticAnnotation" + } + ] + }, + "Size": { + "type": "object", + "properties": { + "width": { + "type": "number", + "minimum": 1, + "description": "Width in pixels" + }, + "height": { + "type": "number", + "minimum": 1, + "description": "Height in pixels" + } + }, + "required": [ + "width", + "height" + ], + "additionalProperties": false + }, + "AssembleOptions": { + "type": "object", + "description": "Layout tuning parameters. All optional with sensible defaults.", + "properties": { + "addTooltips": { + "type": "boolean", + "description": "Add tooltips (default: false)", + "default": false + }, + "stepPadding": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Inter-category padding fraction (default: 0.1)", + "default": 0.1 + }, + "elasticity": { + "type": "number", + "description": "Power-law exponent for discrete axis stretch (default: 0.5)", + "default": 0.5 + }, + "maxStretch": { + "type": "number", + "minimum": 1, + "description": "Maximum stretch multiplier (default: 2)", + "default": 2 + }, + "maxStretchX": { + "type": "number", + "minimum": 1, + "description": "Per-dimension X stretch cap" + }, + "maxStretchY": { + "type": "number", + "minimum": 1, + "description": "Per-dimension Y stretch cap" + }, + "facetElasticity": { + "type": "number", + "description": "Facet subplot stretch exponent (default: 0.3)", + "default": 0.3 + }, + "minStep": { + "type": "number", + "minimum": 1, + "description": "Min px per discrete axis item (default: 6)", + "default": 6 + }, + "maxColorValues": { + "type": "integer", + "minimum": 1, + "description": "Max distinct color values before truncation (default: 24)", + "default": 24 + }, + "minSubplotSize": { + "type": "number", + "minimum": 1, + "description": "Min facet subplot size in px (default: 60)", + "default": 60 + }, + "facetFixedPadding": { + "$ref": "#/$defs/Size", + "description": "Fixed overhead in px for axis labels/titles/legend" + }, + "facetGap": { + "type": "number", + "minimum": 0, + "description": "Gap between facet panels in px" + }, + "facetColumns": { + "type": "integer", + "minimum": 1, + "description": "Explicit facet column count (overrides auto-wrap)" + }, + "defaultBandSize": { + "type": "number", + "minimum": 1, + "description": "Base px per discrete category at 300px baseline (default: 20)", + "default": 20 + }, + "maxBandSize": { + "type": "number", + "minimum": 1, + "description": "Max px per discrete category (sparse expansion ceiling)" + }, + "baseLabelFontSize": { + "type": "number", + "minimum": 1, + "description": "Base tick label font size (default: 10)", + "default": 10 + }, + "baseTitleFontSize": { + "type": "number", + "minimum": 1, + "description": "Base header/title font size (default: 11)", + "default": 11 + }, + "maintainContinuousAxisRatio": { + "type": "boolean", + "description": "Lock continuous axes aspect ratio (default: false)", + "default": false + }, + "continuousMarkCrossSection": { + "description": "Gas-pressure tuning for continuous axes", + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "elasticity": { + "type": "number" + }, + "maxStretch": { + "type": "number" + }, + "seriesCountAxis": { + "type": "string", + "enum": [ + "x", + "y", + "auto" + ] + } + }, + "required": [ + "x", + "y" + ] + } + ] + }, + "facetAspectRatioResistance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Resistance to AR distortion when faceting (0–1)" + }, + "autoFacetWrap": { + "type": "boolean", + "description": "Auto-wrap column-only facets (default: true)", + "default": true + }, + "targetBandAR": { + "type": "number", + "description": "Target aspect ratio for a single band (0 = no correction)" + } + }, + "additionalProperties": false + } + } +} diff --git a/docs/schema/flint-input-plotly.schema.json b/docs/schema/flint-input-plotly.schema.json new file mode 100644 index 0000000..36bd379 --- /dev/null +++ b/docs/schema/flint-input-plotly.schema.json @@ -0,0 +1,2333 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/microsoft/flint-chart/docs/schema/flint-input-plotly", + "title": "flint-input-plotly", + "description": "Flint ChartAssemblyInput — Plotly backend (all chart types).", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference URI (allows standalone .json files to declare their schema)." + }, + "data": { + "description": "Data source — provide inline rows via `values`, or a local file path via `url`.", + "oneOf": [ + { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Inline data rows (array of row objects)" + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Local file path to JSON/CSV/TSV data" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + } + ] + }, + "semantic_types": { + "type": "object", + "description": "Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).", + "additionalProperties": { + "$ref": "#/$defs/SemanticTypeValue" + } + }, + "chart_spec": { + "type": "object", + "description": "Chart specification — describes what to draw.", + "properties": { + "chartType": { + "type": "string", + "enum": [ + "Area Chart", + "Bar Chart", + "Bar Table", + "Boxplot", + "Bullet Chart", + "Bump Chart", + "Candlestick Chart", + "Choropleth", + "Connected Scatter Plot", + "Density Contour", + "Density Plot", + "Donut Chart", + "ECDF Plot", + "Funnel Chart", + "Gantt Chart", + "Gauge Chart", + "Grouped Bar Chart", + "Heatmap", + "Histogram", + "KPI Card", + "Line Chart", + "Lollipop Chart", + "Map", + "Pie Chart", + "Pyramid Chart", + "Radar Chart", + "Range Area Chart", + "Ranged Dot Plot", + "Regression", + "Rose Chart", + "Scatter Plot", + "Slope Chart", + "Sparkline", + "Stacked Bar Chart", + "Streamgraph", + "Strip Plot", + "Violin Plot", + "Waterfall Chart" + ], + "description": "Chart template name" + }, + "encodings": { + "type": "object", + "description": "Channel → encoding map. Valid channels depend on chartType.", + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + } + }, + "baseSize": { + "$ref": "#/$defs/Size", + "description": "Base (target) chart size in pixels (default: 400×320)" + }, + "canvasSize": { + "$ref": "#/$defs/Size", + "description": "Hard ceiling on rendered size in pixels (optional)" + }, + "chartProperties": { + "type": "object", + "description": "Template-specific configurable properties. Valid properties depend on chartType.", + "additionalProperties": true + } + }, + "required": [ + "chartType", + "encodings" + ], + "allOf": [ + { + "if": { + "properties": { + "chartType": { + "const": "Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 1 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Regression" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Regression" + }, + "chartProperties": { + "type": "object", + "properties": { + "regressionMethod": { + "description": "Method", + "enum": [ + "linear", + "log", + "exp", + "pow", + "quad", + "poly" + ], + "default": "linear" + }, + "polyOrder": { + "type": "number", + "description": "Poly Order", + "minimum": 2, + "maximum": 10, + "multipleOf": 1, + "default": 3 + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 1 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Connected Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "order", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Connected Scatter Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Ranged Dot Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Ranged Dot Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Strip Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Strip Plot" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Grouped Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "group", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Grouped Bar Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Stacked Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Stacked Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Lollipop Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Lollipop Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dotSize": { + "type": "number", + "description": "Dot Size", + "minimum": 20, + "maximum": 300, + "multipleOf": 10, + "default": 80 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Waterfall Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Waterfall Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "totals": { + "description": "Totals", + "enum": [ + "auto", + "none", + "first", + "last", + "both" + ], + "default": "auto" + }, + "showTextLabels": { + "type": "boolean", + "description": "Value labels", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pyramid Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pyramid Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Histogram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Histogram" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Max Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 10 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Boxplot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Boxplot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showOutliers": { + "type": "boolean", + "description": "Outliers", + "default": true + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Violin Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Violin Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showBox": { + "type": "boolean", + "description": "Inner box", + "default": true + }, + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Density Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Density Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "bandwidth": { + "type": "number", + "description": "Bandwidth", + "minimum": 0.05, + "maximum": 2, + "multipleOf": 0.05, + "default": 0 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "ECDF Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for ECDF Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Candlestick Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "open", + "high", + "low", + "close", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Candlestick Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "showMA": { + "type": "boolean", + "description": "Moving average", + "default": false + }, + "maWindow": { + "type": "number", + "description": "Average window", + "minimum": 3, + "maximum": 30, + "multipleOf": 1, + "default": 5 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Density Contour" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Density Contour" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 20 + }, + "showPoints": { + "type": "boolean", + "description": "Show points", + "default": true + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Line Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Line Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "showPoints": { + "type": "boolean", + "description": "Show points", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.4 + }, + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "layered" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bump Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bump Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Slope Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Slope Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Streamgraph" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Streamgraph" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Range Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "y2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Range Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.35 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pie Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pie Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "labelType": { + "description": "Labels", + "enum": [ + "categoryPercent", + "category", + "value", + "percent", + "none" + ], + "default": "categoryPercent" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Donut Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Donut Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 20, + "maximum": 80, + "multipleOf": 5, + "default": 55 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "labelType": { + "description": "Labels", + "enum": [ + "categoryPercent", + "category", + "value", + "percent", + "none" + ], + "default": "categoryPercent" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Radar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Radar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "filled": { + "description": "Fill", + "enum": [ + true, + false + ] + }, + "fillOpacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.05, + "maximum": 0.8, + "multipleOf": 0.05, + "default": 0.3 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Rose Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Rose Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Heatmap" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Heatmap" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gantt Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "x2", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gantt Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "taskHeight": { + "type": "number", + "description": "Task height", + "minimum": 40, + "maximum": 90, + "multipleOf": 5, + "default": 70 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 2 + }, + "intervalLabels": { + "type": "boolean", + "description": "Labels", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bullet Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "goal", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bullet Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "KPI Card" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "metric", + "value", + "goal" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for KPI Card" + }, + "chartProperties": { + "type": "object", + "properties": { + "layout": { + "description": "Layout", + "enum": [ + "horizontal", + "vertical", + "grid" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Sparkline" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Sparkline" + }, + "chartProperties": { + "type": "object", + "properties": { + "baseline": { + "description": "Reference line", + "enum": [ + "mean", + "zero", + "median", + "none" + ], + "default": "mean" + }, + "trendWidth": { + "type": "number", + "description": "Sparkline width", + "minimum": 80, + "maximum": 600, + "multipleOf": 10, + "default": 240 + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Table" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Table" + }, + "chartProperties": { + "type": "object", + "properties": { + "maxRows": { + "type": "number", + "description": "Max Rows", + "minimum": 5, + "maximum": 100, + "multipleOf": 1, + "default": 20 + }, + "showPercent": { + "type": "boolean", + "description": "% of total", + "default": false + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Map" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "longitude", + "latitude", + "color", + "size", + "opacity" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Map" + }, + "chartProperties": { + "type": "object", + "properties": { + "region": { + "description": "Region", + "enum": [ + "auto", + "us", + "world" + ], + "default": "auto" + }, + "projection": { + "description": "Projection", + "enum": [ + "default", + "mercator", + "equalEarth", + "orthographic", + "stereographic", + "conicEqualArea", + "conicEquidistant", + "azimuthalEquidistant", + "mollweide" + ], + "default": "default" + }, + "projectionCenter": { + "description": "Center", + "enum": [ + null, + [ + 0, + 0 + ], + [ + 150, + 0 + ], + [ + 105, + 35 + ], + [ + -98, + 39 + ], + [ + 10, + 50 + ], + [ + 138, + 36 + ], + [ + 78, + 22 + ], + [ + -52, + -14 + ], + [ + 134, + -25 + ], + [ + 100, + 60 + ], + [ + 20, + 0 + ], + [ + 45, + 28 + ], + [ + 115, + 5 + ], + [ + -60, + -15 + ], + [ + -100, + 45 + ], + [ + -2, + 54 + ], + [ + 10, + 51 + ], + [ + 2, + 47 + ], + [ + 128, + 36 + ] + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Choropleth" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "id", + "color", + "detail" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Choropleth" + }, + "chartProperties": { + "type": "object", + "properties": { + "region": { + "description": "Region", + "enum": [ + "auto", + "us", + "world" + ], + "default": "auto" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Funnel Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "size" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Funnel Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "sort": { + "description": "Sort", + "enum": [ + "descending", + "ascending", + "none" + ], + "default": "descending" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gauge Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "column" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gauge Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "min": { + "type": "number", + "description": "Min", + "minimum": 0, + "maximum": 1000, + "multipleOf": 10, + "default": 0 + }, + "max": { + "type": "number", + "description": "Max", + "minimum": 0, + "maximum": 10000, + "multipleOf": 100, + "default": 100 + } + }, + "additionalProperties": true + } + } + } + } + ] + }, + "options": { + "$ref": "#/$defs/AssembleOptions" + }, + "field_display_names": { + "type": "object", + "description": "Field name → display label (used as axis titles and legend headers)", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "data", + "chart_spec" + ], + "additionalProperties": false, + "$defs": { + "ChartEncoding": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field (column) name from the data" + }, + "type": { + "type": "string", + "enum": [ + "quantitative", + "nominal", + "ordinal", + "temporal" + ], + "description": "Encoding type override" + }, + "aggregate": { + "type": "string", + "enum": [ + "count", + "sum", + "average", + "mean" + ], + "description": "Aggregation function" + }, + "sortOrder": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "Sort order for this channel" + }, + "sortBy": { + "type": "string", + "description": "Field name to sort by" + }, + "scheme": { + "type": "string", + "description": "Color scheme name (color channel)" + } + }, + "additionalProperties": false + }, + "RawEncodingValue": { + "description": "A channel encoding: an object, a bare field-name string shorthand, or an array (static series).", + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string", + "description": "Shorthand for { field: }" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string" + } + ] + }, + "description": "Static series array (multiple fields on the same channel)" + } + ] + }, + "SemanticAnnotation": { + "type": "object", + "properties": { + "semanticType": { + "type": "string", + "description": "Semantic type string (e.g. \"Amount\", \"Country\", \"Year\")" + }, + "intrinsicDomain": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "description": "Intrinsic domain [min, max] for bounded/scaled types" + }, + "unit": { + "type": "string", + "description": "Unit or currency code (e.g. \"USD\", \"°C\", \"kg\")" + }, + "sortOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Explicit ordinal ordering" + } + }, + "required": [ + "semanticType" + ], + "additionalProperties": false + }, + "SemanticTypeValue": { + "description": "A semantic type: either a string name or a SemanticAnnotation object.", + "oneOf": [ + { + "type": "string", + "enum": [ + "DateTime", + "Date", + "Time", + "Timestamp", + "Year", + "Quarter", + "Month", + "Week", + "Day", + "Hour", + "YearMonth", + "YearQuarter", + "YearWeek", + "Decade", + "Duration", + "Amount", + "Price", + "Quantity", + "Temperature", + "Percentage", + "Profit", + "PercentageChange", + "Sentiment", + "Correlation", + "Count", + "Number", + "Rank", + "Score", + "ID", + "Latitude", + "Longitude", + "Country", + "State", + "City", + "Region", + "Address", + "ZipCode", + "Category", + "Name", + "Status", + "Boolean", + "Direction", + "Range", + "Unknown" + ], + "description": "Registered semantic type name" + }, + { + "type": "string", + "description": "Custom/unregistered semantic type name" + }, + { + "$ref": "#/$defs/SemanticAnnotation" + } + ] + }, + "Size": { + "type": "object", + "properties": { + "width": { + "type": "number", + "minimum": 1, + "description": "Width in pixels" + }, + "height": { + "type": "number", + "minimum": 1, + "description": "Height in pixels" + } + }, + "required": [ + "width", + "height" + ], + "additionalProperties": false + }, + "AssembleOptions": { + "type": "object", + "description": "Layout tuning parameters. All optional with sensible defaults.", + "properties": { + "addTooltips": { + "type": "boolean", + "description": "Add tooltips (default: false)", + "default": false + }, + "stepPadding": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Inter-category padding fraction (default: 0.1)", + "default": 0.1 + }, + "elasticity": { + "type": "number", + "description": "Power-law exponent for discrete axis stretch (default: 0.5)", + "default": 0.5 + }, + "maxStretch": { + "type": "number", + "minimum": 1, + "description": "Maximum stretch multiplier (default: 2)", + "default": 2 + }, + "maxStretchX": { + "type": "number", + "minimum": 1, + "description": "Per-dimension X stretch cap" + }, + "maxStretchY": { + "type": "number", + "minimum": 1, + "description": "Per-dimension Y stretch cap" + }, + "facetElasticity": { + "type": "number", + "description": "Facet subplot stretch exponent (default: 0.3)", + "default": 0.3 + }, + "minStep": { + "type": "number", + "minimum": 1, + "description": "Min px per discrete axis item (default: 6)", + "default": 6 + }, + "maxColorValues": { + "type": "integer", + "minimum": 1, + "description": "Max distinct color values before truncation (default: 24)", + "default": 24 + }, + "minSubplotSize": { + "type": "number", + "minimum": 1, + "description": "Min facet subplot size in px (default: 60)", + "default": 60 + }, + "facetFixedPadding": { + "$ref": "#/$defs/Size", + "description": "Fixed overhead in px for axis labels/titles/legend" + }, + "facetGap": { + "type": "number", + "minimum": 0, + "description": "Gap between facet panels in px" + }, + "facetColumns": { + "type": "integer", + "minimum": 1, + "description": "Explicit facet column count (overrides auto-wrap)" + }, + "defaultBandSize": { + "type": "number", + "minimum": 1, + "description": "Base px per discrete category at 300px baseline (default: 20)", + "default": 20 + }, + "maxBandSize": { + "type": "number", + "minimum": 1, + "description": "Max px per discrete category (sparse expansion ceiling)" + }, + "baseLabelFontSize": { + "type": "number", + "minimum": 1, + "description": "Base tick label font size (default: 10)", + "default": 10 + }, + "baseTitleFontSize": { + "type": "number", + "minimum": 1, + "description": "Base header/title font size (default: 11)", + "default": 11 + }, + "maintainContinuousAxisRatio": { + "type": "boolean", + "description": "Lock continuous axes aspect ratio (default: false)", + "default": false + }, + "continuousMarkCrossSection": { + "description": "Gas-pressure tuning for continuous axes", + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "elasticity": { + "type": "number" + }, + "maxStretch": { + "type": "number" + }, + "seriesCountAxis": { + "type": "string", + "enum": [ + "x", + "y", + "auto" + ] + } + }, + "required": [ + "x", + "y" + ] + } + ] + }, + "facetAspectRatioResistance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Resistance to AR distortion when faceting (0–1)" + }, + "autoFacetWrap": { + "type": "boolean", + "description": "Auto-wrap column-only facets (default: true)", + "default": true + }, + "targetBandAR": { + "type": "number", + "description": "Target aspect ratio for a single band (0 = no correction)" + } + }, + "additionalProperties": false + } + } +} diff --git a/docs/schema/flint-input-vegalite.schema.json b/docs/schema/flint-input-vegalite.schema.json new file mode 100644 index 0000000..695325d --- /dev/null +++ b/docs/schema/flint-input-vegalite.schema.json @@ -0,0 +1,2826 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/microsoft/flint-chart/docs/schema/flint-input-vegalite", + "title": "flint-input-vegalite", + "description": "Flint ChartAssemblyInput — Vega-Lite backend (all chart types).", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference URI (allows standalone .json files to declare their schema)." + }, + "data": { + "description": "Data source — provide inline rows via `values`, or a local file path via `url`.", + "oneOf": [ + { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Inline data rows (array of row objects)" + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Local file path to JSON/CSV/TSV data" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + } + ] + }, + "semantic_types": { + "type": "object", + "description": "Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).", + "additionalProperties": { + "$ref": "#/$defs/SemanticTypeValue" + } + }, + "chart_spec": { + "type": "object", + "description": "Chart specification — describes what to draw.", + "properties": { + "chartType": { + "type": "string", + "enum": [ + "Area Chart", + "Bar Chart", + "Bar Table", + "Boxplot", + "Bullet Chart", + "Bump Chart", + "Candlestick Chart", + "Choropleth", + "Connected Scatter Plot", + "Density Plot", + "Donut Chart", + "ECDF Plot", + "Gantt Chart", + "Grouped Bar Chart", + "Heatmap", + "Histogram", + "KPI Card", + "Line Chart", + "Lollipop Chart", + "Map", + "Pie Chart", + "Pyramid Chart", + "Radar Chart", + "Range Area Chart", + "Ranged Dot Plot", + "Regression", + "Rose Chart", + "Scatter Plot", + "Slope Chart", + "Sparkline", + "Stacked Bar Chart", + "Streamgraph", + "Strip Plot", + "Violin Plot", + "Waterfall Chart" + ], + "description": "Chart template name" + }, + "encodings": { + "type": "object", + "description": "Channel → encoding map. Valid channels depend on chartType.", + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + } + }, + "baseSize": { + "$ref": "#/$defs/Size", + "description": "Base (target) chart size in pixels (default: 400×320)" + }, + "canvasSize": { + "$ref": "#/$defs/Size", + "description": "Hard ceiling on rendered size in pixels (optional)" + }, + "chartProperties": { + "type": "object", + "description": "Template-specific configurable properties. Valid properties depend on chartType.", + "additionalProperties": true + } + }, + "required": [ + "chartType", + "encodings" + ], + "allOf": [ + { + "if": { + "properties": { + "chartType": { + "const": "Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "shape", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 1 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Regression" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Regression" + }, + "chartProperties": { + "type": "object", + "properties": { + "regressionMethod": { + "description": "Method", + "enum": [ + "linear", + "log", + "exp", + "pow", + "quad", + "poly" + ], + "default": "linear" + }, + "polyOrder": { + "type": "number", + "description": "Poly Order", + "minimum": 2, + "maximum": 10, + "multipleOf": 1, + "default": 3 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Connected Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "order", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Connected Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Ranged Dot Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Ranged Dot Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Strip Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Strip Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "stepWidth": { + "type": "number", + "description": "Jitter", + "minimum": 10, + "maximum": 100, + "multipleOf": 5, + "default": 20 + }, + "pointSize": { + "type": "number", + "description": "Size", + "minimum": 0, + "maximum": 150, + "multipleOf": 5, + "default": 0 + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0, + "maximum": 1, + "multipleOf": 0.1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Grouped Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "group", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Grouped Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Stacked Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Stacked Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "center" + ] + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Lollipop Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Lollipop Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dotSize": { + "type": "number", + "description": "Dot Size", + "minimum": 20, + "maximum": 300, + "multipleOf": 10, + "default": 80 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Waterfall Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Waterfall Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 0 + }, + "totals": { + "description": "Totals", + "enum": [ + "auto", + "none", + "first", + "last", + "both" + ], + "default": "auto" + }, + "showTextLabels": { + "type": "boolean", + "description": "Labels", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gantt Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "x2", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gantt Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "taskHeight": { + "type": "number", + "description": "Task height", + "minimum": 40, + "maximum": 90, + "multipleOf": 5, + "default": 70 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 2 + }, + "intervalLabels": { + "type": "boolean", + "description": "Labels", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bullet Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "goal", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bullet Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Histogram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Histogram" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Max Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Density Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Density Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "bandwidth": { + "type": "number", + "description": "Bandwidth", + "minimum": 0.05, + "maximum": 2, + "multipleOf": 0.05, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "ECDF Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for ECDF Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Violin Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Violin Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "bandwidth": { + "type": "number", + "description": "Bandwidth", + "minimum": 0.05, + "maximum": 2, + "multipleOf": 0.05, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Boxplot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Boxplot" + }, + "chartProperties": { + "type": "object", + "properties": { + "whiskerMethod": { + "description": "Whiskers", + "enum": [ + "iqr", + "minmax" + ], + "default": "iqr" + }, + "showOutliers": { + "type": "boolean", + "description": "Outliers", + "default": true + }, + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pyramid Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pyramid Chart" + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Candlestick Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "open", + "high", + "low", + "close", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Candlestick Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Line Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "strokeDash", + "detail", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Line Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Sparkline" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "row", + "column" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Sparkline" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "baseline": { + "description": "Reference line", + "enum": [ + "mean", + "zero", + "median", + "none" + ], + "default": "mean" + }, + "trendWidth": { + "type": "number", + "description": "Sparkline width", + "minimum": 80, + "maximum": 600, + "multipleOf": 10, + "default": 240 + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bump Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bump Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Slope Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Slope Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 0.7 + }, + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "center", + "layered" + ] + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Streamgraph" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Streamgraph" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Range Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "y2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Range Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 0.5 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pie Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pie Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 0, + "maximum": 100, + "multipleOf": 5, + "default": 0 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Donut Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Donut Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 0, + "maximum": 100, + "multipleOf": 5, + "default": 0 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Rose Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Rose Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "padAngle": { + "type": "number", + "description": "Gap", + "minimum": 0, + "maximum": 0.1, + "multipleOf": 0.005, + "default": 0 + }, + "alignment": { + "description": "Alignment", + "enum": [ + "left", + "center" + ] + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Radar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Radar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "filled": { + "type": "boolean", + "description": "Filled", + "default": true + }, + "fillOpacity": { + "type": "number", + "description": "Fill Opacity", + "minimum": 0, + "maximum": 0.5, + "multipleOf": 0.1, + "default": 0.15 + }, + "strokeWidth": { + "type": "number", + "description": "Line Width", + "minimum": 0.5, + "maximum": 4, + "multipleOf": 0.5, + "default": 1.5 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Heatmap" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Heatmap" + }, + "chartProperties": { + "type": "object", + "properties": { + "showTextLabels": { + "type": "boolean", + "description": "Labels", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Table" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Table" + }, + "chartProperties": { + "type": "object", + "properties": { + "maxRows": { + "type": "number", + "description": "Max Rows", + "minimum": 5, + "maximum": 100, + "multipleOf": 1, + "default": 20 + }, + "showPercent": { + "type": "boolean", + "description": "% of total", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "KPI Card" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "metric", + "value", + "goal" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for KPI Card" + }, + "chartProperties": { + "type": "object", + "properties": { + "layout": { + "description": "Layout", + "enum": [ + "horizontal", + "vertical", + "grid" + ], + "default": "grid" + }, + "style": { + "type": "boolean", + "description": "Card style", + "default": true + }, + "behindThreshold": { + "type": "number", + "description": "Behind threshold", + "minimum": 0, + "maximum": 1, + "multipleOf": 0.05, + "default": 0.5 + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Map" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "longitude", + "latitude", + "color", + "size", + "opacity" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Map" + }, + "chartProperties": { + "type": "object", + "properties": { + "region": { + "description": "Region", + "enum": [ + "auto", + "us", + "world" + ], + "default": "auto" + }, + "projection": { + "description": "Projection", + "enum": [ + "default", + "mercator", + "equalEarth", + "orthographic", + "stereographic", + "conicEqualArea", + "conicEquidistant", + "azimuthalEquidistant", + "mollweide" + ], + "default": "default" + }, + "projectionCenter": { + "description": "Center", + "enum": [ + null, + [ + 0, + 0 + ], + [ + 150, + 0 + ], + [ + 105, + 35 + ], + [ + -98, + 39 + ], + [ + 10, + 50 + ], + [ + 138, + 36 + ], + [ + 78, + 22 + ], + [ + -52, + -14 + ], + [ + 134, + -25 + ], + [ + 100, + 60 + ], + [ + 20, + 0 + ], + [ + 45, + 28 + ], + [ + 115, + 5 + ], + [ + -60, + -15 + ], + [ + -100, + 45 + ], + [ + -2, + 54 + ], + [ + 10, + 51 + ], + [ + 2, + 47 + ], + [ + 128, + 36 + ] + ] + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Choropleth" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "id", + "color", + "detail" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Choropleth" + }, + "chartProperties": { + "type": "object", + "properties": { + "region": { + "description": "Region", + "enum": [ + "auto", + "us", + "world" + ], + "default": "auto" + } + }, + "additionalProperties": true + } + } + } + } + ] + }, + "options": { + "$ref": "#/$defs/AssembleOptions" + }, + "field_display_names": { + "type": "object", + "description": "Field name → display label (used as axis titles and legend headers)", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "data", + "chart_spec" + ], + "additionalProperties": false, + "$defs": { + "ChartEncoding": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field (column) name from the data" + }, + "type": { + "type": "string", + "enum": [ + "quantitative", + "nominal", + "ordinal", + "temporal" + ], + "description": "Encoding type override" + }, + "aggregate": { + "type": "string", + "enum": [ + "count", + "sum", + "average", + "mean" + ], + "description": "Aggregation function" + }, + "sortOrder": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "Sort order for this channel" + }, + "sortBy": { + "type": "string", + "description": "Field name to sort by" + }, + "scheme": { + "type": "string", + "description": "Color scheme name (color channel)" + } + }, + "additionalProperties": false + }, + "RawEncodingValue": { + "description": "A channel encoding: an object, a bare field-name string shorthand, or an array (static series).", + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string", + "description": "Shorthand for { field: }" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string" + } + ] + }, + "description": "Static series array (multiple fields on the same channel)" + } + ] + }, + "SemanticAnnotation": { + "type": "object", + "properties": { + "semanticType": { + "type": "string", + "description": "Semantic type string (e.g. \"Amount\", \"Country\", \"Year\")" + }, + "intrinsicDomain": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "description": "Intrinsic domain [min, max] for bounded/scaled types" + }, + "unit": { + "type": "string", + "description": "Unit or currency code (e.g. \"USD\", \"°C\", \"kg\")" + }, + "sortOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Explicit ordinal ordering" + } + }, + "required": [ + "semanticType" + ], + "additionalProperties": false + }, + "SemanticTypeValue": { + "description": "A semantic type: either a string name or a SemanticAnnotation object.", + "oneOf": [ + { + "type": "string", + "enum": [ + "DateTime", + "Date", + "Time", + "Timestamp", + "Year", + "Quarter", + "Month", + "Week", + "Day", + "Hour", + "YearMonth", + "YearQuarter", + "YearWeek", + "Decade", + "Duration", + "Amount", + "Price", + "Quantity", + "Temperature", + "Percentage", + "Profit", + "PercentageChange", + "Sentiment", + "Correlation", + "Count", + "Number", + "Rank", + "Score", + "ID", + "Latitude", + "Longitude", + "Country", + "State", + "City", + "Region", + "Address", + "ZipCode", + "Category", + "Name", + "Status", + "Boolean", + "Direction", + "Range", + "Unknown" + ], + "description": "Registered semantic type name" + }, + { + "type": "string", + "description": "Custom/unregistered semantic type name" + }, + { + "$ref": "#/$defs/SemanticAnnotation" + } + ] + }, + "Size": { + "type": "object", + "properties": { + "width": { + "type": "number", + "minimum": 1, + "description": "Width in pixels" + }, + "height": { + "type": "number", + "minimum": 1, + "description": "Height in pixels" + } + }, + "required": [ + "width", + "height" + ], + "additionalProperties": false + }, + "AssembleOptions": { + "type": "object", + "description": "Layout tuning parameters. All optional with sensible defaults.", + "properties": { + "addTooltips": { + "type": "boolean", + "description": "Add tooltips (default: false)", + "default": false + }, + "stepPadding": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Inter-category padding fraction (default: 0.1)", + "default": 0.1 + }, + "elasticity": { + "type": "number", + "description": "Power-law exponent for discrete axis stretch (default: 0.5)", + "default": 0.5 + }, + "maxStretch": { + "type": "number", + "minimum": 1, + "description": "Maximum stretch multiplier (default: 2)", + "default": 2 + }, + "maxStretchX": { + "type": "number", + "minimum": 1, + "description": "Per-dimension X stretch cap" + }, + "maxStretchY": { + "type": "number", + "minimum": 1, + "description": "Per-dimension Y stretch cap" + }, + "facetElasticity": { + "type": "number", + "description": "Facet subplot stretch exponent (default: 0.3)", + "default": 0.3 + }, + "minStep": { + "type": "number", + "minimum": 1, + "description": "Min px per discrete axis item (default: 6)", + "default": 6 + }, + "maxColorValues": { + "type": "integer", + "minimum": 1, + "description": "Max distinct color values before truncation (default: 24)", + "default": 24 + }, + "minSubplotSize": { + "type": "number", + "minimum": 1, + "description": "Min facet subplot size in px (default: 60)", + "default": 60 + }, + "facetFixedPadding": { + "$ref": "#/$defs/Size", + "description": "Fixed overhead in px for axis labels/titles/legend" + }, + "facetGap": { + "type": "number", + "minimum": 0, + "description": "Gap between facet panels in px" + }, + "facetColumns": { + "type": "integer", + "minimum": 1, + "description": "Explicit facet column count (overrides auto-wrap)" + }, + "defaultBandSize": { + "type": "number", + "minimum": 1, + "description": "Base px per discrete category at 300px baseline (default: 20)", + "default": 20 + }, + "maxBandSize": { + "type": "number", + "minimum": 1, + "description": "Max px per discrete category (sparse expansion ceiling)" + }, + "baseLabelFontSize": { + "type": "number", + "minimum": 1, + "description": "Base tick label font size (default: 10)", + "default": 10 + }, + "baseTitleFontSize": { + "type": "number", + "minimum": 1, + "description": "Base header/title font size (default: 11)", + "default": 11 + }, + "maintainContinuousAxisRatio": { + "type": "boolean", + "description": "Lock continuous axes aspect ratio (default: false)", + "default": false + }, + "continuousMarkCrossSection": { + "description": "Gas-pressure tuning for continuous axes", + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "elasticity": { + "type": "number" + }, + "maxStretch": { + "type": "number" + }, + "seriesCountAxis": { + "type": "string", + "enum": [ + "x", + "y", + "auto" + ] + } + }, + "required": [ + "x", + "y" + ] + } + ] + }, + "facetAspectRatioResistance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Resistance to AR distortion when faceting (0–1)" + }, + "autoFacetWrap": { + "type": "boolean", + "description": "Auto-wrap column-only facets (default: true)", + "default": true + }, + "targetBandAR": { + "type": "number", + "description": "Target aspect ratio for a single band (0 = no correction)" + } + }, + "additionalProperties": false + } + } +} diff --git a/docs/schema/flint-input.schema.json b/docs/schema/flint-input.schema.json new file mode 100644 index 0000000..fbdfa40 --- /dev/null +++ b/docs/schema/flint-input.schema.json @@ -0,0 +1,1692 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/microsoft/flint-chart/docs/schema/flint-input", + "title": "flint-input", + "description": "Flint ChartAssemblyInput — universal schema (chart types supported by all backends: Vega-Lite, ECharts, Chart.js, Plotly).", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference URI (allows standalone .json files to declare their schema)." + }, + "data": { + "description": "Data source — provide inline rows via `values`, or a local file path via `url`.", + "oneOf": [ + { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Inline data rows (array of row objects)" + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Local file path to JSON/CSV/TSV data" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + } + ] + }, + "semantic_types": { + "type": "object", + "description": "Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).", + "additionalProperties": { + "$ref": "#/$defs/SemanticTypeValue" + } + }, + "chart_spec": { + "type": "object", + "description": "Chart specification — describes what to draw.", + "properties": { + "chartType": { + "type": "string", + "enum": [ + "Area Chart", + "Bar Chart", + "Bump Chart", + "Connected Scatter Plot", + "ECDF Plot", + "Gantt Chart", + "Grouped Bar Chart", + "Histogram", + "Line Chart", + "Pie Chart", + "Radar Chart", + "Range Area Chart", + "Rose Chart", + "Scatter Plot", + "Slope Chart", + "Stacked Bar Chart", + "Strip Plot", + "Waterfall Chart" + ], + "description": "Chart template name" + }, + "encodings": { + "type": "object", + "description": "Channel → encoding map. Valid channels depend on chartType.", + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + } + }, + "baseSize": { + "$ref": "#/$defs/Size", + "description": "Base (target) chart size in pixels (default: 400×320)" + }, + "canvasSize": { + "$ref": "#/$defs/Size", + "description": "Hard ceiling on rendered size in pixels (optional)" + }, + "chartProperties": { + "type": "object", + "description": "Template-specific configurable properties. Valid properties depend on chartType.", + "additionalProperties": true + } + }, + "required": [ + "chartType", + "encodings" + ], + "allOf": [ + { + "if": { + "properties": { + "chartType": { + "const": "Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "shape", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 1 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Connected Scatter Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "order", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Connected Scatter Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Strip Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "size", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Strip Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "stepWidth": { + "type": "number", + "description": "Jitter", + "minimum": 10, + "maximum": 100, + "multipleOf": 5, + "default": 20 + }, + "pointSize": { + "type": "number", + "description": "Size", + "minimum": 0, + "maximum": 150, + "multipleOf": 5, + "default": 0 + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0, + "maximum": 1, + "multipleOf": 0.1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 15, + "multipleOf": 1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Grouped Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "group", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Grouped Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "dodge": { + "description": "Dodge", + "enum": [ + "auto", + "local", + "global" + ], + "default": "auto" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Stacked Bar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Stacked Bar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "center" + ] + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Waterfall Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Waterfall Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 0 + }, + "totals": { + "description": "Totals", + "enum": [ + "auto", + "none", + "first", + "last", + "both" + ], + "default": "auto" + }, + "showTextLabels": { + "type": "boolean", + "description": "Labels", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Gantt Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "y", + "x", + "x2", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Gantt Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "taskHeight": { + "type": "number", + "description": "Task height", + "minimum": 40, + "maximum": 90, + "multipleOf": 5, + "default": 70 + }, + "cornerRadius": { + "type": "number", + "description": "Corners", + "minimum": 0, + "maximum": 8, + "multipleOf": 1, + "default": 2 + }, + "intervalLabels": { + "type": "boolean", + "description": "Labels", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Histogram" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Histogram" + }, + "chartProperties": { + "type": "object", + "properties": { + "binCount": { + "type": "number", + "description": "Max Bins", + "minimum": 5, + "maximum": 50, + "multipleOf": 1, + "default": 0 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "ECDF Plot" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for ECDF Plot" + }, + "chartProperties": { + "type": "object", + "properties": { + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Line Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "strokeDash", + "detail", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Line Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "showPoints": { + "type": "boolean", + "description": "Points", + "default": false + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Bump Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Bump Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Slope Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "detail", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Slope Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "opacity", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis", + "cardinal", + "catmull-rom" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 0.7 + }, + "stackMode": { + "description": "Stack", + "enum": [ + null, + "normalize", + "center", + "layered" + ] + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "xAxisType": { + "description": "X as", + "enum": [ + "temporal", + "nominal" + ] + }, + "yAxisType": { + "description": "Y as", + "enum": [ + "temporal", + "nominal" + ] + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Range Area Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "y2", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Range Area Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "interpolate": { + "description": "Curve", + "enum": [ + null, + "linear", + "monotone", + "step", + "step-before", + "step-after", + "basis" + ] + }, + "opacity": { + "type": "number", + "description": "Opacity", + "minimum": 0.1, + "maximum": 1, + "multipleOf": 0.1, + "default": 0.5 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Pie Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "size", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Pie Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "innerRadius": { + "type": "number", + "description": "Donut", + "minimum": 0, + "maximum": 100, + "multipleOf": 5, + "default": 0 + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Rose Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Rose Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "padAngle": { + "type": "number", + "description": "Gap", + "minimum": 0, + "maximum": 0.1, + "multipleOf": 0.005, + "default": 0 + }, + "alignment": { + "description": "Alignment", + "enum": [ + "left", + "center" + ] + }, + "sortSlices": { + "description": "Sort slices", + "enum": [ + "none", + "descending", + "ascending" + ], + "default": "none" + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + } + }, + "additionalProperties": true + } + } + } + }, + { + "if": { + "properties": { + "chartType": { + "const": "Radar Chart" + } + }, + "required": [ + "chartType" + ] + }, + "then": { + "properties": { + "encodings": { + "type": "object", + "propertyNames": { + "enum": [ + "x", + "y", + "color", + "column", + "row" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/RawEncodingValue" + }, + "description": "Valid channels for Radar Chart" + }, + "chartProperties": { + "type": "object", + "properties": { + "filled": { + "type": "boolean", + "description": "Filled", + "default": true + }, + "fillOpacity": { + "type": "number", + "description": "Fill Opacity", + "minimum": 0, + "maximum": 0.5, + "multipleOf": 0.1, + "default": 0.15 + }, + "strokeWidth": { + "type": "number", + "description": "Line Width", + "minimum": 0.5, + "maximum": 4, + "multipleOf": 0.5, + "default": 1.5 + }, + "independentYAxis": { + "type": "boolean", + "description": "Independent Y" + }, + "logScale_x": { + "type": "boolean", + "description": "Log X", + "default": false + }, + "logScale_y": { + "type": "boolean", + "description": "Log Y", + "default": false + }, + "includeZero_x": { + "type": "boolean", + "description": "Zero X" + }, + "includeZero_y": { + "type": "boolean", + "description": "Zero Y" + } + }, + "additionalProperties": true + } + } + } + } + ] + }, + "options": { + "$ref": "#/$defs/AssembleOptions" + }, + "field_display_names": { + "type": "object", + "description": "Field name → display label (used as axis titles and legend headers)", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "data", + "chart_spec" + ], + "additionalProperties": false, + "$defs": { + "ChartEncoding": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field (column) name from the data" + }, + "type": { + "type": "string", + "enum": [ + "quantitative", + "nominal", + "ordinal", + "temporal" + ], + "description": "Encoding type override" + }, + "aggregate": { + "type": "string", + "enum": [ + "count", + "sum", + "average", + "mean" + ], + "description": "Aggregation function" + }, + "sortOrder": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "Sort order for this channel" + }, + "sortBy": { + "type": "string", + "description": "Field name to sort by" + }, + "scheme": { + "type": "string", + "description": "Color scheme name (color channel)" + } + }, + "additionalProperties": false + }, + "RawEncodingValue": { + "description": "A channel encoding: an object, a bare field-name string shorthand, or an array (static series).", + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string", + "description": "Shorthand for { field: }" + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/$defs/ChartEncoding" + }, + { + "type": "string" + } + ] + }, + "description": "Static series array (multiple fields on the same channel)" + } + ] + }, + "SemanticAnnotation": { + "type": "object", + "properties": { + "semanticType": { + "type": "string", + "description": "Semantic type string (e.g. \"Amount\", \"Country\", \"Year\")" + }, + "intrinsicDomain": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "description": "Intrinsic domain [min, max] for bounded/scaled types" + }, + "unit": { + "type": "string", + "description": "Unit or currency code (e.g. \"USD\", \"°C\", \"kg\")" + }, + "sortOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Explicit ordinal ordering" + } + }, + "required": [ + "semanticType" + ], + "additionalProperties": false + }, + "SemanticTypeValue": { + "description": "A semantic type: either a string name or a SemanticAnnotation object.", + "oneOf": [ + { + "type": "string", + "enum": [ + "DateTime", + "Date", + "Time", + "Timestamp", + "Year", + "Quarter", + "Month", + "Week", + "Day", + "Hour", + "YearMonth", + "YearQuarter", + "YearWeek", + "Decade", + "Duration", + "Amount", + "Price", + "Quantity", + "Temperature", + "Percentage", + "Profit", + "PercentageChange", + "Sentiment", + "Correlation", + "Count", + "Number", + "Rank", + "Score", + "ID", + "Latitude", + "Longitude", + "Country", + "State", + "City", + "Region", + "Address", + "ZipCode", + "Category", + "Name", + "Status", + "Boolean", + "Direction", + "Range", + "Unknown" + ], + "description": "Registered semantic type name" + }, + { + "type": "string", + "description": "Custom/unregistered semantic type name" + }, + { + "$ref": "#/$defs/SemanticAnnotation" + } + ] + }, + "Size": { + "type": "object", + "properties": { + "width": { + "type": "number", + "minimum": 1, + "description": "Width in pixels" + }, + "height": { + "type": "number", + "minimum": 1, + "description": "Height in pixels" + } + }, + "required": [ + "width", + "height" + ], + "additionalProperties": false + }, + "AssembleOptions": { + "type": "object", + "description": "Layout tuning parameters. All optional with sensible defaults.", + "properties": { + "addTooltips": { + "type": "boolean", + "description": "Add tooltips (default: false)", + "default": false + }, + "stepPadding": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Inter-category padding fraction (default: 0.1)", + "default": 0.1 + }, + "elasticity": { + "type": "number", + "description": "Power-law exponent for discrete axis stretch (default: 0.5)", + "default": 0.5 + }, + "maxStretch": { + "type": "number", + "minimum": 1, + "description": "Maximum stretch multiplier (default: 2)", + "default": 2 + }, + "maxStretchX": { + "type": "number", + "minimum": 1, + "description": "Per-dimension X stretch cap" + }, + "maxStretchY": { + "type": "number", + "minimum": 1, + "description": "Per-dimension Y stretch cap" + }, + "facetElasticity": { + "type": "number", + "description": "Facet subplot stretch exponent (default: 0.3)", + "default": 0.3 + }, + "minStep": { + "type": "number", + "minimum": 1, + "description": "Min px per discrete axis item (default: 6)", + "default": 6 + }, + "maxColorValues": { + "type": "integer", + "minimum": 1, + "description": "Max distinct color values before truncation (default: 24)", + "default": 24 + }, + "minSubplotSize": { + "type": "number", + "minimum": 1, + "description": "Min facet subplot size in px (default: 60)", + "default": 60 + }, + "facetFixedPadding": { + "$ref": "#/$defs/Size", + "description": "Fixed overhead in px for axis labels/titles/legend" + }, + "facetGap": { + "type": "number", + "minimum": 0, + "description": "Gap between facet panels in px" + }, + "facetColumns": { + "type": "integer", + "minimum": 1, + "description": "Explicit facet column count (overrides auto-wrap)" + }, + "defaultBandSize": { + "type": "number", + "minimum": 1, + "description": "Base px per discrete category at 300px baseline (default: 20)", + "default": 20 + }, + "maxBandSize": { + "type": "number", + "minimum": 1, + "description": "Max px per discrete category (sparse expansion ceiling)" + }, + "baseLabelFontSize": { + "type": "number", + "minimum": 1, + "description": "Base tick label font size (default: 10)", + "default": 10 + }, + "baseTitleFontSize": { + "type": "number", + "minimum": 1, + "description": "Base header/title font size (default: 11)", + "default": 11 + }, + "maintainContinuousAxisRatio": { + "type": "boolean", + "description": "Lock continuous axes aspect ratio (default: false)", + "default": false + }, + "continuousMarkCrossSection": { + "description": "Gas-pressure tuning for continuous axes", + "oneOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "elasticity": { + "type": "number" + }, + "maxStretch": { + "type": "number" + }, + "seriesCountAxis": { + "type": "string", + "enum": [ + "x", + "y", + "auto" + ] + } + }, + "required": [ + "x", + "y" + ] + } + ] + }, + "facetAspectRatioResistance": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Resistance to AR distortion when faceting (0–1)" + }, + "autoFacetWrap": { + "type": "boolean", + "description": "Auto-wrap column-only facets (default: true)", + "default": true + }, + "targetBandAR": { + "type": "number", + "description": "Target aspect ratio for a single band (0 = no correction)" + } + }, + "additionalProperties": false + } + } +} diff --git a/package-lock.json b/package-lock.json index 0553d4e..70007ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,9 @@ "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "zod": "^4.4.3", + "zod-to-json-schema": "^3.25.2" }, "engines": { "node": ">=18" @@ -130,6 +132,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/view/-/view-6.43.6.tgz", "integrity": "sha1-geTusoVefLbGIwX7qN8xm1R2KAw=", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.7.0", "crelt": "^1.0.6", @@ -1071,6 +1074,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", "integrity": "sha1-eXhti1JeJp3oUKyCsfH3V/ORX0Q=", "license": "MIT", + "peer": true, "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", @@ -2225,6 +2229,7 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.27" @@ -2627,6 +2632,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react/-/react-18.3.31.tgz", "integrity": "sha1-teleKP/M6rjZgvM/LrB24XZTwqQ=", "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -2664,6 +2670,7 @@ "integrity": "sha1-caDD1fil5sXf208PBL0b+1ctXiQ=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.64.0", @@ -2693,6 +2700,7 @@ "integrity": "sha1-yYZKHMKKE/8ppzFPve8FKLsSL3I=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.64.0", "@typescript-eslint/types": "8.64.0", @@ -3108,6 +3116,7 @@ "integrity": "sha1-F4WtuE+vjYrdEDabk4Jvwr0I8f4=", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4120,6 +4129,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -4188,6 +4198,7 @@ "integrity": "sha1-Kk48iw91MZbvrpQ8j/qocw/Go/o=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4521,6 +4532,7 @@ "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/express/-/express-5.2.1.tgz", "integrity": "sha1-jyHRW20yf5K0eU7PjLCKcvlWrAQ=", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -5151,6 +5163,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hono/-/hono-4.12.30.tgz", "integrity": "sha1-TVewUcZmF7ADt7oxiRDLW3nEx6w=", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -5213,6 +5226,7 @@ } ], "license": "MIT", + "peer": true, "peerDependencies": { "typescript": "^5 || ^6 || ^7" }, @@ -5588,7 +5602,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5610,7 +5623,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5632,7 +5644,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5654,7 +5665,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5676,7 +5686,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5698,7 +5707,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5720,7 +5728,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5742,7 +5749,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5764,7 +5770,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5786,7 +5791,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5808,7 +5812,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -7299,6 +7302,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", @@ -7468,6 +7472,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react/-/react-18.3.1.tgz", "integrity": "sha1-SauJIAnFOTNiW9FrJTP8dUyrKJE=", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -7480,6 +7485,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha1-wiZdeVEbV9R5s90/36UVNklMXLQ=", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7845,6 +7851,7 @@ "integrity": "sha1-2Q/Ey4EfBxMDyJC3eVlWNPNflUE=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.9" }, @@ -8537,6 +8544,7 @@ "integrity": "sha1-W09Z4VMQqxeiFvXWz1PuR27eZw8=", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8740,6 +8748,7 @@ "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega/-/vega-6.2.0.tgz", "integrity": "sha1-NMLeg7AOcB4EAClziybx7JkvMn8=", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "vega-crossfilter": "~5.1.0", "vega-dataflow": "~6.1.0", @@ -8955,6 +8964,7 @@ "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-lite/-/vega-lite-6.4.3.tgz", "integrity": "sha1-mXPTr+E5H7CIB7wlheEp4tr3o2s=", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "json-stringify-pretty-compact": "~4.0.0", "tslib": "~2.8.1", @@ -9263,6 +9273,7 @@ "integrity": "sha1-zP/OPuSHsYhiI7JOuye5FnSCfTA=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", @@ -9596,10 +9607,11 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zod/-/zod-3.25.76.tgz", - "integrity": "sha1-JoQcP2/SKmonYOfMtxkXl2hHHjQ=", + "version": "4.4.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zod/-/zod-4.4.3.tgz", + "integrity": "sha1-toDxcohdGLvr8hqDTqJeVaG781Y=", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -9721,6 +9733,7 @@ "integrity": "sha1-3MrDZbqg8XNOwnD/S1HIlGXo3H8=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -9741,6 +9754,7 @@ "integrity": "sha1-H0ehv8BvjsiFdSxvSvFDaan4Jgs=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -9765,6 +9779,15 @@ "dev": true, "license": "MIT" }, + "packages/flint-mcp/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zod/-/zod-3.25.76.tgz", + "integrity": "sha1-JoQcP2/SKmonYOfMtxkXl2hHHjQ=", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "site": { "name": "flint-chart-site", "version": "0.0.0", @@ -9827,6 +9850,7 @@ "integrity": "sha1-kMLQt7lKIk5+fc8i0pEv8LUpEWU=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", diff --git a/package.json b/package.json index 531653b..62803e0 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "site": "npm run dev -w site", "site:build": "npm run build -w site", "gen:reference": "esbuild scripts/gen-chart-reference.ts --bundle --platform=node --format=esm --outfile=scripts/.gen-chart-reference.mjs && node scripts/.gen-chart-reference.mjs && rm -f scripts/.gen-chart-reference.mjs", + "gen:schema": "esbuild scripts/gen-json-schema.ts --bundle --platform=node --format=esm --outfile=scripts/.gen-json-schema.mjs && node scripts/.gen-json-schema.mjs && node -e \"require('fs').rmSync('scripts/.gen-json-schema.mjs',{force:true})\"", "presite": "npm run gen:reference", "presite:build": "npm run gen:reference", "postinstall": "node scripts/link-site-react.mjs" @@ -37,7 +38,9 @@ "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "zod": "^4.4.3", + "zod-to-json-schema": "^3.25.2" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "^4.0.0", @@ -48,4 +51,4 @@ "js-yaml": "^4.2.0", "@hono/node-server": "^2.0.5" } -} \ No newline at end of file +} diff --git a/scripts/gen-json-schema.ts b/scripts/gen-json-schema.ts new file mode 100644 index 0000000..bb87330 --- /dev/null +++ b/scripts/gen-json-schema.ts @@ -0,0 +1,448 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Generates JSON Schema files describing the permitted Flint ChartAssemblyInput. + * + * Produces: + * docs/schema/flint-input.schema.json — universal (chart types common to ALL backends) + * docs/schema/flint-input-vegalite.schema.json — Vega-Lite backend + * docs/schema/flint-input-echarts.schema.json — ECharts backend + * docs/schema/flint-input-chartjs.schema.json — Chart.js backend + * docs/schema/flint-input-plotly.schema.json — Plotly backend + * + * Run via: npm run gen:schema (bundled with esbuild, see root package.json) + */ + +import { writeFileSync, mkdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, resolve } from 'node:path'; + +import type { ChartTemplateDef, ChartPropertyDef } from '../packages/flint-js/src/core/types'; +import { vlTemplateDefs } from '../packages/flint-js/src/vegalite/templates/index'; +import { ecTemplateDefs } from '../packages/flint-js/src/echarts/templates/index'; +import { cjsTemplateDefs } from '../packages/flint-js/src/chartjs/templates/index'; +import { plTemplateDefs } from '../packages/flint-js/src/plotly/templates/index'; +import { getRegisteredTypes } from '../packages/flint-js/src/core/type-registry'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const SCHEMA_DIR = resolve(__dirname, '../docs/schema'); + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +type CategorizedDefs = { [category: string]: ChartTemplateDef[] }; + +function flattenDefs(defs: CategorizedDefs): ChartTemplateDef[] { + return Object.values(defs).flat(); +} + +function getChartNames(defs: CategorizedDefs): string[] { + return flattenDefs(defs).map(d => d.chart).sort(); +} + +/** + * Build a JSON Schema for `chartProperties` from a template's property defs. + * Returns undefined if no properties are defined. + */ +function buildChartPropertiesSchema(properties: ChartPropertyDef[] | undefined): object | undefined { + if (!properties || properties.length === 0) return undefined; + + const props: Record = {}; + for (const p of properties) { + switch (p.type) { + case 'binary': + props[p.key] = { + type: 'boolean', + description: p.label, + ...(p.defaultValue !== undefined ? { default: p.defaultValue } : {}), + }; + break; + case 'continuous': + props[p.key] = { + type: 'number', + description: p.label, + minimum: p.min, + maximum: p.max, + ...(p.step !== undefined ? { multipleOf: p.step } : {}), + ...(p.defaultValue !== undefined ? { default: p.defaultValue } : {}), + }; + break; + case 'discrete': + props[p.key] = { + description: p.label, + enum: p.options.map(o => o.value), + ...(p.defaultValue !== undefined ? { default: p.defaultValue } : {}), + }; + break; + } + } + + return { + type: 'object', + properties: props, + additionalProperties: true, + }; +} + +/** + * Build per-chart-type conditional schema blocks (allOf with if/then). + */ +function buildChartTypeConditions(defs: ChartTemplateDef[]): object[] { + return defs.map(def => { + const thenSchema: any = { + properties: { + encodings: { + type: 'object', + propertyNames: { + enum: def.channels, + }, + additionalProperties: { $ref: '#/$defs/RawEncodingValue' }, + description: `Valid channels for ${def.chart}`, + }, + }, + }; + + const propsSchema = buildChartPropertiesSchema(def.properties); + if (propsSchema) { + thenSchema.properties.chartProperties = propsSchema; + } + + return { + if: { + properties: { chartType: { const: def.chart } }, + required: ['chartType'], + }, + then: thenSchema, + }; + }); +} + +// --------------------------------------------------------------------------- +// Schema Construction +// --------------------------------------------------------------------------- + +/** All registered semantic type strings */ +const SEMANTIC_TYPES = getRegisteredTypes(); + +/** Base definitions shared by all schemas */ +function buildDefs(): Record { + return { + ChartEncoding: { + type: 'object', + properties: { + field: { type: 'string', description: 'Field (column) name from the data' }, + type: { + type: 'string', + enum: ['quantitative', 'nominal', 'ordinal', 'temporal'], + description: 'Encoding type override', + }, + aggregate: { + type: 'string', + enum: ['count', 'sum', 'average', 'mean'], + description: 'Aggregation function', + }, + sortOrder: { + type: 'string', + enum: ['ascending', 'descending'], + description: 'Sort order for this channel', + }, + sortBy: { type: 'string', description: 'Field name to sort by' }, + scheme: { type: 'string', description: 'Color scheme name (color channel)' }, + }, + additionalProperties: false, + }, + RawEncodingValue: { + description: 'A channel encoding: an object, a bare field-name string shorthand, or an array (static series).', + oneOf: [ + { $ref: '#/$defs/ChartEncoding' }, + { type: 'string', description: 'Shorthand for { field: }' }, + { + type: 'array', + items: { + oneOf: [ + { $ref: '#/$defs/ChartEncoding' }, + { type: 'string' }, + ], + }, + description: 'Static series array (multiple fields on the same channel)', + }, + ], + }, + SemanticAnnotation: { + type: 'object', + properties: { + semanticType: { + type: 'string', + description: 'Semantic type string (e.g. "Amount", "Country", "Year")', + }, + intrinsicDomain: { + type: 'array', + items: { type: 'number' }, + minItems: 2, + maxItems: 2, + description: 'Intrinsic domain [min, max] for bounded/scaled types', + }, + unit: { type: 'string', description: 'Unit or currency code (e.g. "USD", "°C", "kg")' }, + sortOrder: { + type: 'array', + items: { type: 'string' }, + description: 'Explicit ordinal ordering', + }, + }, + required: ['semanticType'], + additionalProperties: false, + }, + SemanticTypeValue: { + description: 'A semantic type: either a string name or a SemanticAnnotation object.', + oneOf: [ + { + type: 'string', + enum: SEMANTIC_TYPES, + description: 'Registered semantic type name', + }, + { type: 'string', description: 'Custom/unregistered semantic type name' }, + { $ref: '#/$defs/SemanticAnnotation' }, + ], + }, + Size: { + type: 'object', + properties: { + width: { type: 'number', minimum: 1, description: 'Width in pixels' }, + height: { type: 'number', minimum: 1, description: 'Height in pixels' }, + }, + required: ['width', 'height'], + additionalProperties: false, + }, + AssembleOptions: { + type: 'object', + description: 'Layout tuning parameters. All optional with sensible defaults.', + properties: { + addTooltips: { type: 'boolean', description: 'Add tooltips (default: false)', default: false }, + stepPadding: { type: 'number', minimum: 0, maximum: 1, description: 'Inter-category padding fraction (default: 0.1)', default: 0.1 }, + elasticity: { type: 'number', description: 'Power-law exponent for discrete axis stretch (default: 0.5)', default: 0.5 }, + maxStretch: { type: 'number', minimum: 1, description: 'Maximum stretch multiplier (default: 2)', default: 2 }, + maxStretchX: { type: 'number', minimum: 1, description: 'Per-dimension X stretch cap' }, + maxStretchY: { type: 'number', minimum: 1, description: 'Per-dimension Y stretch cap' }, + facetElasticity: { type: 'number', description: 'Facet subplot stretch exponent (default: 0.3)', default: 0.3 }, + minStep: { type: 'number', minimum: 1, description: 'Min px per discrete axis item (default: 6)', default: 6 }, + maxColorValues: { type: 'integer', minimum: 1, description: 'Max distinct color values before truncation (default: 24)', default: 24 }, + minSubplotSize: { type: 'number', minimum: 1, description: 'Min facet subplot size in px (default: 60)', default: 60 }, + facetFixedPadding: { $ref: '#/$defs/Size', description: 'Fixed overhead in px for axis labels/titles/legend' }, + facetGap: { type: 'number', minimum: 0, description: 'Gap between facet panels in px' }, + facetColumns: { type: 'integer', minimum: 1, description: 'Explicit facet column count (overrides auto-wrap)' }, + defaultBandSize: { type: 'number', minimum: 1, description: 'Base px per discrete category at 300px baseline (default: 20)', default: 20 }, + maxBandSize: { type: 'number', minimum: 1, description: 'Max px per discrete category (sparse expansion ceiling)' }, + baseLabelFontSize: { type: 'number', minimum: 1, description: 'Base tick label font size (default: 10)', default: 10 }, + baseTitleFontSize: { type: 'number', minimum: 1, description: 'Base header/title font size (default: 11)', default: 11 }, + maintainContinuousAxisRatio: { type: 'boolean', description: 'Lock continuous axes aspect ratio (default: false)', default: false }, + continuousMarkCrossSection: { + description: 'Gas-pressure tuning for continuous axes', + oneOf: [ + { type: 'number' }, + { + type: 'object', + properties: { + x: { type: 'number' }, + y: { type: 'number' }, + elasticity: { type: 'number' }, + maxStretch: { type: 'number' }, + seriesCountAxis: { type: 'string', enum: ['x', 'y', 'auto'] }, + }, + required: ['x', 'y'], + }, + ], + }, + facetAspectRatioResistance: { type: 'number', minimum: 0, maximum: 1, description: 'Resistance to AR distortion when faceting (0–1)' }, + autoFacetWrap: { type: 'boolean', description: 'Auto-wrap column-only facets (default: true)', default: true }, + targetBandAR: { type: 'number', description: 'Target aspect ratio for a single band (0 = no correction)' }, + }, + additionalProperties: false, + }, + }; +} + +/** + * Build the full schema for a given set of chart type names and template definitions. + */ +function buildSchema( + title: string, + description: string, + chartTypeNames: string[], + allDefs: ChartTemplateDef[], +): object { + // Only include templates that are in the chartTypeNames list + const relevantDefs = allDefs.filter(d => chartTypeNames.includes(d.chart)); + const conditions = buildChartTypeConditions(relevantDefs); + + return { + $schema: 'https://json-schema.org/draft/2020-12/schema', + $id: `https://github.com/microsoft/flint-chart/docs/schema/${title}`, + title, + description, + type: 'object', + properties: { + $schema: { + type: 'string', + description: 'JSON Schema reference URI (confers no versioning guarantee; not currently used to validate input)', + }, + data: { + description: 'Data source — provide inline rows via `values`, or a local file path via `url`.', + oneOf: [ + { + type: 'object', + properties: { + values: { + type: 'array', + items: { type: 'object' }, + description: 'Inline data rows (array of row objects)', + }, + }, + required: ['values'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + url: { + type: 'string', + description: 'Local file path to JSON/CSV/TSV data', + }, + }, + required: ['url'], + additionalProperties: false, + }, + ], + }, + semantic_types: { + type: 'object', + description: 'Per-column semantic type annotations (field name → semantic type string or SemanticAnnotation object).', + additionalProperties: { $ref: '#/$defs/SemanticTypeValue' }, + }, + chart_spec: { + type: 'object', + description: 'Chart specification — describes what to draw.', + properties: { + chartType: { + type: 'string', + enum: chartTypeNames, + description: 'Chart template name', + }, + encodings: { + type: 'object', + description: 'Channel → encoding map. Valid channels depend on chartType.', + additionalProperties: { $ref: '#/$defs/RawEncodingValue' }, + }, + baseSize: { + $ref: '#/$defs/Size', + description: 'Base (target) chart size in pixels (default: 400×320)', + }, + canvasSize: { + $ref: '#/$defs/Size', + description: 'Hard ceiling on rendered size in pixels (optional)', + }, + chartProperties: { + type: 'object', + description: 'Template-specific configurable properties. Valid properties depend on chartType.', + additionalProperties: true, + }, + }, + required: ['chartType', 'encodings'], + // Per-chart-type conditional refinements + allOf: conditions, + }, + options: { $ref: '#/$defs/AssembleOptions' }, + field_display_names: { + type: 'object', + description: 'Field name → display label (used as axis titles and legend headers)', + additionalProperties: { type: 'string' }, + }, + }, + required: ['data', 'chart_spec'], + additionalProperties: false, + $defs: buildDefs(), + }; +} + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +// Collect chart type names per backend +const vlNames = getChartNames(vlTemplateDefs); +const ecNames = getChartNames(ecTemplateDefs); +const cjsNames = getChartNames(cjsTemplateDefs); +const plNames = getChartNames(plTemplateDefs); + +// Universal = intersection of all four backends +const universalNames = vlNames.filter( + name => ecNames.includes(name) && cjsNames.includes(name) && plNames.includes(name), +); + +// All flat template arrays +const vlAll = flattenDefs(vlTemplateDefs); +const ecAll = flattenDefs(ecTemplateDefs); +const cjsAll = flattenDefs(cjsTemplateDefs); +const plAll = flattenDefs(plTemplateDefs); + +// For universal schema, use VL definitions as canonical (they have the broadest property coverage) +const universalDefs = vlAll.filter(d => universalNames.includes(d.chart)); + +interface SchemaSpec { + title: string; + file: string; + description: string; + chartNames: string[]; + defs: ChartTemplateDef[]; +} + +const schemas: SchemaSpec[] = [ + { + title: 'flint-input', + file: 'flint-input.schema.json', + description: 'Flint ChartAssemblyInput — universal schema (chart types supported by all backends: Vega-Lite, ECharts, Chart.js, Plotly).', + chartNames: universalNames, + defs: universalDefs, + }, + { + title: 'flint-input-vegalite', + file: 'flint-input-vegalite.schema.json', + description: 'Flint ChartAssemblyInput — Vega-Lite backend (all chart types).', + chartNames: vlNames, + defs: vlAll, + }, + { + title: 'flint-input-echarts', + file: 'flint-input-echarts.schema.json', + description: 'Flint ChartAssemblyInput — ECharts backend (all chart types).', + chartNames: ecNames, + defs: ecAll, + }, + { + title: 'flint-input-chartjs', + file: 'flint-input-chartjs.schema.json', + description: 'Flint ChartAssemblyInput — Chart.js backend (all chart types).', + chartNames: cjsNames, + defs: cjsAll, + }, + { + title: 'flint-input-plotly', + file: 'flint-input-plotly.schema.json', + description: 'Flint ChartAssemblyInput — Plotly backend (all chart types).', + chartNames: plNames, + defs: plAll, + }, +]; + +// Ensure output directory exists +mkdirSync(SCHEMA_DIR, { recursive: true }); + +for (const spec of schemas) { + const schema = buildSchema(spec.title, spec.description, spec.chartNames, spec.defs); + const outPath = resolve(SCHEMA_DIR, spec.file); + writeFileSync(outPath, JSON.stringify(schema, null, 2) + '\n', 'utf-8'); + console.log(`✓ ${spec.file} (${spec.chartNames.length} chart types)`); +} + +console.log(`\nDone — ${schemas.length} schema files written to docs/schema/`);