superset icon indicating copy to clipboard operation
superset copied to clipboard

feat(chart): support icons and text in the `deck.gl Geojson` visualization

Open JoshuaJADaniel opened this issue 1 month ago β€’ 17 comments

User description

SUMMARY

The deck.gl Geojson visualization allows users to visualize point, line, and polygon geometries on maps using the GeoJSON specification. Currently, users can only render points as circles, however, deck.gl's GeoJsonLayer supports rendering points as circles, icons, and/or text according to the GeoJsonLayer documentation.

This pull request extends the existing functionality, allowing users to additionally render points as labels and/or icons.

Approach

To support both basic and advanced use cases, we implemented two configuration flows for adding labels and/or icons:

  • "Basic" flow: This is the common case where users just want to show labels and/or icons with little customization. The user can customize the labels and/or icons using only UI controls.
  • "Advanced" flow: This is the niche case where users need more per-point customization and/or would like to set options not exposed in the basic flow. The user does this by typing in a JavaScript function that returns a configuration object aligned with deck.gl's documentation.

Rationale

deck.gl's GeoJsonLayer supports many options for labels and icons, but exposing all of them in the UI would lead to a cluttered experience. The approach taken here avoids cluttering the UI while flexibly supporting both basic and advanced use cases.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Text/Label Support Demo

https://github.com/user-attachments/assets/f99802ef-cdb2-47da-a367-3e978f362cb8

Icon Support Demo

https://github.com/user-attachments/assets/86ece538-01cf-4d07-9d23-3b7dbda5b83a

TESTING INSTRUCTIONS

  1. Create a GeoJSON dataset.

    Click here for the sample dataset from the demo


    You can use this query to create a dataset in Superset using the SQL Lab interface:

    SELECT '{
      "type": "FeatureCollection",
      "name": "Top 10 Most Populous US States (2024 Estimates)",
      "features": [
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-121.468926, 38.555605]
          },
          "properties": {
            "longName": "California",
            "shortName": "CA"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-97.7431, 30.2672]
          },
          "properties": {
            "longName": "Texas",
            "shortName": "TX"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-84.27277, 30.4518]
          },
          "properties": {
            "longName": "Florida",
            "shortName": "FL"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-73.781339, 42.659829]
          },
          "properties": {
            "longName": "New York",
            "shortName": "NY"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-76.875613, 40.269789]
          },
          "properties": {
            "longName": "Pennsylvania",
            "shortName": "PA"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-89.650373, 39.78325]
          },
          "properties": {
            "longName": "Illinois",
            "shortName": "IL"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-83.000647, 39.962245]
          },
          "properties": {
            "longName": "Ohio",
            "shortName": "OH"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-84.39, 33.76]
          },
          "properties": {
            "longName": "Georgia",
            "shortName": "GA"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-78.638, 35.771]
          },
          "properties": {
            "longName": "North Carolina",
            "shortName": "NC"
          }
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [-84.5467, 42.7335]
          },
          "properties": {
            "longName": "Michigan",
            "shortName": "MI"
          }
        }
      ]
    }' as JSON
    
  2. Create a deck.gl Geojson chart/visualization using the dataset created in step 1.

  3. Under the Query section, fill the required GeoJson Column field (if using the sample dataset, select JSON).

  4. Under the GeoJson Settings section, configure label and/or icon settings as was shown in the demo videos.

Notes

  • For JavaScript mode, ensure that the ENABLE_JAVASCRIPT_CONTROLS feature flag is enabled.
  • For icons, image URLs must conform to your configured CSP settings. For the demo, I added https://static.thenounproject.com to the connect-src directive in the CSP found in superset/config.py. If you simply want to test icons without modifying the CSP, you can try this sample image URL (it is hosted on cartocdn, which is included in the default CSP).

ADDITIONAL INFORMATION

  • [x] Has associated issue: Fixes #34621
  • [x] Required feature flags: ENABLE_JAVASCRIPT_CONTROLS
  • [x] 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
  • [x] Introduces new feature or API
  • [ ] Removes existing feature or API

CodeAnt-AI Description

Add optional icon and label rendering to GeoJSON map layer

What Changed

  • Users can enable point labels and/or icons in the GeoJSON deck.gl chart via new checkboxes in the control panel; sizes, colors, and units are configurable and JavaScript-based generators are available when the JavaScript controls feature flag is on
  • The layer now renders labels and icons on the map when enabled, using either the simple form controls or a user-provided JS generator; missing icon URLs or undefined colors are handled safely with sensible defaults so rendering no longer throws
  • Added unit tests that validate extraction of label/icon options from both form data and JS outputs

Impact

βœ… Labels and icons on GeoJSON points βœ… Fewer map rendering errors when color or icon inputs are missing βœ… Easier per-point customization using optional JavaScript generators

πŸ’‘ Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

JoshuaJADaniel avatar Nov 20 '25 08:11 JoshuaJADaniel

Code Review Agent Run #b486f3

Actionable Suggestions - 0
Review Details
  • Files reviewed - 5 Β· Commit Range: f187f7a..c79c175
    • superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.test.ts
    • superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.tsx
    • superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/controlPanel.ts
    • superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.tsx
    • superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/controls.ts
  • Files skipped - 0
  • Tools
    • Eslint (Linter) - βœ”οΈŽ 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 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 Default Agent You can customize the agent settings here or contact your Bito workspace admin at [email protected].

Documentation & Help

AI Code Review powered by Bito Logo

bito-code-review[bot] avatar Nov 20 '25 08:11 bito-code-review[bot]

Waouw !! Great !! Congratulation !

+1 !!!

SupersetOdT avatar Nov 20 '25 17:11 SupersetOdT

@DamianPendrak mind taking a look since it's deck.gl

sadpandajoe avatar Nov 20 '25 18:11 sadpandajoe

πŸŽͺ Showtime is building environment on GHA for c79c175

github-actions[bot] avatar Nov 25 '25 22:11 github-actions[bot]

πŸŽͺ Showtime deployed environment on GHA for c79c175

β€’ Environment: http://34.213.178.163:8080 (admin/admin) β€’ Lifetime: 48h auto-cleanup β€’ Updates: New commits create fresh environments automatically

github-actions[bot] avatar Nov 25 '25 23:11 github-actions[bot]

This looks SO cool!

The only thing I'd like to request right now (to prevent XSS attacks) is to put the Javascript forms and the checkboxes to reveal them behind the ENABLE_JAVASCRIPT_CONTROLS feature flag by adding isFeatureEnabled(FeatureFlag.ENABLE_JAVASCRIPT_CONTROLS) where relevant. A lot of orgs have that flag turned off for (very good) safety reasons.

Otherwise, this is complete awesomeness!

@rusackas Thank you, and valid security concern! I made this change in 740b3c2f68daaa2004ff7f08189b108d5f754f5c.

JoshuaJADaniel avatar Nov 26 '25 07:11 JoshuaJADaniel

Thanks for adding all the feature-flag checks. I guess what I'm wondering now, looking at it again, is if we overcorrected here.

Should parts of this work without the Javascript Controls feature flag turned on? I.e. Should I still be able to pick an icon URL, adjust size, or maybe use some of the other inputs (color, etc.)? If some of these new features work without Javascript inptus, that would be nice to leave those features enabled. I was under the impression that the JS inputs just add even more flexibility, and were somewhat optional. Correct me if I'm misunderstanding :)

Would love to be able to use as much of this as possible in deployments where JS controls are disabled (e.g. Preset, and... probably lots of others)

rusackas avatar Nov 28 '25 19:11 rusackas

Otherwise, this is looking fantastic!

rusackas avatar Nov 28 '25 19:11 rusackas

@rusackas

Should parts of this work without the Javascript Controls feature flag turned on? I.e. Should I still be able to pick an icon URL, adjust size, or maybe use some of the other inputs (color, etc.)? If some of these new features work without Javascript inptus, that would be nice to leave those features enabled. I was under the impression that the JS inputs just add even more flexibility, and were somewhat optional. Correct me if I'm misunderstanding :)

You are correct on everything you said here -- the JS inputs just adds more flexibility.

This behavior is still maintained after 740b3c2f68daaa2004ff7f08189b108d5f754f5c; it might be confusing because I was accounting for a potential edge case if I only changed the JS fields visibility logic. Scenario: a user initially had the JS feature flag turned on, then enabled JS mode on the visualization, then turned the JS feature flag off. If this happens, then all the customization controls would be hidden (the non-JS fields would be hidden because JS mode is enabled and the JS fields would be hidden because the feature flag is turned off). To avoid this, I show the non-JS fields if JS mode is disabled OR the feature flag is turned off. For example, here is the label color control: image

