{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import param\n", "import pandas as pd\n", "import panel as pn\n", "import numpy as np\n", "\n", "from panel.reactive import ReactiveHTML\n", "\n", "CSS = ['https://unpkg.com/leaflet@1.7.1/dist/leaflet.css']\n", "\n", "JS = {\n", " 'leaflet': 'https://unpkg.com/leaflet@1.7.1/dist/leaflet.js',\n", " 'heat': 'https://cdn.jsdelivr.net/npm/leaflet.heat@0.2.0/dist/leaflet-heat.min.js'\n", "}\n", "\n", "pn.extension(css_files=CSS, js_files=JS)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class LeafletHeatMap(ReactiveHTML):\n", " \n", " attribution = param.String(doc=\"Tile source attribution.\")\n", " \n", " blur = param.Integer(default=18, bounds=(5, 50), doc=\"Amount of blur to apply to heatmap\")\n", " \n", " center = param.XYCoordinates(default=(0, 0), doc=\"The center of the map.\")\n", " \n", " data = param.DataFrame(doc=\"The heatmap data to plot, should have 'x', 'y' and 'value' columns.\")\n", " \n", " tile_url = param.String(doc=\"Tile source URL with {x}, {y} and {z} parameter\")\n", " \n", " min_alpha = param.Number(default=0.2, bounds=(0, 1), doc=\"Minimum alpha of the heatmap\")\n", " \n", " radius = param.Integer(default=25, bounds=(5, 50), doc=\"The radius of heatmap values on the map\")\n", " \n", " x = param.String(default='longitude', doc=\"Column in the data with longitude coordinates\")\n", " \n", " y = param.String(default='latitude', doc=\"Column in the data with latitude coordinates\")\n", " \n", " value = param.String(doc=\"Column in the data with the data values\")\n", " \n", " zoom = param.Integer(default=13, bounds=(0, 21), doc=\"The plots zoom-level\")\n", "\n", " _template = \"\"\"\n", "
\n", " \"\"\"\n", " \n", " _scripts = {\n", " 'get_data': \"\"\"\n", " const records = []\n", " for (let i=0; i { data.zoom = state.map.getZoom() }) \n", " state.tileLayer = L.tileLayer(data.tile_url, {\n", " attribution: data.attribution,\n", " maxZoom: 21,\n", " tileSize: 512,\n", " zoomOffset: -1,\n", " }).addTo(state.map);\n", " \"\"\",\n", " 'after_layout': \"\"\"\n", " state.map.invalidateSize()\n", " state.heatLayer = L.heatLayer(self.get_data(), {blur: data.blur, radius: data.radius, max: 10, minOpacity: data.min_alpha}).addTo(state.map)\n", " \"\"\",\n", " 'radius': \"state.heatLayer.setOptions({radius: data.radius})\",\n", " 'blur': \"state.heatLayer.setOptions({blur: data.blur})\",\n", " 'min_alpha': \"state.heatLayer.setOptions({minOpacity: data.min_alpha})\",\n", " 'zoom': \"state.map.setZoom(data.zoom)\",\n", " 'data': 'state.heatLayer.setLatLngs(self.get_data())'\n", " }\n", " \n", " __css__ = CSS\n", " \n", " __javascript__ = list(JS.values())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "url=\"http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv\"\n", "earthquakes = pd.read_csv(url)\n", "\n", "heatmap = LeafletHeatMap(\n", " attribution='Map data © OpenStreetMap contributors',\n", " data=earthquakes[['longitude', 'latitude', 'mag']],\n", " min_height=500,\n", " tile_url='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.jpg',\n", " radius=30,\n", " sizing_mode='stretch_both',\n", " value='mag',\n", " zoom=2,\n", ")\n", "\n", "description=pn.pane.Markdown(f'## Earthquakes between {earthquakes.time.min()} and {earthquakes.time.max()}\\n\\n[Data Source]({url})', sizing_mode=\"stretch_width\")\n", "\n", "pn.Column(\n", " description,\n", " pn.Row(\n", " heatmap.controls(['blur', 'min_alpha', 'radius', 'zoom']),\n", " heatmap,\n", " sizing_mode='stretch_both'\n", " ),\n", " sizing_mode='stretch_both'\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## App\n", "\n", "Let's wrap it into nice template that can be served via `panel serve LeafletHeatMap.ipynb`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.template.FastListTemplate(\n", " site=\"Panel\", title=\"Leaflet Heat Map\", \n", " sidebar=[heatmap.controls(['blur', 'min_alpha', 'radius', 'zoom'])], \n", " main=[description, pn.Row(heatmap, sizing_mode=\"stretch_both\")]\n", ").servable();" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 4 }