Reactive Python-Javascript communication in Jupyter Notebook

Tom Grek
Tom Grek
Nov 23, 2017 · 6 min read
This is the state of MapboxGL embedding today with the mapboxgl-jupyter library.
<iframe id="map" ,="" srcdoc="<!DOCTYPE html>
<html>
<head>
<title>mapboxgl-jupyter viz</title>
<meta charset='UTF-8' />
<meta name='viewport'
content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script type='text/javascript'
src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.41.0/mapbox-gl.js'></script>
...map.on('load', function() {

map.addSource('data', {
'type': 'geojson',
'data': {'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {'Avg Medicare Payments': 7678.21, 'Avg Covered Charges': 35247.03}, 'geometry': {'type': 'Point', 'coordinates': [-85.3629, 31.2162]}}, {'type': 'Feature', 'properties': {'Avg Medicare Payments': 5793.63, 'Avg Covered Charges': 16451.09}, 'geometry': {'type': 'Point', 'coordinates': [-88.1428, 32.453]}}, {'type': 'Feature', 'properties': {'Avg Medicare Payments': 7145.96, 'Avg Covered Charges': 36942.36}, 'geometry': {'type': 'Point', 'coordinates': [-87.6829, 34.7941]}},
[... etc!]

Jupyter’s internals

jupyter nbextension enable — py widgetsnbextension

Python variables triggering Javascript events

Embedding Javascript in Python

from IPython.core.display import HTML
HTML("<script>console.log('Hello, world!');</script>")
from IPython.core.display import Javascript
Javascript("alert('Hello, world!')")

Turning it into a standalone module

import ipywidgets as widgets
class MapboxWidget(widgets.DOMWidget):
from traitlets import Dict, Unicode
_view_name = Unicode('MapboxGLView').tag(sync=True)
_view_module = Unicode('mapboxglModule').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
value = Dict({"my_key": "Hello"}).tag(sync=True)
def create(self):
from IPython.core.display import Javascript
return Javascript("""
require.undef('mapboxglModule');
define('mapboxglModule', ["@jupyter-widgets/base"], widgets => {
let MapboxGLView = widgets.DOMWidgetView.extend({
defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, { value: '' }),
render: function() {
this.value_changed();
this.model.on('change:value', this.value_changed, this);
},
value_changed: function() {
this.el.textContent = this.model.get('value').my_key;
},
});
return {
MapboxGLView,
};
});
""")

Output and usage

Start with this — note the contents of cell [75]
Next we update the value…
What!!!???! Did that just reactively update? Yeah!!

Tom Grek

Written by

Tom Grek

Engineer in the NLP/AI space. Maker, hacker, MS EE. AGI enthusiast. Traveler and nature lover. Opinions are my own.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade