Skip to content

Add FeatureGroupSubGroup plugin #875

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

Merged
Merged
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
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- Explicit WMSTileLayer options, accept all **kwargs (conengmo #838)
- Updated links to Draw plugin (conengmo #868)
- Ingest any object that __geo_interface__ (ocefpaf #880)
- Added `FeatureGroupSubGroup` plugin (shtrom #875)

API changes

Expand Down
194 changes: 152 additions & 42 deletions examples/Plugins.ipynb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions folium/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from folium.plugins.boat_marker import BoatMarker
from folium.plugins.draw import Draw
from folium.plugins.fast_marker_cluster import FastMarkerCluster
from folium.plugins.feature_group_sub_group import FeatureGroupSubGroup
from folium.plugins.float_image import FloatImage
from folium.plugins.fullscreen import Fullscreen
from folium.plugins.heat_map import HeatMap
Expand All @@ -33,6 +34,7 @@
'BoatMarker',
'Draw',
'FastMarkerCluster',
'FeatureGroupSubGroup',
'FloatImage',
'Fullscreen',
'HeatMap',
Expand Down
84 changes: 84 additions & 0 deletions folium/plugins/feature_group_sub_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)

from branca.element import Figure, JavascriptLink

from folium.map import Layer

from jinja2 import Template


class FeatureGroupSubGroup(Layer):
"""
Creates a Feature Group that adds its child layers into a parent group when
added to a map (e.g. through LayerControl). Useful to create nested groups,
or cluster markers from multiple overlays. From [0].

[0] https://github.com/ghybs/Leaflet.FeatureGroup.SubGroup

Parameters
----------
group : Layer
The MarkerCluster or FeatureGroup containing this subgroup.

name : string, default None
The name of the Layer, as it will appear in LayerControls
overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).

Examples
-------

Nested groups
=============
>>> fg = folium.FeatureGroup() # Main group
>>> g1 = folium.plugins.FeatureGroupSubGroup(fg, 'g1') # First subgroup of fg
>>> g2 = folium.plugins.FeatureGroupSubGroup(fg, 'g2') # Second subgroup of fg
>>> m.add_child(fg)
>>> m.add_child(g1)
>>> m.add_child(g2)
>>> g1.add_child(folium.Marker([0,0]))
>>> g2.add_child(folium.Marker([0,1]))
>>> folium.LayerControl().add_to(m)

Multiple overlays part of the same cluster group
=====================================================
>>> mcg = folium.plugins.MarkerCluster(control=False) # Marker Cluster, hidden in controls
>>> g1 = folium.plugins.FeatureGroupSubGroup(mcg, 'g1') # First group, in mcg
>>> g2 = folium.plugins.FeatureGroupSubGroup(mcg, 'g2') # Second group, in mcg
>>> m.add_child(mcg)
>>> m.add_child(g1)
>>> m.add_child(g2)
>>> g1.add_child(folium.Marker([0,0]))
>>> g2.add_child(folium.Marker([0,1]))
>>> folium.LayerControl().add_to(m)
"""
_template = Template(u"""
{% macro script(this, kwargs) %}
var {{this.get_name()}} = L.featureGroup.subGroup({{this._group.get_name()}});
{{this.get_name()}}.addTo({{this._parent.get_name()}});
{% endmacro %}
""")

def __init__(self, group, name=None, overlay=True, control=True, show=True):
super(FeatureGroupSubGroup, self).__init__(name=name, overlay=overlay,
control=control, show=show)

self._group = group
self._name = 'FeatureGroupSubGroup'

def render(self, **kwargs):
super(FeatureGroupSubGroup, self).render(**kwargs)

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

figure.header.add_child(
JavascriptLink('https://unpkg.com/[email protected]/dist/leaflet.featuregroup.subgroup.js'), # noqa
name='featuregroupsubgroupjs')
43 changes: 43 additions & 0 deletions tests/plugins/test_feature_group_sub_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-

"""
Test MarkerCluster
------------------
"""

from __future__ import (absolute_import, division, print_function)

import folium

from folium import plugins

Choose a reason for hiding this comment

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

F401 'folium.plugins' imported but unused

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.


from jinja2 import Template


def test_feature_group_sub_group():
m = folium.Map([0., 0.], zoom_start=6)
fg = folium.FeatureGroup()
m.add_child(fg)
g1 = plugins.FeatureGroupSubGroup(fg, 'g1')
m.add_child(g1)
folium.Marker([1, 1]).add_to(g1)
folium.Marker([-1, -1]).add_to(g1)
g2 = plugins.FeatureGroupSubGroup(fg, 'g2')
folium.Marker([-1, 1]).add_to(g2)
folium.Marker([1, -1]).add_to(g2)
m.add_child(g2)
folium.LayerControl().add_to(m)
m._repr_html_()

out = m._parent.render()

# We verify that imports
assert '<script src="https://unpkg.com/[email protected]/dist/leaflet.featuregroup.subgroup.js"></script>' in out # noqa

# Verify the script part is okay.
tmpl = Template("""
var {{this.get_name()}} = L.featureGroup.subGroup({{this._group.get_name()}});
{{this.get_name()}}.addTo({{this._parent.get_name()}});
""")
assert ''.join(tmpl.render(this=g1).split()) in ''.join(out.split())
assert ''.join(tmpl.render(this=g2).split()) in ''.join(out.split())