{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ipyleaflet: Interactive maps\n", "\n", "## A Jupyter - LeafletJS bridge\n", "\n", "## https://github.com/jupyter-widgets/ipyleaflet\n", "\n", "\n", "ipyleaflet is a jupyter interactive widget library which provides interactive maps to the Jupyter notebook.\n", "\n", "- MIT Licensed\n", "\n", "**Installation:**\n", "\n", "```bash\n", "conda install -c conda-forge ipyleaflet\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from __future__ import print_function\n", "\n", "from ipyleaflet import (\n", " Map,\n", " Marker, MarkerCluster,\n", " TileLayer, ImageOverlay,\n", " Polyline, Polygon, Rectangle, Circle, CircleMarker,\n", " Popup,\n", " GeoJSON,\n", " SplitMapControl, WidgetControl,\n", " basemaps,\n", " basemap_to_tiles\n", ")\n", "\n", "from ipywidgets import HTML" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "center = [34.6252978589571, -77.34580993652344]\n", "zoom = 10" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = Map(center=center, zoom=zoom)\n", "m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m.interact(zoom=(5, 10, 1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# jupyterlab-sidecar: A sidecar output widget for JupyterLab\n", "\n", "## https://github.com/jupyter-widgets/jupyterlab-sidecar" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sidecar import Sidecar\n", "\n", "sc = Sidecar(title='Map Output')\n", "with sc:\n", " display(m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m.clear_layers()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m.add_layer(basemaps.Esri.DeLorme)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(m.center)\n", "print(m.zoom)\n", "print(m.bounds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Marker" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark = Marker(location=m.center)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark.visible" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m += mark" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark.interact(opacity=(0.0,1.0,0.01))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark.visible" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark.visible = False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mark.visible = True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Popup\n", "\n", "The popup is displayed when you click on the marker. You can add ANY widget as a popup for the marker, from simple HTMLWidget to plots using bqplot." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ipywidgets import FloatSlider, link\n", "\n", "slider = FloatSlider(value=1.0, min=0.0, max=1.0)\n", "link((mark, 'opacity'), (slider, 'value'))\n", "\n", "mark.popup = slider" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Marker Cluster\n", "\n", "Markers can be clustered depending on the zoom level." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "xscale = 5\n", "yscale = 10\n", "\n", "x = [m.center[0] + i * xscale * .05 for i in (-1,0,1)]\n", "y = [m.center[1] + i * yscale * .05 for i in (-1,0,1)]\n", "\n", "from itertools import product\n", "locations = product(x, y)\n", "markers = [Marker(location=loc) for loc in locations]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `MarkerCluster` will automatically handle clustering and the zoom level changes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "marker_cluster = MarkerCluster(markers=markers)\n", "m += marker_cluster" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Controls" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following NASA images need a zoom level <= 9\n", "if m.zoom > 9:\n", " m.zoom = 9\n", "\n", "control = SplitMapControl(\n", " left_layer=basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, \"2017-11-11\") , \n", " right_layer=basemap_to_tiles(basemaps.NASAGIBS.ModisAquaBands721CR, \"2017-11-11\")\n", ")\n", "m.add_control(control)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m.remove_control(control)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ipywidgets import IntSlider, Button, link\n", "\n", "button = Button(description='Goto NYC')\n", "\n", "def goto_nyc(*args, **kwargs):\n", " # NYC: 40.7128° N, 74.0060° W\n", " m.center = (40.7128, -74.0060)\n", " m.zoom = 9\n", "\n", "button.on_click(goto_nyc)\n", "\n", "wid_control = WidgetControl(widget=button, position='bottomright')\n", "m.add_control(wid_control)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m.remove_control(wid_control)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Advanced example" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ipywidgets import Text, HTML, HBox\n", "from ipyleaflet import GeoJSON, WidgetControl, Map \n", "import json" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = Map(center = (43,-100), zoom = 4)\n", "\n", "geo_json_data = json.load(open('us-states-density-colored.json'))\n", "geojson = GeoJSON(data=geo_json_data, hover_style={'color': 'black', 'dashArray': '5, 5', 'weight': 2})\n", "m.add_layer(geojson)\n", "\n", "html = HTML('''\n", "

US population density

\n", " Hover over a state\n", "''')\n", "html.layout.margin = '0px 20px 20px 20px'\n", "control = WidgetControl(widget=html, position='topright')\n", "m.add_control(control)\n", "\n", "def update_html(properties, **kwargs):\n", " html.value = '''\n", "

US population density

\n", "

{}

\n", " {} people / mi^2\n", " '''.format(properties['name'], properties['density'])\n", "\n", "geojson.on_hover(update_html)\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1) Create a Map" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2) Create a slider controlling the zoom level of the Map (manually, not using interact)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3) Embed the slider in a WidgetControl on the bottom left of the map" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "widgets-tutorial", "language": "python", "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }