Skip to content

feat(mcp): treemap chart type plugin - #43569

Merged
aminghadersohi merged 1 commit into
apache:masterfrom
gkneighb:feat/mcp-treemap-plugin
Sep 10, 2026
Merged

aminghadersohi merged 1 commit into
apache:masterfrom
gkneighb:feat/mcp-treemap-plugin

Conversation

@gkneighb

Copy link
Copy Markdown
Contributor

SUMMARY

Adds a generate_chart MCP plugin for the treemap chart type (viz_type: treemap_v2), so the MCP generate_chart tool can produce treemaps. Treemap is a shipped Superset viz type that had no MCP plugin; this closes that gap.

The plugin mirrors the frontend Treemap buildQuery contract: one metric sizing the tiles plus an ordered groupby hierarchy — the first column is the outermost level and each subsequent column nests inside it. When sort_by_metric is set (the frontend default), tiles are ordered by the metric descending.

Follows the established plugin pattern (pie/funnel/gauge/waterfall) — a config schema, a map_*_config mapper, a plugin class, and registration:

  • TreemapChartConfig — metric required and a non-empty ordered groupby list (the hierarchy); optional sort_by_metric, row_limit, filters, color_scheme. Added to the ChartConfig discriminated union and the get_chart_type_schema adapters. groupby entries may not be saved_metric/sql_expression (dimensions, not metrics).
  • map_treemap_config — maps the config to form_data, preserving groupby order as the nesting hierarchy; saved metrics pass through as a bare name string, ad-hoc metrics as SIMPLE/SQL adhoc objects.
  • TreemapChartPlugin — registered in the plugin registry; treemap_v2 was already present in the recommendation category map.

The field set is intentionally minimal (core query contract). Cosmetic controls (label type, upper labels, number/date format) are left for a follow-up.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — backend/MCP only, no UI change.

TESTING INSTRUCTIONS

pytest tests/unit_tests/mcp_service/chart/test_treemap_chart.py — 15 unit tests cover schema validation (required non-empty groupby, hierarchy order preserved, groupby-not-a-metric, extra-field rejection), ChartConfig union dispatch, form_data mapping (viz_type/groupby-order/metric/sort/filters/saved-metric), and registry integration (registration, resolve_viz_type, display_name, pre_validate).

To exercise end-to-end: call the generate_chart MCP tool with
{"chart_type": "treemap_v2", "groupby": [{"name": "region"}, {"name": "product"}], "metric": {"name": "revenue", "aggregate": "SUM"}}.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

🤖 Generated with Claude Code

@codecov

codecov Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.75000% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.12%. Comparing base (1b46983) to head (458631c).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/chart/plugins/treemap.py 46.15% 25 Missing and 3 partials ⚠️
superset/mcp_service/chart/chart_utils.py 50.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #43569      +/-   ##
==========================================
- Coverage   80.13%   80.12%   -0.02%     
==========================================
  Files        2923     2924       +1     
  Lines      172286   172366      +80     
  Branches    39995    40009      +14     
==========================================
+ Hits       138063   138108      +45     
- Misses      31637    31669      +32     
- Partials     2586     2589       +3     
Flag Coverage Δ
hive 37.35% <42.50%> (+<0.01%) ⬆️
mysql 56.88% <42.50%> (-0.02%) ⬇️
postgres 56.90% <42.50%> (-0.02%) ⬇️
presto 39.24% <42.50%> (+<0.01%) ⬆️
python 84.47% <58.75%> (-0.03%) ⬇️
sqlite 56.61% <42.50%> (-0.02%) ⬇️
unit 75.78% <58.75%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gkneighb
gkneighb force-pushed the feat/mcp-treemap-plugin branch from 63597b1 to 260770f Compare August 27, 2026 10:33
@gkneighb
gkneighb marked this pull request as ready for review August 27, 2026 11:21
@dosubot dosubot Bot added the viz:charts:treemap Related to the Treemap chart label Aug 27, 2026
Comment on lines +1090 to +1100
@model_validator(mode="after")
def reject_metric_style_groupby(self) -> "TreemapChartConfig":
"""groupby entries are hierarchy dimensions, not metrics."""
for i, col in enumerate(self.groupby or []):
_reject_sql_expression_on_dimension(col, f"groupby[{i}]")
if col.saved_metric:
raise ValueError(
f"groupby[{i}] cannot use saved_metric=True; "
"saved metrics belong in the 'metric' field"
)
return self

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The validator rejects saved_metric and sql_expression, but it still accepts aggregate on a groupby entry even though aggregate also marks a ColumnRef as a metric. map_treemap_config later emits only each entry's name, silently discarding the aggregate and changing an invalid metric-style hierarchy entry into an unaggregated dimension. Reject non-null aggregate values for treemap hierarchy columns as well. [api mismatch]

