Skip to content

Commit 8d90f0a

Browse files
Country dropdown (#5)
Co-authored-by: Benjamin Szeghy <benjamin.szeghy@berkeley.edu>
1 parent 1c48538 commit 8d90f0a

6 files changed

Lines changed: 109 additions & 34 deletions

File tree

prototype_gui2cell/data/ne_110m_admin_0_countries.geojson

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

prototype_gui2cell/widget.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
from pathlib import Path
2+
13
from ipywidgets import DOMWidget
24
from traitlets import Unicode
35

46
MODULE_NAME = "prototype-gui2cell"
57
MODULE_VERSION = "^0.1.0"
68

9+
ADMIN_BOUNDARIES_GEOJSON_FILE = (
10+
Path(__file__).parent / "data" / "ne_110m_admin_0_countries.geojson"
11+
)
12+
ADMIN_BOUNDARIES_GEOJSON = ADMIN_BOUNDARIES_GEOJSON_FILE.read_text()
13+
714

815
class Gui2CellWidget(DOMWidget):
916
# TODO: Set module name and version
@@ -15,3 +22,7 @@ class Gui2CellWidget(DOMWidget):
1522
_view_module_version = Unicode(MODULE_VERSION).tag(sync=True)
1623

1724
value = Unicode("Hello World").tag(sync=True)
25+
26+
# Probably no good reason to pass this data from Python to JS...
27+
# Only needs to be synced unidirectionally, do we need the sync tag?
28+
admin_boundaries_geojson = Unicode(ADMIN_BOUNDARIES_GEOJSON).tag(sync=True)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ classifiers = [
2323
"Programming Language :: Python :: 3.14",
2424
]
2525
dependencies = [
26+
"ipyleaflet>=0.20.0",
2627
"ipywidgets>=8.1.8",
2728
"traitlets>=5.14.3",
2829
]

src/widget.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,32 +42,62 @@ export class ExampleModel extends DOMWidgetModel {
4242
export class ExampleView extends DOMWidgetView {
4343
static tracker: INotebookTracker;
4444

45+
private select!: HTMLSelectElement;
4546
private button!: HTMLButtonElement;
4647
private textarea!: HTMLTextAreaElement;
4748

4849
render() {
50+
// TODO: Type as GeoJSON (@types/geojson)
51+
const adminBoundariesGeoJson: any = JSON.parse(
52+
this.model.get('admin_boundaries_geojson')
53+
);
54+
const countries = adminBoundariesGeoJson['features']
55+
.map((f: any) => f['properties']['NAME'] as string)
56+
.sort();
57+
4958
this.textarea = document.createElement('textarea');
5059
this.textarea.value = this.model.get('value');
5160

5261
this.button = document.createElement('button');
53-
this.button.textContent = 'test'; //this.model.get('value');
62+
this.button.textContent = 'Export to Python code cell';
63+
64+
this.select = document.createElement('select');
65+
for (const country of countries) {
66+
const option = document.createElement('option');
67+
option.textContent = country;
68+
this.select.appendChild(option);
69+
}
70+
71+
const notebook = ExampleView.tracker?.currentWidget?.content;
5472

5573
this.button.onclick = () => {
56-
const notebook = ExampleView.tracker?.currentWidget?.content;
5774
if (!notebook?.model) {
5875
return;
59-
}
76+
} // Should never happen; just a typeguard
77+
78+
const geoJson = adminBoundariesGeoJson['features'].find(
79+
(f: any) => f['properties']['NAME'] === this.select.value
80+
);
81+
const codeCellContents =
82+
`print('${String(this.textarea.value)}')\n` +
83+
'from ipyleaflet import Map, GeoJSON\n' +
84+
'import json\n' +
85+
'm = Map()\n' +
86+
`m.add(GeoJSON(data=json.loads("""${JSON.stringify(geoJson)}""")))\n` +
87+
'm';
88+
6089
notebook.model.sharedModel.insertCell(
6190
notebook.widgets.findIndex(cell => cell.node.contains(this.el)) + 1,
6291
{
6392
cell_type: 'code',
64-
source: "print('" + String(this.textarea.value) + "')",
93+
source: codeCellContents,
6594
metadata: {}
6695
}
6796
);
6897
};
6998

7099
this.el.appendChild(this.textarea);
100+
this.el.appendChild(this.select);
71101
this.el.appendChild(this.button);
72102
this.el.classList.add('custom-widget');
73103
this.model.on('change:value', this.value_changed, this);

test.ipynb

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
{
22
"cells": [
3-
{
4-
"cell_type": "code",
5-
"execution_count": null,
6-
"id": "f02609c1-d2ec-452a-8217-4125d8dcbb52",
7-
"metadata": {},
8-
"outputs": [],
9-
"source": [
10-
"1 + 1"
11-
]
12-
},
133
{
144
"cell_type": "code",
155
"execution_count": null,
@@ -20,26 +10,8 @@
2010
"from prototype_gui2cell import Gui2CellWidget\n",
2111
"\n",
2212
"w = Gui2CellWidget()\n",
23-
"w # Hello world!"
24-
]
25-
},
26-
{
27-
"cell_type": "code",
28-
"execution_count": null,
29-
"id": "e6312644-d1fd-4f0a-99e0-3b543bd417c7",
30-
"metadata": {},
31-
"outputs": [],
32-
"source": [
33-
"w.value = \"Foo\" # This should update the widget text"
13+
"w"
3414
]
35-
},
36-
{
37-
"cell_type": "code",
38-
"execution_count": null,
39-
"id": "0a44bf30-6583-4f02-b31b-922b1119a4e2",
40-
"metadata": {},
41-
"outputs": [],
42-
"source": []
4315
}
4416
],
4517
"metadata": {
@@ -58,7 +30,7 @@
5830
"name": "python",
5931
"nbconvert_exporter": "python",
6032
"pygments_lexer": "ipython3",
61-
"version": "3.12.3"
33+
"version": "3.14.0"
6234
}
6335
},
6436
"nbformat": 4,

uv.lock

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

0 commit comments

Comments
 (0)