Skip to content

Added SideBySide plugin basic funcionality #1032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions examples/SideBySide.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import folium\n",
"from folium import TileLayer, WmsTileLayer\n",
"from folium.plugins import SideBySide"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVM9ZmFsc2U7IExfTk9fVE9VQ0g9ZmFsc2U7IExfRElTQUJMRV8zRD1mYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4zLjQvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4zLjQvZGlzdC9sZWFmbGV0LmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC10aGVtZS5taW4uY3NzIi8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9MZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy8yLjAuMi9sZWFmbGV0LmF3ZXNvbWUtbWFya2Vycy5jc3MiLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9yYXdjZG4uZ2l0aGFjay5jb20vcHl0aG9uLXZpc3VhbGl6YXRpb24vZm9saXVtL21hc3Rlci9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUuY3NzIi8+CiAgICA8c3R5bGU+aHRtbCwgYm9keSB7d2lkdGg6IDEwMCU7aGVpZ2h0OiAxMDAlO21hcmdpbjogMDtwYWRkaW5nOiAwO308L3N0eWxlPgogICAgPHN0eWxlPiNtYXAge3Bvc2l0aW9uOmFic29sdXRlO3RvcDowO2JvdHRvbTowO3JpZ2h0OjA7bGVmdDowO308L3N0eWxlPgogICAgCiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLAogICAgICAgIGluaXRpYWwtc2NhbGU9MS4wLCBtYXhpbXVtLXNjYWxlPTEuMCwgdXNlci1zY2FsYWJsZT1ubyIgLz4KICAgIDxzdHlsZT4jbWFwX2ZkMGYyOWJiMTU3NzRkYTdhZWQ1MTMzZWRiZGYwZDNkIHsKICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgICAgICAgd2lkdGg6IDEwMC4wJTsKICAgICAgICBoZWlnaHQ6IDEwMC4wJTsKICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgIHRvcDogMC4wJTsKICAgICAgICB9CiAgICA8L3N0eWxlPgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vcmF3Y2RuLmdpdGhhY2suY29tL2RpZ2lkZW0vbGVhZmxldC1zaWRlLWJ5LXNpZGUvZ2gtcGFnZXMvbGVhZmxldC1zaWRlLWJ5LXNpZGUuanMiPjwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgPGRpdiBjbGFzcz0iZm9saXVtLW1hcCIgaWQ9Im1hcF9mZDBmMjliYjE1Nzc0ZGE3YWVkNTEzM2VkYmRmMGQzZCIgPjwvZGl2Pgo8L2JvZHk+CjxzY3JpcHQ+ICAgIAogICAgCiAgICAKICAgICAgICB2YXIgYm91bmRzID0gbnVsbDsKICAgIAoKICAgIHZhciBtYXBfZmQwZjI5YmIxNTc3NGRhN2FlZDUxMzNlZGJkZjBkM2QgPSBMLm1hcCgKICAgICAgICAnbWFwX2ZkMGYyOWJiMTU3NzRkYTdhZWQ1MTMzZWRiZGYwZDNkJywgewogICAgICAgIGNlbnRlcjogWzQwLCAtMTAwXSwKICAgICAgICB6b29tOiA0LAogICAgICAgIG1heEJvdW5kczogYm91bmRzLAogICAgICAgIGxheWVyczogW10sCiAgICAgICAgd29ybGRDb3B5SnVtcDogZmFsc2UsCiAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NywKICAgICAgICB6b29tQ29udHJvbDogdHJ1ZSwKICAgICAgICB9KTsKCgogICAgCiAgICB2YXIgdGlsZV9sYXllcl9mM2VlNWIwNGU0ODA0ODBkYWZmMWQ0YWJiY2Q3Yjc4ZiA9IEwudGlsZUxheWVyKAogICAgICAgICdodHRwczovL3tzfS50aWxlLm9wZW5zdHJlZXRtYXAub3JnL3t6fS97eH0ve3l9LnBuZycsCiAgICAgICAgewogICAgICAgICJhdHRyaWJ1dGlvbiI6IG51bGwsCiAgICAgICAgImRldGVjdFJldGluYSI6IGZhbHNlLAogICAgICAgICJtYXhOYXRpdmVab29tIjogMTgsCiAgICAgICAgIm1heFpvb20iOiAxOCwKICAgICAgICAibWluWm9vbSI6IDAsCiAgICAgICAgIm5vV3JhcCI6IGZhbHNlLAogICAgICAgICJvcGFjaXR5IjogMSwKICAgICAgICAic3ViZG9tYWlucyI6ICJhYmMiLAogICAgICAgICJ0bXMiOiBmYWxzZQp9KS5hZGRUbyhtYXBfZmQwZjI5YmIxNTc3NGRhN2FlZDUxMzNlZGJkZjBkM2QpOwogICAgdmFyIHRpbGVfbGF5ZXJfNzdiNTE3ZGFkMjcyNDEzZGIyNzBkMjE3ODBmOTdmMmUgPSBMLnRpbGVMYXllcigKICAgICAgICAnaHR0cDovL3tzfS5nb29nbGUuY29tL3Z0L2x5cnM9bSZ4PXt4fSZ5PXt5fSZ6PXt6fScsCiAgICAgICAgewogICAgICAgICJhdHRyaWJ1dGlvbiI6ICJnb29nbGUiLAogICAgICAgICJkZXRlY3RSZXRpbmEiOiBmYWxzZSwKICAgICAgICAibWF4TmF0aXZlWm9vbSI6IDIwLAogICAgICAgICJtYXhab29tIjogMjAsCiAgICAgICAgIm1pblpvb20iOiAwLAogICAgICAgICJub1dyYXAiOiBmYWxzZSwKICAgICAgICAib3BhY2l0eSI6IDEsCiAgICAgICAgInN1YmRvbWFpbnMiOiBbCiAgICAgICAgICAgICAgICAibXQwIiwKICAgICAgICAgICAgICAgICJtdDEiLAogICAgICAgICAgICAgICAgIm10MiIsCiAgICAgICAgICAgICAgICAibXQzIgogICAgICAgIF0sCiAgICAgICAgInRtcyI6IGZhbHNlCn0pLmFkZFRvKG1hcF9mZDBmMjliYjE1Nzc0ZGE3YWVkNTEzM2VkYmRmMGQzZCk7CiAgICAKICAgICAgICAgICAgdmFyIG1hY3JvX2VsZW1lbnRfZDkwZTA5ZmY3YzcxNGJiZWJkYjcyM2RmN2RiYjg0YjcgPSBMLnRpbGVMYXllci53bXMoCiAgICAgICAgICAgICAgICAnaHR0cDovL21lc29uZXQuYWdyb24uaWFzdGF0ZS5lZHUvY2dpLWJpbi93bXMvbmV4cmFkL24wci5jZ2knLAogICAgICAgICAgICAgICAgewogICJhdHRyaWJ1dGlvbiI6ICJXZWF0aGVyIGRhdGEgXHUwMGE5IDIwMTIgSUVNIE5leHJhZCIsCiAgImZvcm1hdCI6ICJpbWFnZS9wbmciLAogICJsYXllcnMiOiAibmV4cmFkLW4wci05MDA5MTMiLAogICJzdHlsZXMiOiAiIiwKICAidHJhbnNwYXJlbnQiOiB0cnVlLAogICJ2ZXJzaW9uIjogIjEuMS4xIgp9CiAgICAgICAgICAgICAgICApLmFkZFRvKG1hcF9mZDBmMjliYjE1Nzc0ZGE3YWVkNTEzM2VkYmRmMGQzZCk7CgogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgc2lkZV9ieV9zaWRlX2ViZWI5YzExNzZjMzQxZGJiOTQ5NjI4OGQ4MjNmYmQ4ID0gbmV3IEwuQ29udHJvbC5TaWRlQnlTaWRlKAogICAgICAgICAgICB0aWxlX2xheWVyXzc3YjUxN2RhZDI3MjQxM2RiMjcwZDIxNzgwZjk3ZjJlLCBtYWNyb19lbGVtZW50X2Q5MGUwOWZmN2M3MTRiYmViZGI3MjNkZjdkYmI4NGI3KTsKICAgICAgICAgICAgbWFwX2ZkMGYyOWJiMTU3NzRkYTdhZWQ1MTMzZWRiZGYwZDNkLmFkZENvbnRyb2woc2lkZV9ieV9zaWRlX2ViZWI5YzExNzZjMzQxZGJiOTQ5NjI4OGQ4MjNmYmQ4KTsKCiAgICAgICAgCjwvc2NyaXB0Pg==\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
],
"text/plain": [
"<folium.folium.Map at 0x391ab70>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"m = folium.Map(location=[40, -100], zoom_start=4)\n",
"\n",
"left_layer = folium.raster_layers.TileLayer(\n",
" tiles='http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',\n",
" attr='google',\n",
" name='google street view',\n",
" max_zoom=20,\n",
" subdomains=['mt0', 'mt1', 'mt2', 'mt3'],\n",
" overlay=False,\n",
" control=True,\n",
").add_to(m)\n",
"\n",
"right_layer = folium.raster_layers.WmsTileLayer(\n",
" url='http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi',\n",
" name='test',\n",
" fmt='image/png',\n",
" layers='nexrad-n0r-900913',\n",
" attr=u'Weather data © 2012 IEM Nexrad',\n",
" transparent=True,\n",
" overlay=True,\n",
" control=True,\n",
").add_to(m)\n",
"\n",
"sbs = SideBySide(left_layer, right_layer)\n",
"m.add_child(sbs)"
]
}
],
"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.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 2 additions & 0 deletions folium/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from folium.plugins.polyline_text_path import PolyLineTextPath
from folium.plugins.scroll_zoom_toggler import ScrollZoomToggler
from folium.plugins.search import Search
from folium.plugins.side_by_side import SideBySide
from folium.plugins.terminator import Terminator
from folium.plugins.time_slider_choropleth import TimeSliderChoropleth
from folium.plugins.timestamped_geo_json import TimestampedGeoJson
Expand All @@ -48,6 +49,7 @@
'PolyLineTextPath',
'ScrollZoomToggler',
'Search',
'SideBySide',
'Terminator',
'TimeSliderChoropleth',
'TimestampedGeoJson',
Expand Down
97 changes: 97 additions & 0 deletions folium/plugins/side_by_side.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)