Hopefully it makes sense (I can clarify further if needed). In any case, if it is not an edge case we need to consider, I can only change the JS fields visibility logic (which is what I believe you were expecting initially).

JoshuaJADaniel avatar Nov 28 '25 20:11 JoshuaJADaniel

πŸŽͺ Showtime is building environment on GHA for 740b3c2

github-actions[bot] avatar Dec 01 '25 23:12 github-actions[bot]

Pinging @sadpandajoe (cc @mistercrunch) who was (I believe) looking into Showtime failures. This one seems good to go by looking at the code, but I'd love to kick the tires on it before approving/merging.

rusackas avatar Dec 02 '25 20:12 rusackas

Hey @rusackas, any update on getting this pull request merged?

JoshuaJADaniel avatar Dec 08 '25 14:12 JoshuaJADaniel

OK, finally testing this now, and running into some questions/feedback:

  • It looks like this (pre-existing) control for labels/markdown isn't working right. Not sure if it does outside of this PR: image But it seems like it kind of covers both use cases of this PR? I'm not sure where that feature falls short.
  • It looks like you can use Labels OR Icons, but not both, is that accurate? I'm wondering if a "Labels/Icons/None" Select would make more sense, and showing/hiding the relevant controls according to the option selected.
  • If you choose settings for the image, and uncheck/re-check the "Image" box, the settings are wiped/lost. Would be nice to persist that.
  • The icon size options seem sensible, but i wonder if we should allow a freeform entry there.
  • If you have an icon selected/working, then check the "Text" option, it hides the icons and shows the text (awesome!) but does not show the icon again if you un-check "Text"
  • Changing the settings for icons doesn't seem to refresh the viz, even though the controls seem to indicate that they should. You have to click Update... so something probably just isn't getting sent to TransformProps quite right or something like that.

I'm most curious about the first point, regarding the markdown controls, and if/how we should get those working, and whether or not that would solve the same purposes of rendering different properties, adding icons, etc.

rusackas avatar Dec 08 '25 19:12 rusackas

CodeAnt AI is reviewing your PR.

Nitpicks πŸ”

πŸ”’Β No security issues identified
⚑ Recommended areas for review

  • [ ] Risky sandboxed execution
    Multiple calls to sandboxedEval are used (data mutator, label generator, icon generator). Ensure the sandbox implementation actually isolates execution and consider limiting execution time / resource usage. Also, any exceptions thrown by the evaluated code are currently not caught in all places β€” these should be handled to avoid destabilising the layer rendering.

  • [ ] Unvalidated user JS output
    The code executes user-provided JavaScript (via sandboxedEval) to generate label and icon configuration objects and then spreads the results into the GeoJsonLayer props. The generator's return value is only guarded by typeof generator === 'function' and then passed directly to compute*Options functions (which only filter keys). This can lead to runtime errors (wrong types for deck.gl props), unexpected behaviour, or a crash if the generator throws. Consider validating the generator return shape and surrounding execution with try/catch and fallbacks.

  • [ ] Weak runtime type-safety for options
    computeGeoJsonTextOptionsFromJsOutput and computeGeoJsonIconOptionsFromJsOutput only filter keys by name but do not validate that the values have the expected types (e.g., functions, arrays, numbers). This can pass invalid values into deck.gl and cause runtime errors. Consider asserting types for common props (e.g., getText should be a function or string-producing accessor) before returning.

  • [ ] Arbitrary JS execution
    The new controls expose JavaScript config generators (label_javascript_config_generator and icon_javascript_config_generator) that accept user-provided JS and are later evaluated to configure deck.gl. Even though this is gated by FeatureFlag.EnableJavascriptControls, evaluate how and where that JS is executed, whether it is sandboxed, and what protections exist against arbitrary script execution, data exfiltration, or XSS-like behaviors.

  • [ ] Icon URL validation / CSP risk
    The icon_url text control allows arbitrary URLs and only references CSP in the description. There is no validator to block dangerous schemes (e.g., javascript:, data:) or to ensure HTTPS. This can lead to failed loads under strict CSP or unexpected behaviors β€” validate input and/or sanitize before use.

  • [ ] Defensive defaults
    The default label config generator uses f.properties.name directly. If a feature object is missing properties or name, the accessor may throw when executed in some environments. Use defensive access (optional chaining) in the default example to avoid runtime errors for edge-case GeoJSON.

  • [ ] Public API change
    The function jsFunctionControl was changed from an internal function to a named export. Verify this was intentional: exporting it makes it part of the module's public surface and may require adding it to consuming modules' imports or the package's barrel exports. Confirm there are no naming collisions with other exports and that consumers handle the new export correctly.

  • [ ] Brittle assertions
    Several tests use full-object equality (toEqual) including function properties and exact nested objects. These assertions are brittle: small, unrelated implementation changes (additional keys, reordering, or small numeric differences) will break the tests even if behavior is correct. Prefer matching subsets (toMatchObject / objectContaining) or asserting behavior of returned functions rather than strict object equality.

