Skip to content

Commit dc98eab

Browse files
chrisgervangclaude
andcommitted
pydeck: bump frontend to ~9.3.*, fix widget JSON registration, add widget gallery examples (#10242)
* Prepare pydeck 0.9.3 release Bump pydeck version 0.9.2 → 0.9.3 and lock frontend to deck.gl ~9.3.*. Update bump_version.py to generate tilde-range semver (~X.Y.*) from lerna.json. https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * Fix quote style to double quotes per Black formatter https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * Add PopupWidget and InfoWidget to pydeck widget gallery example Demonstrates the two new 9.3 widgets: - PopupWidget: static HTML popup anchored at Heathrow Airport coordinates - InfoWidget: hover-mode widget (getTooltip callback must be set on the JS side) https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * Fix InfoWidget JSON registration and use @@= for getTooltip in example create-deck.js was overwriting InfoWidget, ThemeWidget, and LoadingWidget with undefined by referencing non-existent _-prefixed exports; those widgets are already captured by extractElements. Removed the incorrect entries. Update the widgets example to use @@= expression syntax for InfoWidget's getTooltip, and drop "new in 9.3" labels. https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * Register TimelineWidget in JSON converter configuration https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * Revert pydeck version bump to 0.9.2 Not ready for release yet; keep frontend locked to ~9.3.* but hold the Python package version at 0.9.2. https://claude.ai/code/session_012C1gkGaLFxk6HMvN4VMrST * fix(widgets): handle negative DMS degrees and guard InfoWidget tooltip expression The dmsToDecimal function miscalculated when degrees were negative with non-zero minutes/seconds (e.g. -37°48'00" → -36.2 instead of -37.8). Also guard the InfoWidget example's @@= expression against undefined object when hovering empty space. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(pydeck): add 0.9.3 changelog, whats-new section, and playground link Add pydeck 0.9.3 entry to CHANGELOG.rst, a pydeck subsection under deck.gl v9.3 whats-new, and link to the new pydeck playground from the pydeck docs index page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: remove pydeck section from deck.gl whats-new pydeck has its own docs site with CHANGELOG.rst as the canonical release notes location. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: move DMS fix to deck.gl whats-new patch notes The negative DMS parsing fix is a deck.gl core change, not a pydeck change. Move it to the v9.3 patch releases section in whats-new.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: remove patch release note from whats-new Patch fixes aren't historically documented in this file on master. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore(deps): bump bleach to 6.4.0 and jupyter-server to 2.20.0 Security updates for pydeck lockfile: - bleach 6.4.0: XSS fixes in URI/formaction sanitization (GHSA-8rfp-98v4-mmr6) - jupyter-server 2.20.0: CVE-2026-44727 (GHSA-fcw5-x6j4-ccmp) Supersedes #10390 and #10391. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 10c4c0c commit dc98eab

9 files changed

Lines changed: 122 additions & 43 deletions

File tree

bindings/pydeck/bump_version.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def bump(release_type):
3131

3232
def rewrite_version_file(semver):
3333
with open("pydeck/_version.py", "w+") as f:
34-
t = jinja2.Template("__version__ = '{{semver_str}}'")
34+
t = jinja2.Template('__version__ = "{{semver_str}}"')
3535
contents = t.render(semver_str=str(semver))
3636
f.write(contents)
3737

@@ -58,11 +58,13 @@ def rewrite_frontend_version_file():
5858
"""Current associated version of NPM modules deck.gl and @deck.gl/jupyter-widget"""
5959
with open("../../lerna.json") as f:
6060
lerna_version = json.loads(f.read())["version"]
61+
version_info = semver.parse_version_info(lerna_version)
62+
semver_range = "~{}.{}.*".format(version_info.major, version_info.minor)
6163
with open("pydeck/frontend_semver.py", "w+") as f:
62-
t = jinja2.Template("DECKGL_SEMVER = '{{semver_str}}'")
63-
contents = t.render(semver_str=str(lerna_version))
64+
t = jinja2.Template('DECKGL_SEMVER = "{{semver_str}}"')
65+
contents = t.render(semver_str=semver_range)
6466
f.write(contents)
65-
return lerna_version
67+
return semver_range
6668

6769

6870
parser = argparse.ArgumentParser(description="Bump semver for pydeck. Modifies pydeck/_version.py directly.")

bindings/pydeck/docs/CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ Releases and associated GitHub PRs for pydeck are documented here.
66
0.9 Releases
77
------------
88

9+
0.9.3 - Jul 2026
10+
^^^^^^^^^^^^^^^^^^^
11+
- Update to deck.gl v9.3 (#10242)
12+
- Add PopupWidget and InfoWidget to widget gallery example
13+
- Add pydeck playground at `deck.gl/pydeck <https://deck.gl/pydeck>`__
14+
915
0.9.2 - Apr 16 2026
1016
^^^^^^^^^^^^^^^^^^^
1117
- Update to deck.gl v9.2 (#9895)

bindings/pydeck/docs/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ Gallery
1616
Overview
1717
^^^^^^^^
1818

19+
`pydeck Playground <https://deck.gl/pydeck>`__
20+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
Try pydeck scripts directly in the browser with the `pydeck playground <https://deck.gl/pydeck>`__. No installation needed — edit Python code and see the visualization update in real time.
23+
1924
`pydeck in Jupyter <jupyter.html>`__
2025
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2126

bindings/pydeck/examples/widgets.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
- FullscreenWidget and ScreenshotWidget for utility
1010
- ScaleWidget for displaying map scale
1111
- StatsWidget for rendering performance stats
12+
- PopupWidget for anchored geographic popups
13+
- InfoWidget for hover/click-activated feature popups
1214
"""
1315

1416
import pydeck as pdk
@@ -54,6 +56,17 @@
5456
pdk.Widget("ScreenshotWidget"),
5557
pdk.Widget("ScaleWidget", placement="bottom-right"),
5658
pdk.Widget("StatsWidget", statsType="luma", placement="bottom-left"),
59+
# PopupWidget: static popup anchored to a geographic coordinate.
60+
# content accepts a string (plain text) or a dict with "text", "html", or "element".
61+
pdk.Widget(
62+
"PopupWidget",
63+
position=[-0.4543, 51.4775], # Heathrow Airport, London
64+
content={"html": "<strong>Heathrow Airport</strong><br/>London, United Kingdom"},
65+
placement="right",
66+
),
67+
# InfoWidget: popup triggered by hovering over pickable features.
68+
# getTooltip uses the @@= expression syntax from @deck.gl/json to access feature properties.
69+
pdk.Widget("InfoWidget", mode="hover", getTooltip="@@=object && object.properties && object.properties.name"),
5770
]
5871

5972
deck = pdk.Deck(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
DECKGL_SEMVER = "~9.2.*"
1+
DECKGL_SEMVER = "~9.3.*"

bindings/pydeck/uv.lock

Lines changed: 66 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

modules/jupyter-widget/src/playground/create-deck.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,12 @@ function extractElements(library = {}, filter) {
4242
const JSON_CONVERTER_CONFIGURATION = {
4343
classes: {
4444
...extractElements(deckExports, classesFilter),
45-
// Add experimental widgets (exported with _ prefix)
46-
FpsWidget: deckExports._FpsWidget,
45+
// Register widgets exported with _ prefix under their canonical names
4746
StatsWidget: deckExports._StatsWidget,
4847
ScaleWidget: deckExports._ScaleWidget,
4948
GeocoderWidget: deckExports._GeocoderWidget,
5049
SplitterWidget: deckExports._SplitterWidget,
51-
InfoWidget: deckExports._InfoWidget,
52-
ThemeWidget: deckExports._ThemeWidget,
53-
LoadingWidget: deckExports._LoadingWidget
50+
TimelineWidget: deckExports._TimelineWidget
5451
},
5552
// Will be resolved as `<enum-name>.<enum-value>`
5653
enumerations: {

modules/widgets/src/lib/geocode/geocoders.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,12 @@ function dmsToDecimal(s: string): number {
195195
const minutes = parseFloat(match[2]) || 0;
196196
const seconds = parseFloat(match[3]) || 0;
197197
const direction = match[4] || '';
198-
let dec = degrees + minutes / 60 + seconds / 3600;
198+
const sign = degrees < 0 ? -1 : 1;
199+
let dec = Math.abs(degrees) + minutes / 60 + seconds / 3600;
199200
if (/[SW]/i.test(direction)) {
200201
dec = -dec;
202+
} else {
203+
dec = sign * dec;
201204
}
202205
return dec;
203206
}

test/modules/widgets/geocoder-widget.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@ test('CoordinatesGeocoder.geocode - Handles DMS format correctly', async () => {
5151
}
5252
});
5353

54+
test('CoordinatesGeocoder.geocode - Handles negative DMS degrees correctly', async () => {
55+
const cases = [
56+
{
57+
input: '-37°48\'00\", 144°57\'47\"',
58+
expected: {latitude: -37.8, longitude: 144.96305555555556}
59+
},
60+
{
61+
input: '-33°51\'36\", -70°40\'12\"',
62+
expected: {latitude: -33.86, longitude: -70.67}
63+
}
64+
];
65+
66+
for (const {input, expected} of cases) {
67+
const result = await CoordinatesGeocoder.geocode(input);
68+
expect(result?.latitude, `geocode(${input}) latitude`).toBeCloseTo(expected.latitude, 4);
69+
expect(result?.longitude, `geocode(${input}) longitude`).toBeCloseTo(expected.longitude, 4);
70+
}
71+
});
72+
5473
test('CoordinatesGeocoder.geocode - Returns null for invalid inputs', async () => {
5574
const cases = [
5675
{input: 'not a coordinate', expected: null},

0 commit comments

Comments
 (0)