aminghadersohi commented on code in PR #43770:
URL: https://github.com/apache/superset/pull/43770#discussion_r4194170734
##########
superset/mcp_service/chart/query_result.py:
##########
@@ -286,7 +2244,8 @@ def normalize_chart_query_result(result: Any, form_data:
Mapping[str, Any]) -> A
def normalize_treemap_query_result(result: Any, form_data: Mapping[str, Any])
-> Any:
"""Require unique hierarchy outputs and finite numeric Treemap metrics."""
- if failure := query_result_failure(result):
+ _data, failure = query_result_data(result, preserve_nonfinite_floats=True)
Review Comment:
Fixed in 10d39d282631e2a307996fc25609b2b75f403368. Treemap validation
inspects detached normalized rows without rewriting the source envelope,
leaving CSV/Excel normalization format-aware. Regression tests cover saved,
saved-cache, and unsaved-cache exports: CSV keeps the datetime space separator
and Excel retains native date cells. Nested-container copy and validation-bound
tests also pass.
##########
superset/mcp_service/chart/preview_utils.py:
##########
@@ -1398,6 +2445,92 @@ def fallback_vega_lite_preview(
return None
+def generate_xy_pivot_vega_lite_preview(
+ data: list[dict[str, Any]], form_data: dict[str, Any], *, mark: str
+) -> VegaLitePreview | None:
+ """Render flattened timeseries pivot columns without dropping grouped
series.
+
+ Folding exact output keys avoids splitting category values that contain
+ escaped commas. The legend retains each complete metric/category label.
+ Long-form results continue through the generic renderer.
+ """
+ from superset.mcp_service.chart.chart_helpers import _as_list
+ from superset.utils.pandas_postprocessing.utils import (
+ escape_separator,
+ FLAT_COLUMN_SEPARATOR,
+ )
+
+ if not data:
+ return None
+ dimensions = [
+ label
+ for column in _as_list(form_data.get("groupby"))
+ if (label := _form_column_label(column))
+ ]
+ if not dimensions or any(label in data[0] for label in dimensions):
+ return None
+ x_axis = _form_column_label(form_data.get("x_axis")) or "__timestamp"
+ if x_axis not in data[0]:
+ return None
+ metric_labels = [
+ escape_separator(label)
+ for metric in _as_list(form_data.get("metrics"))
+ if (label := metric_result_label(metric))
+ ]
+ fields = [
+ field
+ for field in data[0]
+ if field != x_axis
+ and any(
+ field.startswith(label + FLAT_COLUMN_SEPARATOR)
+ or field.startswith(label + "__")
+ for label in metric_labels
+ )
+ ]
+ if not fields:
+ return None
+ sample = data[0][x_axis]
+ x_type = (
+ "temporal"
+ if isinstance(sample, str) and any(char in sample for char in "-/: ")
+ else "quantitative"
+ if isinstance(sample, (int, float))
+ else "nominal"
+ )
+ return VegaLitePreview(
+ specification={
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
+ "data": {"values": data},
+ "transform": [
+ {"fold": fields, "as": ["__mcp_xy_series", "__mcp_xy_value"]}
Review Comment:
Fixed in 10d39d282631e2a307996fc25609b2b75f403368. Fold field paths escape
dots, brackets, and backslashes while the data keys stay literal. Regression
tests exercise dotted, bracketed, and backslash category labels through saved
and unsaved line/bar preview dispatch.
##########
docs/admin_docs/configuration/mcp-server.mdx:
##########
@@ -1349,6 +1362,118 @@ Disabling a plugin only stops new charts of that type
from being created. Existi
- **[Security](/developer-docs/extensions/security)** -- Security best
practices for extensions
- **[Deployment](/developer-docs/extensions/deployment)** -- Package and
deploy Superset extensions
+## Bullet chart compatibility
+
+The MCP Bullet plugin uses `chart_type: "bullet"` and the native ECharts
+`viz_type: "bullet"`. Its optional `dimensions` hierarchy maps to `groupby`.
+Omit `dimensions` (or use `null`) to create a single-metric Bullet without a
+breakdown. On updates, omission or `null` preserves the saved hierarchy; use
+`dimensions: []` to clear it explicitly. An `order_by` update can reference the
+saved dimensions without resending them; unknown targets are rejected after
+resolving the saved hierarchy. When replacing the dataset, saved-chart and
+cached-preview updates retain an omitted hierarchy only if its columns resolve
+in the replacement dataset; incompatible inherited roles and temporal-filter
+provenance are discarded.
+
+Inherited native SQL dimensions remain query expressions when updating metrics
+or `order_by`; reference their output labels to sort by them. Caller-supplied
+`dimensions` must still be physical columns, not SQL expressions.
+
+Dimension and metric output names are case-sensitive: quoted physical columns
+such as `Region` and `region` remain distinct. Reference lookup prefers exact
+names and uses case-insensitive matching only when there is a single candidate;
+ambiguous references require the exact spelling. Bullet metric strings use
+JavaScript numeric spellings: underscore separators and non-ASCII digits are
+rejected rather than interpreted as numbers. Bounded array-valued dimensions
+retain their raw values in data reads and exports; preview category labels use
+JavaScript string conversion (for example, `[1, 2]` displays as `1,2`). Native
+SQL metrics without a label use their SQL expression as the output label.
+
+Presentation-only updates preserve saved predicates, including legacy top-level
+`where`, `having`, and `filters`, and normalize the native `order_by_cols`
alias.
+When both `orderby` and `order_by_cols` are saved, their sort entries are
+concatenated in form-data key order, including when `orderby` is empty.
+Explicit `filters: []` and `order_by: []` clear those inherited controls.
+
+Range, marker, and marker-line label lists may be shorter than their value
lists.
+Labels that become empty after sanitization retain their slots so later labels
+remain aligned with their corresponding values.
+As in Explore, missing or empty range labels are not displayed, and missing or
+empty marker labels use the formatted numeric value. Extra labels have no value
+to annotate and are ignored. These rules also apply to saved-chart previews and
+updates. Omitted label controls preserve the saved state only when their
+corresponding value controls (`ranges`, `markers`, or `marker_lines`) are also
+omitted. Replacing a value control without its labels clears the saved labels;
+resend the labels to retain annotations with the replacement values.
+
+Saved native `ranges`, `markers`, and `marker_lines` controls ignore empty,
+non-numeric, and NaN tokens, matching Explore. If no numeric range remains, the
+preview uses the default band up to 110% of the largest measure. Unrelated
+updates preserve these saved controls. Newly authored typed lists must contain
+finite numbers; infinite native values and oversized controls remain errors.
+
+On same-dataset chart updates, `filters: []` clears both user filters and the
+generated dashboard-time binding. `temporal_column: null` clears only that
+generated binding, preserving user filters. Omitting those controls preserves
+the saved binding. Bullet Vega previews keep separate indexed rows even when
+dimension display labels are identical, and support both `SMART_NUMBER` and
+`SMART_NUMBER_SIGNED` number formats. Bullet preview numeric format
+precision is limited to 20 digits before formatting; raw data reads do not
+validate presentation formats.
+
+Native Bullet temporal filters retain the active filter's subject and range as
a
+pair; `No filter` placeholders do not supply the subject of another active
range.
+Typed configs support one such pair. Multiple active native temporal filters,
or
+conflicts with explicit `temporal_column`/`time_range`, are rejected rather
than
+silently dropping or moving a predicate.
+
+### Query result limits
+
+MCP chart tools accept up to 50,000 rows per query. The row-shaped `indexnames`
Review Comment:
Fixed in 10d39d282631e2a307996fc25609b2b75f403368. The MCP documentation and
UPDATING.md describe the 100,000-total-row and 2,500,000-value/container
budgets, how nested values, repeated occurrences, object keys, and indexnames
are counted, and why 50,000 rows with 50 scalar columns exceed the value budget.
##########
superset/mcp_service/chart/preview_utils.py:
##########
@@ -496,6 +1177,372 @@ def _is_nan(value: Any) -> bool:
return False
+def _bullet_numeric_tokens(value: Any) -> list[float]:
Review Comment:
Fixed in 10d39d282631e2a307996fc25609b2b75f403368. Removed
_bullet_numeric_tokens and _canonical_result_field after a repository-wide
Python search confirmed neither had callers. Active strict control parsing and
result-alias resolution are unchanged.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]