Allow dynamic changes to st.pydeck_chart parameters when key is provided #13703
Allow dynamic changes to st.pydeck_chart parameters when key is provided #13703lukasmasuch merged 10 commits intodevelopfrom
st.pydeck_chart parameters when key is provided #13703Conversation
…meter
When a user provides a `key` parameter to st.pydeck_chart with selections
enabled, the element ID now remains stable across data/spec changes, allowing
selection state to persist similar to st.vega_lite_chart.
Changes:
- Backend: Set key_as_main_identity={"selection_mode"} to use only the
selection mode for ID computation when key is provided
- Frontend: Add selection sanitization useEffect to remove orphaned indices
when data shrinks or layers are removed
- Frontend: Improve anyLayersHaveSelection check to validate indices before
applying dimming, preventing visual glitches
- Frontend: Add proper React key in ElementNodeRenderer matching
ArrowVegaLiteChart pattern
Co-Authored-By: Claude <[email protected]>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
There was a problem hiding this comment.
Pull request overview
This PR implements selection state preservation for st.pydeck_chart when users provide a key parameter, matching the established pattern used by st.vega_lite_chart and st.dataframe. The implementation allows map selections to persist across data updates without forcing a full reset.
Changes:
- Backend: Modified element ID computation to use
key_as_main_identity={"selection_mode"}, making element identity stable when a key is provided - Frontend: Added selection sanitization logic to remove orphaned indices when data shrinks or layers are removed
- Frontend: Enhanced the
anyLayersHaveSelectionvalidation to prevent visual glitches with stale selections - Frontend: Added React key pattern in ElementNodeRenderer consistent with ArrowVegaLiteChart
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
lib/streamlit/elements/deck_gl_json_chart.py |
Changed key_as_main_identity from False to {"selection_mode"} to preserve element ID across spec changes when a key is provided |
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx |
Added sanitization useEffect to clean orphaned selections and improved selection validation logic |
frontend/lib/src/components/core/Block/ElementNodeRenderer.tsx |
Added conditional React key based on element ID, matching the ArrowVegaLiteChart pattern |
dynamic-pydeck-chart-opus.md |
Documentation file providing implementation analysis and context (not production code) |
dynamic-pydeck-chart-codex.md |
Documentation file with technical deep-dive (not production code) |
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
- Add Python unit tests for element ID stability with key - Add E2E test for selection preservation when data updates - Add selection sanitization effect for orphaned indices - Add smarter dimming check to validate indices before applying - Remove planning documents Co-Authored-By: Claude <[email protected]>
- Fix non-array layer data handling: preserve selections for layers with URL strings, GeoJSON objects, or undefined data instead of clearing them - Extract duplicated layer data lengths logic into getLayerDataLengths helper - Remove data.selection from useEffect dependency array to avoid unnecessary re-executions (only sanitize when spec changes) - Fix unit tests to properly verify element ID stability with same key using mock to bypass duplicate key restriction Co-Authored-By: Claude <[email protected]>
st.pydeck_chart parameters when key is provided
📈 Frontend coverage change detectedThe frontend unit test (vitest) coverage has increased by 0.1300%
🎉 Great job on improving test coverage! |
SummaryThis PR makes Code QualityThe new selection sanitization is cleanly encapsulated, but it only updates client-side state. Because updates are marked useEffect(() => {
if (!isSelectionModeActivated || !parsedPydeckJson.layers) {
return
}
// ...
if (changed) {
setSelection({
fromUi: false,
value: { selection: { indices: newIndices, objects: newObjects } },
})
}
// ...
}, [parsedPydeckJson, isSelectionModeActivated, setSelection]) pydeck_proto.id = compute_and_register_element_id(
"deck_gl_json_chart",
user_key=key,
# When a key is provided, only selection_mode affects the element ID.
# This allows selection state to persist across data/spec changes.
# Note: This can lead to orphaned selections if data length shrinks,
# but the frontend handles this by sanitizing invalid indices.
key_as_main_identity={"selection_mode"},Test CoverageThe new e2e test verifies selection persistence on data updates, but it does not cover the orphaned-index cases the sanitization logic targets (data shrink or layer removal), and it lacks a “must NOT happen” assertion per the e2e guidelines. @pytest.mark.only_browser("chromium")
@pytest.mark.flaky(reruns=4)
def test_pydeck_chart_selection_preserved_when_data_updates(app: Page):
"""
Test that selection state is preserved when data updates and a key is provided.
This tests the key_as_main_identity={"selection_mode"} behavior.
"""
_select_chart_type(app, "dynamic")
wait_for_chart(app)
# ...
# Selection should still be preserved because key is provided
expect_prefixed_markdown(app, markdown_prefix, FIRST_POINT_SELECTION)
expect_prefixed_markdown(app, markdown_prefix_session_state, FIRST_POINT_SELECTION)Backwards CompatibilityBehavior changes are gated behind providing Security & RiskNo security issues identified. The main risk is stale selection indices when data shrinks, which can lead to UI/backend divergence or out-of-range indexing in app code on the rerun that introduces the data change. Recommendations
VerdictAPPROVED: Changes are solid and behavior is well-motivated; only follow-up coverage/consistency improvements are recommended. This is an automated AI review using |
Add comprehensive tests for: - Clear selection button rendering in DeckGlJsonChart - Selection sanitization in useDeckGl hook (layer removal, data shrinking, URL data preservation) - PydeckSelectionSerde serialization/deserialization - parse_selection_mode function validation - Callback handling with on_select parameter Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Claude (claude-opus-4-5) <[email protected]>
frontend/lib/src/components/elements/DeckGlJsonChart/useDeckGl.tsx
Outdated
Show resolved
Hide resolved
The hasUnknownLayerId flag was incorrectly preserving orphaned selections when any layer lacked an ID. Now only preserve when ALL layers lack IDs (layerData is empty), allowing proper cleanup of non-existent layer selections in mixed scenarios. Co-Authored-By: Claude (claude-opus-4-5) <[email protected]>
| } | ||
| ) | ||
|
|
||
| it("should render clear selection button when there is an active selection and not disabled", async () => { |
There was a problem hiding this comment.
Is this test related, or is it just opportunistically adding more test coverage?
There was a problem hiding this comment.
It's partly related to the selection state itself, which we are touching in this PR, but I also requested Claude to add some more tests around the selection logic (which was previously a but undercovered)
| parsedPydeckJson.layers | ||
| ) | ||
|
|
||
| // Filter out orphaned selections |
There was a problem hiding this comment.
Maybe make this into a separate function for readability/testing?
There was a problem hiding this comment.
Sounds good, extracted it!
| continue | ||
| } | ||
|
|
||
| const objects = data.selection.objects[layerId] || [] |
There was a problem hiding this comment.
Also this block could be a small function.
There was a problem hiding this comment.
Updated as well 👍
| const { layerData } = getLayerDataInfo(jsonCopy.layers) | ||
|
|
||
| // Only consider a selection valid if the layer exists and has at least one | ||
| // index within the current data length. This prevents dimming when selection |
There was a problem hiding this comment.
I'm not very familiar with this element, is dimming referring to changing the node's appearance to unselected?
There was a problem hiding this comment.
Yes, when a selection is active, unselected points are dimmed by reducing their opacity to 40%, making selected points stand out. I've updated the comment to clarify this behavior.
|
|
||
|
|
||
| class PydeckSelectionSerdeTest(DeltaGeneratorTestCase): | ||
| """Test PydeckSelectionSerde serialization and deserialization.""" |
There was a problem hiding this comment.
Are these opportunistic test coverage? Or related to the changes?
There was a problem hiding this comment.
Yep, see the other comment
| assert "Selection mode must be a single value" in str(e.value) | ||
|
|
||
|
|
||
| class PydeckCallbackTest(DeltaGeneratorTestCase): |
There was a problem hiding this comment.
I guess this one also, is opportunistic added coverage for callbacks and not directly related?
There was a problem hiding this comment.
Indirectly related since it covers the selection logic itself. So a bit more opportunistic to fill in missing coverage for selection logic on pydeck_chart.
Extract selection sanitization logic into reusable helper functions for better readability and testability: - sanitizeSelection(): main orchestration function - filterValidIndicesForLayer(): index validation for array data Also clarify "dimming" comment to explain it reduces opacity to 40%. Co-Authored-By: Claude (claude-opus-4-5) <[email protected]>
Describe your changes
This PR enables
st.pydeck_chartto preserve selection state when map data or parameters change, when a user provides akeyparameter. Selection state now persists across data updates, similar tost.vega_lite_chart.Backend Change: Set
key_as_main_identity={"selection_mode"}so the element ID depends only on the selection mode, not the spec.Frontend Changes:
anyLayersHaveSelectioncheck to validate indices before applying dimmingTesting Plan
key="my_map"Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.