Severity Level: Minor 🧹
- ⚠️ `generate_chart` accepts invalid metric-style treemap hierarchy entries.
- ⚠️ Treemap form-data silently drops requested aggregates.
- ⚠️ Generated hierarchy differs from the caller’s configuration.

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/mcp_service/chart/schemas.py
**Line:** 1090:1100
**Comment:**
	*Api Mismatch: The validator rejects `saved_metric` and `sql_expression`, but it still accepts `aggregate` on a `groupby` entry even though `aggregate` also marks a `ColumnRef` as a metric. `map_treemap_config` later emits only each entry's name, silently discarding the aggregate and changing an invalid metric-style hierarchy entry into an unaggregated dimension. Reject non-null `aggregate` values for treemap hierarchy columns as well.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The issue is valid. The reject_metric_style_groupby validator in TreemapChartConfig currently checks for saved_metric and sql_expression but fails to reject aggregate on groupby entries, which are intended to be dimensions. This allows invalid configurations that are later silently discarded.

To resolve this, update the reject_metric_style_groupby validator in superset/mcp_service/chart/schemas.py to also check for the presence of an aggregate value on groupby columns.

    @model_validator(mode="after")
    def reject_metric_style_groupby(self) -> "TreemapChartConfig":
        """groupby entries are hierarchy dimensions, not metrics."""
        for i, col in enumerate(self.groupby or []):
            _reject_sql_expression_on_dimension(col, f"groupby[{i}]")
            if col.saved_metric:
                raise ValueError(
                    f"groupby[{i}] cannot use saved_metric=True; "
                    "saved metrics belong in the 'metric' field"
                )
            if col.aggregate:
                raise ValueError(
                    f"groupby[{i}] cannot use aggregate='{col.aggregate}'; "
                    "aggregates belong in the 'metric' field"
                )
        return self

Would you like me to check the other comments on this PR and implement fixes for them as well?

superset/mcp_service/chart/schemas.py

if col.aggregate:
                raise ValueError(
                    f"groupby[{i}] cannot use aggregate='{col.aggregate}'; "
                    "aggregates belong in the 'metric' field"
                )

@bito-code-review

bito-code-review Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #a4136b

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/chart/chart_utils.py - 1
    • Dead code in treemap name builder · Line 1556-1558
      `TreemapChartConfig.groupby` has `min_length=1` (schemas.py:1062), so `dims` is always truthy. The `if dims:` guard and the `return f"{metric_label}"` fallback at lines 1556-1558 are dead code. Simplify to a single return statement.
Review Details
  • Files reviewed - 6 · Commit Range: 260770f..260770f
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/treemap.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • tests/unit_tests/mcp_service/chart/test_treemap_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@aminghadersohi aminghadersohi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gkneighb — this is a clean, well-documented plugin that mirrors the existing pie/pivot conventions closely (docstrings tie back to the frontend buildQuery contract, the union discriminator and get_chart_type_schema example are both wired up, and the tests are meaningful). Comments below; nothing here blocks the design, and one of them is a shared convention that will save you work on the sibling PRs. I'm leaving this as a review comment (not requesting changes) and not resolving the CodeAnt thread.

1. Confirmed: reject_metric_style_groupby misses aggregate (the live CodeAnt thread is correct)

schemas.py:1090-1099 guards groupby against two of the three ways a ColumnRef becomes a metric — sql_expression (via _reject_sql_expression_on_dimension) and saved_metric (explicit) — but not aggregate. So a hierarchy entry written metric-style passes validation, and map_treemap_config (chart_utils.py:1021) emits [g.name for g in config.groupby], dropping the aggregate.

Executed at head 260770ff (groupby=[{name:'region'}, {name:'sales', aggregate:'SUM'}]):