CodeAnt AI finished reviewing your PR.

Appreciate the feedback @rusackas!

  • It looks like this (pre-existing) control for labels/markdown isn't working right. Not sure if it does outside of this PR: [image]. But it seems like it kind of covers both use cases of this PR? I'm not sure where that feature falls short.

I'm most curious about the first point, regarding the markdown controls, and if/how we should get those working, and whether or not that would solve the same purposes of rendering different properties, adding icons, etc.

I do not think this PR impacted the tooltip functionality. In any case, the tooltip (presumably) only appears on hover. This is different from labels and icons, which remain visible without requiring a hover event.

  • It looks like you can use Labels OR Icons, but not both, is that accurate? I'm wondering if a "Labels/Icons/None" Select would make more sense, and showing/hiding the relevant controls according to the option selected.

You can use both labels and icons at the same time:

image

If you are not using JavaScript though, the icon and label might overlap.

  • If you choose settings for the image, and uncheck/re-check the "Image" box, the settings are wiped/lost. Would be nice to persist that.

Agreed! Done in 44bd0d676478196622cd8886b92defa5c744f7dc.

  • The icon size options seem sensible, but i wonder if we should allow a freeform entry there.

It is actually free form, but it was not doing the string --> int conversion. Fixed in 8b83a50303e1edf1d4437430b9cf6a1ec648261f.

  • If you have an icon selected/working, then check the "Text" option, it hides the icons and shows the text (awesome!) but does not show the icon again if you un-check "Text"
  • Changing the settings for icons doesn't seem to refresh the viz, even though the controls seem to indicate that they should. You have to click Update... so something probably just isn't getting sent to TransformProps quite right or something like that.

The second bullet here appears to be due to deck.gl's IconLayer failing to initialize when the icon URL is empty. When this happens, you have to hit "Update chart" to reinitialize the IconLayer. Fixed in f25f57ba3ad908f68744fcecf46c9211511f29c6.

I was not able to reproduce the first bullet here, but I suspect it might be resolved with the same commit.

JoshuaJADaniel avatar Dec 08 '25 23:12 JoshuaJADaniel

Hey @rusackas, any update on this pull request?

JoshuaJADaniel avatar Dec 15 '25 19:12 JoshuaJADaniel

πŸŽͺ Showtime is building environment on GHA for 44bd0d6

github-actions[bot] avatar Dec 16 '25 21:12 github-actions[bot]

πŸŽͺ Showtime deployed environment on GHA for 44bd0d6

β€’ Environment: http://54.188.146.143:8080 (admin/admin) β€’ Lifetime: 48h auto-cleanup β€’ Updates: New commits create fresh environments automatically

github-actions[bot] avatar Dec 16 '25 21:12 github-actions[bot]

I was just wondering if the terms "Tooltip contents" and "Customize tooltips template" are appropriate and do not cause confusion with the real (non-persistent) tooltips in the field "JavaScript tooltip generator"?

The 2 sections "Tooltip contents"' and "Customize tooltips template" are actually related to the section "Enable labels" and allow for more finely tuned text display, right?

Wouldn’t it be clearer to name them 'Label contents' and 'Customize label template'?

Moreover, I can’t set up a display via these 2 sections. Could you provide an example script?

Thank you for the nice job !

SupersetOdT avatar Dec 17 '25 10:12 SupersetOdT