From 92e60e771a0f4bfb02f309f404a699d7c4c751f7 Mon Sep 17 00:00:00 2001 From: El Williams Date: Fri, 29 May 2026 04:19:11 +0000 Subject: [PATCH 1/2] Add LayerGroup support (#1034) Add a LayerGroup class that mirrors FeatureGroup but uses L.layerGroup() instead of L.featureGroup() in the generated JavaScript, allowing custom options to be passed through to the Leaflet LayerGroup constructor. Closes #1034 --- folium/__init__.py | 2 ++ folium/map.py | 53 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_folium.py | 18 +++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/folium/__init__.py b/folium/__init__.py index 67489f8c50..249fafa397 100644 --- a/folium/__init__.py +++ b/folium/__init__.py @@ -36,6 +36,7 @@ FitOverlays, Icon, LayerControl, + LayerGroup, Marker, Popup, Tooltip, @@ -88,6 +89,7 @@ "JsCode", "LatLngPopup", "LayerControl", + "LayerGroup", "LinearColormap", "Link", "MacroElement", diff --git a/folium/map.py b/folium/map.py index 011025b6a4..ea651e6eea 100644 --- a/folium/map.py +++ b/folium/map.py @@ -185,6 +185,59 @@ def __init__( self.options = remove_empty(**kwargs) +class LayerGroup(Layer): + """ + Create a LayerGroup layer ; you can put things in it and handle them + as a single layer. For example, you can add a LayerControl to + tick/untick the whole group. + + LayerGroup is the base class of FeatureGroup in Leaflet. + Unlike FeatureGroup, LayerGroup accepts custom options + that can be used in custom JavaScript code. + + Parameters + ---------- + name : str, default None + The name of the layer group layer. + It will be displayed in the LayerControl. + If None get_name() will be called to get the technical (ugly) name. + overlay : bool, default True + Whether your layer will be an overlay (ticked with a check box in + LayerControls) or a base layer (ticked with a radio button). + control: bool, default True + Whether the layer will be included in LayerControls. + show: bool, default True + Whether the layer will be shown on opening. + **kwargs + Additional (possibly inherited) options. See + https://leafletjs.com/reference.html#layergroup + + """ + + _template = Template( + """ + {% macro script(this, kwargs) %} + var {{ this.get_name() }} = L.layerGroup( + {{ this.options|tojavascript }} + ); + {% endmacro %} + """ + ) + + def __init__( + self, + name: Optional[str] = None, + overlay: bool = True, + control: bool = True, + show: bool = True, + **kwargs: TypeJsonValue, + ): + super().__init__(name=name, overlay=overlay, control=control, show=show) + self._name = "LayerGroup" + self.tile_name = name if name is not None else self.get_name() + self.options = remove_empty(**kwargs) + + class LayerControl(MacroElement): """ Creates a LayerControl object to be added on a folium map. diff --git a/tests/test_folium.py b/tests/test_folium.py index e424d277c7..fc0b32fc26 100644 --- a/tests/test_folium.py +++ b/tests/test_folium.py @@ -171,6 +171,24 @@ def test_feature_group(self): bounds = m.get_bounds() assert bounds == [[45, -30], [45, 30]], bounds + def test_layer_group(self): + """Test LayerGroup.""" + + m = folium.Map() + layer_group = folium.LayerGroup(name="my_layer_group", custom_option="test_value") + layer_group.add_child(folium.Marker([45, -30], popup=folium.Popup("-30"))) + layer_group.add_child(folium.Marker([45, 30], popup=folium.Popup("30"))) + m.add_child(layer_group) + m.add_child(folium.LayerControl()) + + m._repr_html_() + + bounds = m.get_bounds() + assert bounds == [[45, -30], [45, 30]], bounds + html = m._repr_html_() + assert "L.layerGroup" in html + assert "my_layer_group" in html + def test_topo_json_smooth_factor(self): """Test topojson smooth factor method.""" self.m = folium.Map([43, -100], zoom_start=4) From 3f2ff853d81c2765c9133b6af5cbc75dd0cda47d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 04:26:17 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- folium/map.py | 6 ++---- tests/test_folium.py | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/folium/map.py b/folium/map.py index ea651e6eea..ce2e561a5b 100644 --- a/folium/map.py +++ b/folium/map.py @@ -214,15 +214,13 @@ class LayerGroup(Layer): """ - _template = Template( - """ + _template = Template(""" {% macro script(this, kwargs) %} var {{ this.get_name() }} = L.layerGroup( {{ this.options|tojavascript }} ); {% endmacro %} - """ - ) + """) def __init__( self, diff --git a/tests/test_folium.py b/tests/test_folium.py index fc0b32fc26..0947da1350 100644 --- a/tests/test_folium.py +++ b/tests/test_folium.py @@ -175,7 +175,9 @@ def test_layer_group(self): """Test LayerGroup.""" m = folium.Map() - layer_group = folium.LayerGroup(name="my_layer_group", custom_option="test_value") + layer_group = folium.LayerGroup( + name="my_layer_group", custom_option="test_value" + ) layer_group.add_child(folium.Marker([45, -30], popup=folium.Popup("-30"))) layer_group.add_child(folium.Marker([45, 30], popup=folium.Popup("30"))) m.add_child(layer_group)