VALIDATION: accepted (no error raised)
groupby[1].aggregate on the model = 'SUM'
groupby[1].is_metric = True
emitted form_data groupby = ['region', 'sales']

Note groupby[1].is_metric == True — the model's own predicate already classifies this entry as a metric; the validator just doesn't consult it.

Treemap-specific consequence (traced through to form_data)

For a treemap the groupby list is the nesting hierarchy and the query's GROUP BY, so dropping the aggregate isn't cosmetic — it changes the aggregation grain:

  • sales (an intended-metric column) is silently promoted to the innermost nesting level. The emitted query becomes GROUP BY region, sales, so instead of one tile per region you get one leaf tile per distinct raw sales value under each region.
  • The tile-sizing metric SUM(revenue) is then aggregated at grain (region, sales_value) rather than (region) — every region tile is subdivided and its children no longer sum to what the caller configured.
  • With row_limit=100 + sort_by_metric, the backend truncates to the top 100 (region, sales) rows, i.e. an arbitrary slice of a high-cardinality axis — the rendered hierarchy is non-representative.

This is a step worse than the sibling instances: on the gauge PR the dropped aggregate produced a misleading single dial and on radar a degenerate axis — both presentation-level. Here it corrupts the GROUP BY grain itself, so the aggregation is wrong, not just the picture.

2. This is a cross-family hole — one shared fix

