from __future__ import print_function
from leafletwidget import (
Map,
Marker,
TileLayer, ImageOverlay,
Polyline, Polygon, Rectangle, Circle, CircleMarker,
GeoJSON,
DrawControl
)
from leafletwidget import initialize_notebook
from IPython.html import widgets
from IPython.display import display
from IPython.utils.traitlets import link
# Run this if you have an internet connection
initialize_notebook()
# Run this if you have installed the JS/CSS in $HOME/.ipython/nbextensions
initialize_notebook(leaflet_url='/nbextensions/leaflet-0.7.2',
leaflet_draw_url='/nbextensions/leaflet.draw/0.2.3')
center = [34.6252978589571, -77.34580993652344]
zoom = 10
c = widgets.ContainerWidget()
m = Map(width='600px',height='400px', center=center, zoom=zoom)
c.children = [m]
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-17-8b9d4498a04c> in <module>() 1 c = widgets.ContainerWidget() ----> 2 m = Map(width='600px',height='400px', center=center, zoom=zoom) 3 c.children = [m] /usr/local/lib/python2.7/site-packages/leafletwidget-0.1-py2.7.egg/leafletwidget/leaflet.pyc in __init__(self, **kwargs) 320 self.on_displayed(self._fire_children_displayed) 321 if self.default_tiles is not None: --> 322 self.layers = (self.default_tiles,) 323 self.on_msg(self._handle_leaflet_event) 324 /Library/Python/2.7/site-packages/IPython/utils/traitlets.pyc in __set__(self, obj, value) 380 # we explicitly compare silent to True just in case the equality 381 # comparison above returns something other than True/False --> 382 obj._notify_trait(self.name, old_value, new_value) 383 384 def _validate(self, obj, value): /Library/Python/2.7/site-packages/IPython/utils/traitlets.pyc in _notify_trait(self, name, old_value, new_value) 529 c(name, new_value) 530 elif nargs + offset == 3: --> 531 c(name, old_value, new_value) 532 else: 533 raise TraitError('a trait changed callback ' /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in _handle_property_changed(self, name, old, new) 296 if self._should_send_property(name, new): 297 # Send new state to front-end --> 298 self.send_state(key=name) 299 300 def _handle_displayed(self, **kwargs): /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in send_state(self, key) 186 self._send({ 187 "method" : "update", --> 188 "state" : self.get_state() 189 }) 190 /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in _send(self, msg) 339 def _send(self, msg): 340 """Sends a message to the model in the front-end.""" --> 341 self.comm.send(msg) 342 343 /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in comm(self) 147 148 # first update --> 149 self.send_state() 150 return self._comm 151 /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in send_state(self, key) 186 self._send({ 187 "method" : "update", --> 188 "state" : self.get_state() 189 }) 190 /Library/Python/2.7/site-packages/IPython/html/widgets/widget.pyc in _send(self, msg) 339 def _send(self, msg): 340 """Sends a message to the model in the front-end.""" --> 341 self.comm.send(msg) 342 343 /Library/Python/2.7/site-packages/IPython/kernel/comm/comm.pyc in send(self, data, metadata) 101 def send(self, data=None, metadata=None): 102 """Send a message to the frontend-side version of this comm""" --> 103 self._publish_msg('comm_msg', data, metadata) 104 105 # registering callbacks /Library/Python/2.7/site-packages/IPython/kernel/comm/comm.pyc in _publish_msg(self, msg_type, data, metadata, **keys) 74 metadata=metadata, 75 parent=self.shell.get_parent(), ---> 76 ident=self.topic, 77 ) 78 /Library/Python/2.7/site-packages/IPython/kernel/zmq/session.pyc in send(self, stream, msg_or_type, content, parent, ident, buffers, track, header, metadata) 633 return 634 buffers = [] if buffers is None else buffers --> 635 to_send = self.serialize(msg, ident) 636 to_send.extend(buffers) 637 longest = max([ len(s) for s in to_send ]) /Library/Python/2.7/site-packages/IPython/kernel/zmq/session.pyc in serialize(self, msg, ident) 540 content = self.none 541 elif isinstance(content, dict): --> 542 content = self.pack(content) 543 elif isinstance(content, bytes): 544 # content is already packed, as in a relayed message /Library/Python/2.7/site-packages/IPython/kernel/zmq/session.pyc in <lambda>(obj) 81 82 # ISO8601-ify datetime objects ---> 83 json_packer = lambda obj: jsonapi.dumps(obj, default=date_default) 84 json_unpacker = lambda s: jsonapi.loads(s) 85 /usr/local/lib/python2.7/site-packages/zmq/utils/jsonapi.pyc in dumps(o, **kwargs) 53 kwargs['separators'] = (',', ':') 54 ---> 55 s = jsonmod.dumps(o, **kwargs) 56 57 if isinstance(s, unicode): /usr/local/Cellar/python/2.7.8_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.pyc in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, encoding, default, sort_keys, **kw) 248 check_circular=check_circular, allow_nan=allow_nan, indent=indent, 249 separators=separators, encoding=encoding, default=default, --> 250 sort_keys=sort_keys, **kw).encode(obj) 251 252 /usr/local/Cellar/python/2.7.8_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.pyc in encode(self, o) 205 # exceptions aren't as detailed. The list call should be roughly 206 # equivalent to the PySequence_Fast that ''.join() would do. --> 207 chunks = self.iterencode(o, _one_shot=True) 208 if not isinstance(chunks, (list, tuple)): 209 chunks = list(chunks) /usr/local/Cellar/python/2.7.8_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.pyc in iterencode(self, o, _one_shot) 268 self.key_separator, self.item_separator, self.sort_keys, 269 self.skipkeys, _one_shot) --> 270 return _iterencode(o, 0) 271 272 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, /Library/Python/2.7/site-packages/IPython/utils/jsonutil.pyc in date_default(obj) 113 return obj.isoformat() 114 else: --> 115 raise TypeError("%r is not JSON serializable"%obj) 116 117 TypeError: <leafletwidget.leaflet.TileLayer object at 0x1070e9f90> is not JSON serializable
display(c)
m.zoom
Now create the DrawControl
and add it to the Map
using add_control
. We also register a handler for draw events. This will fire when a drawn path is created, edited or deleted (there are the actions). The geo_json
argument is the serialized geometry of the drawn path, along with its embedded style.
dc = DrawControl()
def handle_draw(self, action, geo_json):
print(action)
print(geo_json)
dc.on_draw(handle_draw)
m.add_control(dc)
In addition, the DrawControl
also has last_action
and last_draw
attributes that are created dynamicaly anytime a new drawn path arrives.
dc.last_action
dc.last_draw
Let's draw a second map and try to import this GeoJSON data into it.
m2 = Map(width='600px',height='400px', center=center, zoom=zoom)
display(m2)
We can use link
to synchronize traitlets of the two maps:
map_center_link = link((m,'center'),(m2,'center'))
map_zoom_link = link((m,'zoom'),(m2,'zoom'))
new_poly = GeoJSON(data=dc.last_draw)
m2.add_layer(new_poly)
Note that the style is preserved! If you wanted to change the style, you could edit the properties.style
dictionary of the GeoJSON data. Or, you could even style the original path in the DrawControl
by setting the polygon
dictionary of that object. See the code for details.
Now let's add a DrawControl
to this second map. For fun we will disable lines and enable circles as well and change the style a bit.
dc2 = DrawControl(polygon={'shapeOptions':{'color':'#00F'}}, polyline={},
circle={'shapeOptions':{'color':'#00F'}})
m2.add_control(dc2)