sadpandajoe commented on code in PR #43770:
URL: https://github.com/apache/superset/pull/43770#discussion_r4223874854
##########
superset/mcp_service/chart/chart_utils.py:
##########
@@ -1715,6 +1758,847 @@ def map_histogram_config(config:
"HistogramChartConfig") -> Dict[str, Any]:
return form_data
+def _bullet_token_list(values: Sequence[str | int | float]) -> str:
+ """Serialize typed Bullet controls to the frontend's comma-separated
form."""
+ tokens: list[str] = []
+ for value in values:
+ if isinstance(value, float):
+ token = repr(value)
+ # ``100`` parses back to the same binary float as ``100.0`` and
+ # preserves the frontend's established compact integer spelling.
+ if token.endswith(".0") and not (
+ value == 0.0 and math.copysign(1.0, value) < 0
+ ):
+ token = token[:-2]
+ tokens.append(token)
+ else:
+ tokens.append(str(value))
+ return ",".join(tokens)
+
+
+def map_bullet_config(config: BulletChartConfig) -> Dict[str, Any]: # noqa:
C901
+ """Map typed Bullet config to ``Bullet/buildQuery`` and transformProps.
+
+ The frontend buildQuery replaces the generic query fields with exactly one
+ metric and the groupby hierarchy. Presentation controls stay in native
+ snake_case form_data; the chart plugin camelizes them for transformProps.
+ """
+ if (
+ config.dimensions is None
+ and config._inherited_groupby is None
+ and config.order_by
+ ):
+ # An update resolves its saved hierarchy before mapping. Without one,
+ # creation must validate sort targets against an empty hierarchy.
+ BulletChartConfig.model_validate(
+ {**config.model_dump(exclude_unset=True), "dimensions": []}
+ )
+ metric = create_metric_object(config.metric)
+ form_data: Dict[str, Any] = {
+ "viz_type": "bullet",
+ "metric": metric,
+ }
+
+ # Optional semantic/query fields are emitted only when explicitly supplied.
+ # This lets update_chart and update_chart_preview preserve native saved
state,
+ # while an explicit empty value still clears it through the generic merge
path.
+ if "dimensions" in config.model_fields_set:
+ form_data["groupby"] = [dimension.name for dimension in
config.dimensions or []]
+ if "row_limit" in config.model_fields_set:
Review Comment:
Creating a Bullet chart without `row_limit` now saves no limit, even though
`BulletChartConfig.row_limit` advertises a default of 10000 / max 50000
("Maximum bullet rows"). On a deployment with `ROW_LIMIT=50000`,
`generate_chart` with `dimensions=[{"name":"region"}]` and no `row_limit` over
15,000 regions stores a chart whose `get_chart_data` and previews return 15,000
rows instead of the documented 10,000; every other mapper in this file writes
`row_limit` unconditionally. Can creation apply the schema default while
updates keep preserving the saved value when the field is omitted?
##########
superset/mcp_service/chart/preview_utils.py:
##########
@@ -1398,6 +2412,101 @@ 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 escaped field paths resolves literal output keys without 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)
Review Comment:
A saved grouped XY chart with the default `truncate_metric: true` (`metrics:
["revenue"]`, `groupby: ["region"]`, `x_axis: "day"`) comes back from the new
query chain with the metric prefix already stripped (`chart_helpers.py` ~1380
renames the metric level to `None`), so rows look like `{day: ..., East: 10,
West: 20}`. None of those keys start with `revenue` + the separator, so
`fields` is empty, the adapter returns `None`, and the generic renderer plots a
single numeric series with no legend while the preview still reports success.
Should the field discovery also cover the truncated-metric shape, e.g. every
non-x-axis key when `truncate_metric` is set and there is one metric?
##########
superset/mcp_service/chart/compile.py:
##########
@@ -116,14 +119,19 @@ def _compile_chart(
row_limit=plugin.compile_row_limit(form_data) if plugin else 2,
force=False,
)
+ set_query_context_form_data(query_context, dataset_id, "table")
command = ChartDataCommand(query_context)
command.validate()
result = command.run()
warnings: List[str] = []
row_count = 0
- if query_failure := query_result_failure(result):
+ query_data, query_failure = query_result_data(
Review Comment:
A grouped Gauge whose query returns one non-finite dial next to finite ones
(say `[{team: "A", score: Infinity}, {team: "B", score: 42}]` from a Postgres
division) now fails `generate_chart`/`update_chart` with `CHART_COMPILE_FAILED`
("contains a non-finite number"). This `query_result_data` call runs before
`normalize_chart_query_result`, and without `preserve_nonfinite_floats=True` it
rejects the infinity up front, so the Gauge normalizer that skips invalid dials
and renders B never runs; before this change that result compiled. Should this
call pass `preserve_nonfinite_floats=True` (as `normalize_treemap_query_result`
does), with the same for the new preview validation calls?
--
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]