The identical gap exists in the gauge (#43568) and radar (#43571) reject_metric_style_* validators: each rejects saved_metric/sql_expression and misses aggregate. The repo already ships the complete predicate — ColumnRef.is_metric (schemas.py:751-753 = bool(self.aggregate) or self.saved_metric or bool(self.sql_expression)), which is already used for positive metric checks (e.g. schemas.py:1517, chart_utils.py:462, update_chart.py:157). No dimension guard uses its negation, which is exactly the miss. Collapsing the hand-rolled checks to it fixes all three at once:

@model_validator(mode="after")
def reject_metric_style_groupby(self) -> "TreemapChartConfig":
    """groupby entries are hierarchy dimensions, not metrics."""
    for i, col in enumerate(self.groupby or []):
        if col.is_metric:
            raise ValueError(
                f"groupby[{i}] is a hierarchy dimension and cannot carry a "
                "metric (aggregate, saved_metric, or sql_expression); "
                "put metrics in the 'metric' field."
            )
    return self

(If you want to keep the existing tailored error strings, just add an if col.aggregate is not None: branch alongside the saved_metric one — the point is closing aggregate.)

3. Test coverage — add the negative case

test_treemap_chart.py is solid (+167, and reverting the production files fails the union-dispatch, mapping, and registry tests). It has test_treemap_groupby_rejects_saved_metric but no test for aggregate on a groupby entry — the exact hole above. Worth a test_treemap_groupby_rejects_aggregate asserting ValidationError. As a family note: none of the reviewed siblings currently has a negative test for this case, so the gap has been shipping unguarded across the set.

4. Non-issues I checked (so you don't have to)

  • The 2 deleted lines in schemas.py are benign — they're the union discriminator description string being reflowed to insert 'treemap_v2' into the chart-type list. No behavior change.
  • map_treemap_config drops nothing else silently — every field it emits (viz_type, groupby, metric, sort_by_metric, row_limit, color_scheme, adhoc filters) has a corresponding config field.
  • chart_utils.py (+31) is purely additive (map_treemap_config + _treemap_chart_what); no existing plugin's path changes.
  • Hierarchy ordering is significant and correctly handled — order is preserved end-to-end and asserted in test_basic_treemap_form_data, and documented in the config docstring.
  • get_chart_type_schema (+9) surfaces the treemap adapter with a usable example.

Verification

  • RAN: full test_treemap_chart.py at head 260770ff → 15 passed.
  • RAN: the dropped-aggregate repro above (superset-core/src on PYTHONPATH).
  • INSPECTED: cross-family is_metric usage grep; the 2 deleted lines; map_treemap_config field coverage.
  • CI at head, deduped by check-name/latest-run: 46 SUCCESS / 3 NEUTRAL / 12 SKIPPED, zero live failures (the raw rollup's 2 playwright FAILUREs are superseded re-runs).

@netlify

netlify Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 458631c
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6aa211fc12d6ba00079c304f
😎 Deploy Preview https://deploy-preview-43569--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@aminghadersohi aminghadersohi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2 — thanks for the fast turnaround, @gkneighb. The fix(mcp): treemap — reject aggregate on groupby hierarchy columns commit (8f8ef8c) resolves my round-1 finding cleanly. One heads-up below that is not a blocker for this PR (it lives in shared infra, not your plugin), plus a trivial nit.

✅ Round-1 finding fixed — verified by execution

reject_metric_style_groupby now switches the hand-rolled saved_metric-only check to the complete predicate:

if col.is_metric:   # bool(aggregate) or saved_metric or bool(sql_expression)
    raise ValueError(f"groupby[{i}] must be a plain column, not a metric; ...")

This is exactly the ColumnRef.is_metric (schemas.py:751) reuse suggested, and it closes the aggregate hole that CodeAnt/Bito and I flagged. RAN at 8f8ef8c (superset-core/src on PYTHONPATH):

  • The round-1 repro — groupby=[{name:'region'},{name:'sales',aggregate:'SUM'}] — now raises ValidationError ("groupby[1] must be a plain column, not a metric…") instead of silently emitting groupby: ['region','sales']. Grain-corruption path closed.
  • New test_treemap_groupby_rejects_aggregate is present and the file is green: 16 passed (was 15).

The CodeAnt thread is still open in the UI but is addressed by this commit — leaving it for the bot/maintainer to resolve rather than resolving someone else's thread.

🔎 Heads-up (non-blocking, shared infra, whole plugin family): sort_by_metric isn't honored on the get_chart_data path

Not introduced here and not fixable in the treemap plugin — flagging for family awareness since the config's own docstring promises "the query orders by the metric descending."

The frontend Treemap/buildQuery.ts is the only place that turns sort_by_metric into ordering:

if (sort_by_metric && metric) { orderby.push([metric, false]); }
orderby.push(...buildColumnsOrderBy(groupby));

map_treemap_config correctly emits sort_by_metric into form_data. But the MCP data-retrieval path (get_chart_data → build_query_context_from_form_data → build_query_dicts_from_form_data, chart_helpers.py:546) builds the QueryObject server-side and never runs buildQuery.ts. That builder special-cases only deck_* and mixed_timeseries for orderby; treemap_v2 falls through to _build_single_query_dict, which sets columns/metrics/row_limit/filters but no orderby. Net effect: when an agent creates a treemap and then calls get_chart_data, the row_limit=100 truncation returns an arbitrary 100 rows rather than the top-100 by metric — so the returned/rendered tiles differ from a treemap saved and viewed in the browser.

This is the same buildQuery-bypass symptom already confirmed on the funnel sibling (#43567). The fix belongs in shared build_query_dicts_from_form_data (a treemap_v2 orderby branch mirroring buildQuery.ts), not in this PR — noting it so the family can address it in one place.

Nit (optional, pre-existing)

_treemap_chart_what (chart_utils.py:1555-1558): since groupby has min_length=1 and groupby entries always carry name (sql_expression is rejected there), dims is always truthy — the if dims: guard and the return f"{metric_label}" fallback are unreachable. Collapsible to a single return. Already flagged by Bito; purely cosmetic.

Verification

  • RAN: test_treemap_chart.py @ 8f8ef8c → 16 passed; round-1 aggregate repro now raises ValidationError.
  • INSPECTED: build_query_dicts_from_form_data / _build_single_query_dict (no treemap_v2 orderby branch); generate_chart persists form_data only; _treemap_chart_what reachability.
  • CI @ 8f8ef8c, deduped by check-name/latest run: 47 SUCCESS / 2 NEUTRAL / 9 SKIPPED, zero failures. mergeStateStatus: BLOCKED is the required maintainer-review gate (reviewDecision: REVIEW_REQUIRED) for an external contributor, not a code issue.

@bito-code-review

bito-code-review Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #784d95

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 260770f..8f8ef8c
    • superset/mcp_service/chart/schemas.py
    • tests/unit_tests/mcp_service/chart/test_treemap_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@gkneighb
gkneighb force-pushed the feat/mcp-treemap-plugin branch from 8f8ef8c to 8664853 Compare August 31, 2026 15:15

@rebenitez1802 rebenitez1802 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve — clean, pattern-faithful addition.

map_treemap_config matches the frontend treemap_v2 buildQuery/controlPanel contract (singular metric, ordered groupby hierarchy, sort_by_metric, row_limit, color_scheme), the schema validators are sound — reject_metric_style_groupby correctly rejects metric-shaped groupby entries, mirroring the newer waterfall pattern — and the unit tests pass locally (16/16) with ruff clean.

One test-coverage gap worth addressing before/soon after merge (inline comment below). A few optional low-severity polish items, none blocking:

  • treemap_v2 is missing from the generate_chart tool docstring and DEFAULT_INSTRUCTIONS in app.py (LLM discoverability), and the app.py "display name is null for all other viz_types" note is now stale since the plugin registers native_viz_types={"treemap_v2": "Treemap"}.
  • get_chart_preview has no treemap_v2 spec in _get_chart_spec_for_type, so previews fall through to the scatter fallback (waterfall was explicitly slotted into the "bar" bucket for this reason).
  • TestMapTreemapConfig doesn't assert the color_scheme default, row_limit passthrough, or the sql_expression metric branch.

Review assisted by automated multi-agent analysis + a local test/lint run.

def resolve_viz_type(self, config: Any) -> str:
return "treemap_v2"

def normalize_column_refs(self, config: Any, dataset_context: Any) -> Any:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalize_column_refs has no test coverage.

This is the most branch-heavy method in the plugin — per-column canonicalization of groupby, plus the three-way metric branch (sql_expression → passthrough, saved_metric → get_canonical_metric_name, else → get_canonical_column_name) — and it's dispatched in the live validation flow (superset/mcp_service/chart/validation/dataset_validator.py:537), yet nothing in test_treemap_chart.py exercises it.

The repo already guards exactly this saved-metric column-vs-metric casing branch for every other metric-bearing chart type via TestSavedMetricNormalizationCorrectness in tests/unit_tests/mcp_service/chart/test_column_name_normalization.py (xy / table / pie / big_number / mixed). Treemap is the only metric-bearing type missing, so a casing regression here would fail silently.

Suggested: add a treemap case to that class asserting (a) a plain groupby column is canonicalized, (b) a saved_metric metric routes through get_canonical_metric_name, (c) an adhoc-column metric routes through get_canonical_column_name, and (d) a sql_expression metric is left untouched.

@bito-code-review

bito-code-review Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #140d04

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/chart/plugins/treemap.py - 1
    • Replace Any with specific type · Line 80-80
      Use `TreemapChartConfig` instead of `Any` for the `config` parameter in `extract_column_refs`. Similar `Any` usages exist in `to_form_data`, `generate_name`, `resolve_viz_type`, and `normalize_column_refs`.
Review Details
  • Files reviewed - 6 · Commit Range: 28c4864..8664853
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/treemap.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • tests/unit_tests/mcp_service/chart/test_treemap_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@aminghadersohi

aminghadersohi commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

@gkneighb Thanks again for the solid typed Treemap foundation. I need to elevate my earlier non-blocking note after tracing the full customer-facing MCP paths: for Treemap support, registration + mapping alone still leaves materially incorrect behavior, so could you please extend this PR before we count Treemap as complete?

  1. Server-side ordering: mirror the frontend buildQuery contract—when a row limit applies, order by the singular metric descending when sort_by_metric=true, then by the ordered hierarchy columns. Today MCP emits no orderby, so a limit can return arbitrary leaves.
  2. Treemap previews: add a real shared treemap_v2 spec for both saved/form-data-key and unsaved previews, using every ordered hierarchy level plus the resolved singular metric label. Current saved preview falls through to scatter; unsaved falls through to an incomplete bar.
  3. Native round-trip + updates: adapt native groupby strings and saved/SIMPLE/SQL singular metric shapes back into TreemapChartConfig; expose/map the frontend Treemap presentation controls and preserve omitted saved values (including color scheme) in both update tools.
  4. Product-path validation: normalize update-preview column casing and add tests through generate/update/update-preview/get-chart-data/preview—not only direct model/mapper/registry tests.

At current head 86648530, I ran the 16 Treemap tests, 435 focused shared tests, and the full MCP chart suite (1,383 passed); these gaps reproduce despite green CI. Shared query-error-envelope handling can coordinate with #43737 rather than be duplicated here, but the Treemap-specific behavior above needs coverage in this PR. I have not modified or pushed to your branch.

@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Sep 6, 2026
@rusackas
rusackas force-pushed the feat/mcp-treemap-plugin branch from 8664853 to 8d0895e Compare September 7, 2026 02:35
@github-actions github-actions Bot removed the requires:rebase Requires rebasing on top of current master label Sep 7, 2026
@bito-code-review

bito-code-review Bot commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #7388fa

Actionable Suggestions - 0
Additional Suggestions - 3
  • superset/mcp_service/chart/chart_utils.py - 1
    • groupby drops sql_expression · Line 1080-1080
      `map_treemap_config` emits `groupby` as `[g.name for g in config.groupby]`, dropping `sql_expression`. The treemap plugin's `normalize_column_refs` explicitly supports groupby columns with `sql_expression` (skips canonicalization when set), so a custom-SQL groupby column would be emitted as `g.name` (possibly `None`) instead of the expression, producing an incorrect query. Consider a helper that prefers `sql_expression` over `name`, as `create_metric_object` does for metrics.
  • superset/mcp_service/chart/schemas.py - 1
    • Duplicated validator logic · Line 1166-1177
      `TreemapChartConfig.reject_metric_style_groupby` (1166-1177) is an exact copy of `GaugeChartConfig.reject_metric_style_groupby` (line 1098). Duplicating this validator creates divergence risk — a fix to one won't propagate to the other. Consider extracting a shared helper and calling it from both validators.
  • superset/mcp_service/chart/plugins/treemap.py - 1
    • Replace Any with specific types · Line 80-80
      Dynamically typed `Any` is used in multiple method signatures: `extract_column_refs`, `to_form_data`, `generate_name`, `resolve_viz_type`, and `normalize_column_refs`. Replace `Any` with specific types where possible, e.g., `TreemapChartConfig` for `config` and `dict` for `dataset_context`.
Review Details
  • Files reviewed - 6 · Commit Range: ec030c3..8d0895e
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/treemap.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • tests/unit_tests/mcp_service/chart/test_treemap_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@aminghadersohi

Copy link
Copy Markdown
Contributor

Re-reviewed 8d0895e986ef786c7b901385e39928e5424b232b against the previous head and refreshed base, also checking integration with master 53070fa4. The range-diff is effectively a rebase; the previously requested Treemap gaps remain:

  • Ordering is partially fixed by the refreshed base: chart_helpers.py:508–517 emits metric-descending order, but omits the hierarchy tie-breakers. With row_limit=1, sort_by_metric=false still emits no orderby; the frontend Treemap buildQuery appends the ordered hierarchy in both cases.
  • Previews still aren't Treemaps: for region/product/SUM(revenue) data, the saved/form-data-key strategy falls through to scatter (get_chart_preview.py:488–531); the unsaved helper emits a bar with only a region color encoding, no value axis or hierarchy (preview_utils.py:470–566). Please share a real Treemap spec across both paths.
  • Native round-trip/preservation remains missing: request validation rejects native string groupby and saved/SIMPLE/SQL singular metric shapes. A replacement saved update drops omitted show_labels/number_format and resets lyftColors to supersetColors (update_chart.py:233–252); update-preview likewise resets omitted presentation values. The schema/mapper still lack the frontend presentation controls.
  • Update-preview casing: lowercase hierarchy/metric names reach validate_and_compile unchanged against uppercase dataset columns (update_chart_preview.py:220–274), unlike generate/update normalization.

Validation: all 1,403 MCP chart tests pass, as do Ruff on the six PR files and git diff --check; focused temporary reproductions expose the above behavior. The PR still adds only schema/mapper/registry Treemap tests, not the requested generate/update/update-preview/get-chart-data/preview workflow regressions. Please cover these behaviors before considering Treemap support complete. No contributor-branch changes made.

@gkneighb
gkneighb force-pushed the feat/mcp-treemap-plugin branch 2 times, most recently from e0d51c4 to 8af1773 Compare September 9, 2026 19:13
Adds a generate_chart plugin for treemap (viz_type 'treemap_v2'): one metric
sizing the tiles plus an ordered groupby hierarchy; sort_by_metric orders
tiles by the metric descending.

Rebased onto current master (past the gauge plugin + its follow-up), and adds
the generate_chart.py docstring entry (one-of list, per-type bullet,
'treemap'/'hierarchy' quick-lookup) plus the get_chart_type_schema core list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gkneighb
gkneighb force-pushed the feat/mcp-treemap-plugin branch from 8af1773 to 458631c Compare September 10, 2026 02:12
@aminghadersohi

Copy link
Copy Markdown
Contributor

Re-reviewed 458631c26eb4515be0f6582f353523a409c16a90 against 8d0895e9. Thanks for the refresh: update-preview casing is fixed, and both update paths preserve omitted show_labels/number_format. The remaining gaps from the previous review still reproduce:

  • Ordering: with row_limit=1, the shared query builder emits only metric-descending order when enabled, and no orderby when disabled. Both cases still omit the frontend Treemap hierarchy ordering (chart_helpers.py:578–585).
  • Previews: region/product/SUM(revenue) still renders through the saved/form-data-key scatter fallback (get_chart_preview.py:575) or an unsaved bar spec with only region color encoding, without a value axis or hierarchy (preview_utils.py:953).
  • Round-trip and update defaults: native string hierarchy columns and saved/SIMPLE/SQL metric shapes still fail request validation. Both update paths reset omitted color_scheme='lyftColors', row_limit=7, and sort_by_metric=false to supersetColors, 100, and true. The Treemap schema/mapper still don't expose the frontend presentation controls; the shared merge's omitted-field handling is specialized for Gauge (chart_utils.py:675–726).

Validation: 1,578 chart tests passed, 1 skipped, plus eight temporary diagnostic cases confirming the remaining gaps and the fixes above; Ruff and whitespace checks passed. The Treemap test file is unchanged and still lacks the requested product-path regression coverage. CI has no failing/pending checks and mergeability is clean, but those green checks don't cover these behaviors. Please address the remaining Treemap paths before considering support complete. No contributor-branch changes made.

@bito-code-review

bito-code-review Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #b4f529

Actionable Suggestions - 0
Additional Suggestions - 4
  • superset/mcp_service/chart/schemas.py - 1
    • Missing metric validation · Line 1403-1414
      `reject_metric_style_groupby` rejects metric-style `groupby` entries but never validates that the required `metric` field is actually a metric. A plain column (no `aggregate`/`saved_metric`/`sql_expression`) passes validation and yields invalid treemap `form_data` via `map_treemap_config`. Mirror the `GaugeChartConfig` guard (`if not self.metric.is_metric: raise ValueError(...)`) for consistency.
  • superset/mcp_service/chart/chart_utils.py - 1
    • Aggregate metric label mismatch · Line 1807-1809
      For an aggregate metric like `{"name":"revenue","aggregate":"SUM"}`, `metric_label` resolves to `name` ("revenue") because `label` is None, so the chart name reads "region by revenue" while the actual form_data metric is "SUM(revenue)" (see `create_metric_object` line 836). `_big_number_chart_what` (line 1873) handles this; consider matching it.
  • superset/mcp_service/chart/plugins/treemap.py - 2
    • Inconsistent pre_validate metric check · Line 53-54
      `pre_validate` checks `groupby` with truthiness (`not config.get("groupby")`) but checks `metric` only for key presence (`"metric" not in config`). A config with `"metric": null` or `"metric": {}` slips past this fast-path and falls through to a generic schema error instead of the helpful `MISSING_TREEMAP_FIELDS` message. Align both checks for consistent validation.
    • Disallow dynamic Any type · Line 80-80
      Replace `Any` with `TreemapChartConfig` in `extract_column_refs`. Similar `Any` usages exist in `to_form_data`, `generate_name`, `resolve_viz_type`, and `normalize_column_refs` (lines 90, 94, 99, 102).
Review Details
  • Files reviewed - 7 · Commit Range: 458631c..458631c
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/treemap.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • tests/unit_tests/mcp_service/chart/test_treemap_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@aminghadersohi
aminghadersohi merged commit 1b03ad8 into apache:master Sep 10, 2026
75 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L viz:charts:treemap Related to the Treemap chart

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants