-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
Leaflet.encoded
plugin: Enable creating PolyLine and Polygon fr…
…om encoded string (#1928) * add plugin to visualize the polyline from an encoded string * correct import in user guide * Update polyline_encoded.py Added type information to for argument to `__init__` * rework encoded plugin to include PolygonFromEncoded * include doc and tests for PolygonFromEncoded * update doc to include the link of the algo * use path_options instead of parse_options * set path_options to an attribute --------- Co-authored-by: Hans Then <hans.then@gmail.com>
- Loading branch information
1 parent
55a758a
commit 5086929
Showing
6 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
```{code-cell} ipython3 | ||
--- | ||
nbsphinx: hidden | ||
--- | ||
import folium | ||
from folium import plugins | ||
``` | ||
|
||
# PolygonFromEncoded | ||
|
||
Create a Polygon directly from an encoded polyline string. To understand the encoding algorithm | ||
refer to [this](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) link. | ||
|
||
```{code-cell} ipython3 | ||
m = folium.Map(location=[40, -80], zoom_start=5) | ||
encoded = r"w`j~FpxivO}jz@qnnCd}~Bsa{@~f`C`lkH" | ||
plugins.PolygonFromEncoded(encoded=encoded).add_to(m) | ||
m | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
```{code-cell} ipython3 | ||
--- | ||
nbsphinx: hidden | ||
--- | ||
import folium | ||
from folium import plugins | ||
``` | ||
|
||
# PolyLineFromEncoded | ||
|
||
Create a PolyLine directly from an encoded polyline string. To understand the encoding algorithm | ||
refer to [this](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) link. | ||
|
||
```{code-cell} ipython3 | ||
m = folium.Map(location=[40, -120], zoom_start=5) | ||
encoded = r"_p~iF~cn~U_ulLn{vA_mqNvxq`@" | ||
plugins.PolyLineFromEncoded(encoded=encoded).add_to(m) | ||
m | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
from abc import ABC, abstractmethod | ||
|
||
from jinja2 import Template | ||
|
||
from folium.elements import JSCSSMixin | ||
from folium.features import MacroElement | ||
from folium.vector_layers import path_options | ||
|
||
|
||
class _BaseFromEncoded(JSCSSMixin, MacroElement, ABC): | ||
"""Base Interface to create folium objects from encoded strings. | ||
Derived classes must define `_encoding_type` property which returns the string | ||
representation of the folium object to create from the encoded string. | ||
Parameters | ||
---------- | ||
encoded: str | ||
The raw encoded string from the Polyline Encoding Algorithm. See: | ||
https://developers.google.com/maps/documentation/utilities/polylinealgorithm | ||
**kwargs: | ||
Object options as accepted by leaflet. | ||
""" | ||
|
||
_template = Template( | ||
""" | ||
{% macro script(this, kwargs) %} | ||
var {{ this.get_name() }} = L.{{ this._encoding_type }}.fromEncoded( | ||
{{ this.encoded|tojson }}, | ||
{{ this.options|tojson }} | ||
).addTo({{ this._parent.get_name() }}); | ||
{% endmacro %} | ||
""" | ||
) | ||
|
||
default_js = [ | ||
( | ||
"polyline-encoded", | ||
"https://cdn.jsdelivr.net/npm/polyline-encoded@0.0.9/Polyline.encoded.js", | ||
) | ||
] | ||
|
||
def __init__(self, encoded: str): | ||
super().__init__() | ||
self.encoded = encoded | ||
|
||
@property | ||
@abstractmethod | ||
def _encoding_type(self) -> str: | ||
"""An abstract getter to return the type of folium object to create.""" | ||
raise NotImplementedError | ||
|
||
|
||
class PolyLineFromEncoded(_BaseFromEncoded): | ||
"""Create PolyLines directly from the encoded string. | ||
Parameters | ||
---------- | ||
encoded: str | ||
The raw encoded string from the Polyline Encoding Algorithm. See: | ||
https://developers.google.com/maps/documentation/utilities/polylinealgorithm | ||
**kwargs: | ||
Polyline options as accepted by leaflet. See: | ||
https://leafletjs.com/reference.html#polyline | ||
Adapted from https://github.com/jieter/Leaflet.encoded | ||
Examples | ||
-------- | ||
>>> from folium import Map | ||
>>> from folium.plugins import PolyLineFromEncoded | ||
>>> m = Map() | ||
>>> encoded = r"_p~iF~cn~U_ulLn{vA_mqNvxq`@" | ||
>>> PolyLineFromEncoded(encoded=encoded, color="green").add_to(m) | ||
""" | ||
|
||
def __init__(self, encoded: str, **kwargs): | ||
self._name = "PolyLineFromEncoded" | ||
super().__init__(encoded=encoded) | ||
self.options = path_options(line=True, **kwargs) | ||
|
||
@property | ||
def _encoding_type(self) -> str: | ||
"""Return the name of folium object created from the encoded.""" | ||
return "Polyline" | ||
|
||
|
||
class PolygonFromEncoded(_BaseFromEncoded): | ||
"""Create Polygons directly from the encoded string. | ||
Parameters | ||
---------- | ||
encoded: str | ||
The raw encoded string from the Polyline Encoding Algorithm. See: | ||
https://developers.google.com/maps/documentation/utilities/polylinealgorithm | ||
**kwargs: | ||
Polygon options as accepted by leaflet. See: | ||
https://leafletjs.com/reference.html#polygon | ||
Adapted from https://github.com/jieter/Leaflet.encoded | ||
Examples | ||
-------- | ||
>>> from folium import Map | ||
>>> from folium.plugins import PolygonFromEncoded | ||
>>> m = Map() | ||
>>> encoded = r"w`j~FpxivO}jz@qnnCd}~Bsa{@~f`C`lkH" | ||
>>> PolygonFromEncoded(encoded=encoded).add_to(m) | ||
""" | ||
|
||
def __init__(self, encoded: str, **kwargs): | ||
self._name = "PolygonFromEncoded" | ||
super().__init__(encoded) | ||
self.options = path_options(line=True, radius=None, **kwargs) | ||
|
||
@property | ||
def _encoding_type(self) -> str: | ||
"""Return the name of folium object created from the encoded.""" | ||
return "Polygon" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
"""Test PolyLineFromEncoded Plugin.""" | ||
|
||
from jinja2 import Template | ||
|
||
from folium import Map | ||
from folium.plugins import PolygonFromEncoded, PolyLineFromEncoded | ||
from folium.utilities import normalize | ||
|
||
|
||
def test_polyline_from_encoded(): | ||
"""Test `PolyLineFromEncoded` plugin. | ||
The test ensures: | ||
- The original JS script is present in the HTML file. | ||
- The rendering from `PolyLineFromEncoded` and the original plugin gives the | ||
same output. | ||
""" | ||
|
||
m = Map([35.0, -120.0], zoom_start=3) | ||
|
||
encoded = r"_p~iF~cn~U_ulLn{vA_mqNvxq`@" | ||
kwargs = {"color": "green"} | ||
polyline = PolyLineFromEncoded(encoded=encoded, **kwargs) | ||
|
||
polyline.add_to(m) | ||
|
||
out = normalize(m._parent.render()) | ||
|
||
script = '<script src="https://cdn.jsdelivr.net/npm/polyline-encoded@0.0.9/Polyline.encoded.js"></script>' | ||
assert script in out | ||
|
||
tmpl = Template( | ||
""" | ||
var {{this.get_name()}} = L.Polyline.fromEncoded( | ||
{{ this.encoded|tojson }}, | ||
{{ this.options|tojson }} | ||
).addTo({{this._parent.get_name()}}); | ||
""" | ||
) | ||
|
||
expected_render = tmpl.render(this=polyline) | ||
actual_render = polyline._template.module.script(polyline) | ||
|
||
assert normalize(expected_render) == normalize(actual_render) | ||
|
||
|
||
def test_polygon_from_encoded(): | ||
"""Test `PolygonFromEncoded` plugin. | ||
The test ensures: | ||
- The original JS script is present in the HTML file. | ||
- The rendering from `PolygonFromEncoded` and the original plugin gives the | ||
same output. | ||
""" | ||
|
||
m = Map([40.0, -80.0], zoom_start=3) | ||
|
||
encoded = r"w`j~FpxivO}jz@qnnCd}~Bsa{@~f`C`lkH" | ||
polygon = PolygonFromEncoded(encoded=encoded, kwargs={}) | ||
|
||
polygon.add_to(m) | ||
|
||
out = normalize(m._parent.render()) | ||
|
||
script = '<script src="https://cdn.jsdelivr.net/npm/polyline-encoded@0.0.9/Polyline.encoded.js"></script>' | ||
assert script in out | ||
|
||
tmpl = Template( | ||
""" | ||
var {{this.get_name()}} = L.Polygon.fromEncoded( | ||
{{ this.encoded|tojson }}, | ||
{{ this.options|tojson }} | ||
) | ||
.addTo({{this._parent.get_name()}}); | ||
""" | ||
) | ||
|
||
expected_render = tmpl.render(this=polygon) | ||
|
||
actual_render = polygon._template.module.script(polygon) | ||
|
||
assert normalize(expected_render) == normalize(actual_render) |