Skip to content

Commit

Permalink
Example of using Folium in Panel - Notebook for Gallery (#1189)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcSkovMadsen authored Apr 3, 2020
1 parent 9fb95e3 commit aa14739
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 2 deletions.
196 changes: 196 additions & 0 deletions examples/gallery/external/Folium.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Demonstrates the use of [`Folium`](https://python-visualization.github.io/folium/) in Panel."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import folium as fm\n",
"import pandas as pd\n",
"import param\n",
"import panel as pn\n",
"import random\n",
"pn.extension()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can use `Folium` directly in a Jupyter Notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_map(lat=20.5936832, long=78.962883, zoom_start=5):\n",
" return fm.Map(location=[lat,long], zoom_start=zoom_start)\n",
"\n",
"map = get_map()\n",
"\n",
"pn.panel(map)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Interactive Panel app using Folium\n",
"\n",
"Let build an interactive Panel application using Folium.\n",
"\n",
"Lets **define some data**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_df_aqi(lat_bounds=(10,30), long_bounds=(70,90), points_count=40):\n",
" aqi = {\n",
" \"Latitude\": [random.uniform(*lat_bounds) for _ in range(0,points_count)],\n",
" \"Longitude\": [random.uniform(*long_bounds) for _ in range(0,points_count)],\n",
" \"AQI\": [random.uniform(0,500) for _ in range(0,points_count)],\n",
" }\n",
" return pd.DataFrame(aqi)\n",
"\n",
"df_aqi = get_df_aqi()\n",
"df_aqi.sample(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets define some functionality to **add the data to the map** as circles"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def add_aqi_circles(map, df_aqi):\n",
" green_p1 = fm.map.FeatureGroup()\n",
" yellow_p1 = fm.map.FeatureGroup()\n",
" orange_p1 = fm.map.FeatureGroup()\n",
" red_p1 = fm.map.FeatureGroup()\n",
" purple_p1 = fm.map.FeatureGroup()\n",
" maroon_p1 = fm.map.FeatureGroup()\n",
"\n",
" for _, row in df_aqi.iterrows():\n",
" if row.AQI<50:\n",
" feature_group = green_p1\n",
" fill_color = \"green\"\n",
" elif row.AQI < 100:\n",
" feature_group = yellow_p1\n",
" fill_color = \"yellow\"\n",
" elif row.AQI < 150:\n",
" feature_group = orange_p1\n",
" fill_color = \"orange\"\n",
" elif row.AQI < 200:\n",
" feature_group = red_p1\n",
" fill_color = \"red\"\n",
" elif row.AQI < 300:\n",
" feature_group = purple_p1\n",
" fill_color='purple'\n",
" else:\n",
" feature_group = maroon_p1\n",
" fill_color = \"maroon\"\n",
"\n",
" feature_group.add_child(\n",
" fm.CircleMarker(\n",
" [row.Latitude, row.Longitude],\n",
" radius=10, \n",
" fill=True,\n",
" fill_color=fill_color,\n",
" fill_opacity=0.7\n",
" )\n",
" )\n",
"\n",
" map.add_child(green_p1)\n",
" map.add_child(yellow_p1)\n",
" map.add_child(orange_p1)\n",
" map.add_child(red_p1)\n",
" map.add_child(purple_p1)\n",
"\n",
"add_aqi_circles(map, df_aqi)\n",
"pn.panel(map)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets put it all together into an **interactive app** where the user can select the number of data points to generate and display."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class PanelFoliumMap(param.Parameterized):\n",
" points_count = param.Integer(20, bounds=(10,100))\n",
" \n",
" def __init__(self, **params):\n",
" super().__init__(**params)\n",
" self.map = get_map()\n",
" self.html_pane = pn.pane.HTML(sizing_mode=\"stretch_width\", min_height=600) \n",
" self.view = pn.Column(\n",
" self.param.points_count,\n",
" self.html_pane,\n",
" sizing_mode=\"stretch_width\", min_height=600,\n",
" )\n",
" self._update_map()\n",
"\n",
" @param.depends(\"points_count\", watch=True)\n",
" def _update_map(self):\n",
" self.map = get_map()\n",
" df_aqi = get_df_aqi(points_count=self.points_count)\n",
" add_aqi_circles(self.map, df_aqi)\n",
" self.html_pane.object = self.map\n",
"\n",
" \n",
"app = PanelFoliumMap()\n",
"app.view.embed()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"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.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
17 changes: 17 additions & 0 deletions panel/pane/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,20 @@ def _get_properties(self):
if self.height is None: p["height"] = height

return p


class Folium(HTML):
"""
The Folium pane wraps Folium map components.
"""

sizing_mode = param.ObjectSelector(default='stretch_width', objects=[
'fixed', 'stretch_width', 'stretch_height', 'stretch_both',
'scale_width', 'scale_height', 'scale_both', None])

priority = 0.6

@classmethod
def applies(cls, obj):
return (getattr(obj, '__module__', '').startswith('folium.') and
hasattr(obj, "_repr_html_"))
3 changes: 2 additions & 1 deletion panel/viewable.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ def __init__(self, **params):
params.get('height_policy') is None and
'sizing_mode' not in params):
params['sizing_mode'] = 'fixed'
elif not self.param.sizing_mode.constant and not self.param.sizing_mode.readonly:
elif (not (self.param.sizing_mode.constant or self.param.sizing_mode.readonly) and
type(self).sizing_mode is None):
params['sizing_mode'] = params.get('sizing_mode', config.sizing_mode)
super(Layoutable, self).__init__(**params)

Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ def run(self):
'scipy',
'nbsmoke >=0.2.0',
'pytest-cov',
'codecov'
'codecov',
'folium',
]

extras_require = {
Expand Down

0 comments on commit aa14739

Please sign in to comment.