from branca.element import Figure, JavascriptLink, MacroElement
from jinja2 import Template
from folium.raster_layers import TileLayer, WmsTileLayer


class SideBySide(MacroElement):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E302 expected 2 blank lines, found 1

"""Add a side-by-side control to an existing map.

Uses the Leaflet plugin by Digidem under MIT License.
https://github.com/digidem/leaflet-side-by-side

Parameters
----------
left_layer : folium TileLayer or WMSTileLayer
A layer to show on the left side of the map. Any layer added to the map
that is here will be shown on the left.
right_layer : folium TileLayer or WMSTileLayer
A layer to show on the right side of the map. Any layer added to the
map that is here will be shown on the right. This should not be the
same as any layer in `left_layers`.
version : str, default None
The version of the javascript library to use. Default value will use
the development version. Valid values are None, 'gh-pages', 'v2.0.0',
'v1.1.1', 'v1.1.0', 'v1.0.2' or 'v1.0.1'.

Examples
--------
>>> m = folium.Map(location=[40, -100], zoom_start=4)
>>> left_layer = folium.raster_layers.TileLayer(
... tiles='http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',
... attr='google',
... name='google street view',
... max_zoom=20,
... subdomains=['mt0', 'mt1', 'mt2', 'mt3'],
... overlay=False,
... control=True,
... ).add_to(m)
>>> right_layer = folium.raster_layers.WmsTileLayer(
... url='http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi',
... name='test',
... fmt='image/png',
... layers='nexrad-n0r-900913',
... attr=u'Weather data © 2012 IEM Nexrad',
... transparent=True,
... overlay=True,
... control=True,
... ).add_to(m)
>>> sbs = folium.plugin.SideBySide(left_layer, right_layer)
>>> m.add_child(sbs)
"""

_template = Template("""
{% macro script(this, kwargs) %}

var {{this.get_name()}} = new L.Control.SideBySide(
{{this.left_layer.get_name()}}, {{this.right_layer.get_name()}});
{{this._parent.get_name()}}.addControl({{this.get_name()}});

{% endmacro %}
""") # noqa

def __init__(self, left_layer, right_layer, version=None):

super(SideBySide, self).__init__()
self._name = 'SideBySide'
# Check input layers
if not isinstance(left_layer, (TileLayer, WmsTileLayer)):
raise TypeError('"left_layer" shall be a folium TileLayer or '
'WmsTileLayer instance.')
if not isinstance(right_layer, (TileLayer, WmsTileLayer)):
raise TypeError('"right_layer" shall be a folium TileLayer or '
'WmsTileLayer instance.')
self.left_layer = left_layer
self.right_layer = right_layer
# Manage version
versions = ('gh-pages', 'v2.0.0', 'v1.1.1',
'v1.1.0', 'v1.0.2', 'v1.0.1')
if not version:
version = versions[0]
if version in versions:
self._jslink = ('https://rawcdn.githack.com/digidem/'
'leaflet-side-by-side/{}/'
'leaflet-side-by-side.js').format(version)
else:
raise ValueError('"version" is not a valid value.')

def render(self, **kwargs):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E303 too many blank lines (2)

figure = self.get_root()
assert isinstance(figure, Figure), ('You cannot render this Element '
'if it is not in a Figure.')
super(SideBySide, self).render()

figure.header.add_child(JavascriptLink(self._jslink)) # noqa
54 changes: 54 additions & 0 deletions tests/plugins/test_side_by_side.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-

"""
Test MiniMap
---------------
"""

from __future__ import (absolute_import, division, print_function)

from folium import Map, TileLayer, WmsTileLayer, Marker
from folium.plugins import SideBySide
import pytest

def test_side_by_side():

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E302 expected 2 blank lines, found 1

m = Map(location=[40, -100], zoom_start=4)
url = 'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}'
tile = TileLayer(tiles=url, attr='google', name='google street view',
max_zoom=20, subdomains=['mt0', 'mt1', 'mt2', 'mt3'],
overlay=False, control=True).add_to(m)
url = 'http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi'
wms = WmsTileLayer(url=url, name='test', fmt='image/png',
layers='nexrad-n0r-900913',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W291 trailing whitespace

attr=u'Weather data © 2012 IEM Nexrad',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W291 trailing whitespace

transparent=True, overlay=True, control=True).add_to(m)
sbs = SideBySide(tile, wms)
m.add_child(sbs)
out = m._parent.render()
# Verify that a new side-by-side control is getting created.
assert 'new L.Control.SideBySide' in out

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W293 blank line contains whitespace

m = Map(location=[40, -100], zoom_start=4)
url = 'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}'
tile = TileLayer(tiles=url, attr='google', name='google street view',
max_zoom=20, subdomains=['mt0', 'mt1', 'mt2', 'mt3'],
overlay=False, control=True).add_to(m)
url = 'http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi'
marker = Marker((40, -100))
with pytest.raises(TypeError):
sbs = SideBySide(tile, marker)
sbs = SideBySide(marker, tile)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W293 blank line contains whitespace

m = Map(location=[40, -100], zoom_start=4)
url = 'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}'
tile = TileLayer(tiles=url, attr='google', name='google street view',
max_zoom=20, subdomains=['mt0', 'mt1', 'mt2', 'mt3'],
overlay=False, control=True).add_to(m)
url = 'http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi'
wms = WmsTileLayer(url=url, name='test', fmt='image/png',
layers='nexrad-n0r-900913',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W291 trailing whitespace

attr=u'Weather data © 2012 IEM Nexrad',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W291 trailing whitespace

transparent=True, overlay=True, control=True).add_to(m)
with pytest.raises(ValueError):
sbs = SideBySide(tile, wms, version="whatever")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W293 blank line contains whitespace
W391 blank line at end of file