Skip to content

Commit f3ca260

Browse files
adarshsmclaude
andcommitted
Support base layers in GroupedLayerControl
GroupedLayerControl always passed `null` as the base layers argument of `L.control.groupedLayers`, so base layers could only go in a separate regular LayerControl (#1876). An unknown `base_layers` keyword was also silently forwarded into the JS options. Add a `base_layers` argument: the given layers are rendered as the base layer radio buttons of the grouped control and get `control = False`, so they no longer also show up in a regular LayerControl. Which base layer is visible on opening still follows each layer's `show`, as with LayerControl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0376182 commit f3ca260

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

‎folium/plugins/groupedlayercontrol.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class GroupedLayerControl(JSCSSMixin, MacroElement):
2323
exclusive_groups : bool, default True
2424
Whether to use radio buttons (default) or checkboxes.
2525
If you want to use both, use two separate instances of this class.
26+
base_layers : list, default None
27+
Layer objects, typically tile layers, to show as base layers in this
28+
control. These are removed from the regular LayerControl. Use the
29+
layers' `show` argument to choose which one is shown on opening.
2630
**kwargs
2731
Additional (possibly inherited) options. See
2832
https://leafletjs.com/reference.html#control-layers
@@ -45,7 +49,15 @@ class GroupedLayerControl(JSCSSMixin, MacroElement):
4549
{% macro script(this,kwargs) %}
4650
4751
L.control.groupedLayers(
52+
{%- if this.base_layers %}
53+
{
54+
{%- for key, val in this.base_layers.items() %}
55+
{{ key|tojson }} : {{val}},
56+
{%- endfor %}
57+
},
58+
{%- else %}
4859
null,
60+
{%- endif %}
4961
{
5062
{%- for group_name, overlays in this.grouped_overlays.items() %}
5163
{{ group_name|tojson }} : {
@@ -65,12 +77,16 @@ class GroupedLayerControl(JSCSSMixin, MacroElement):
6577
{% endmacro %}
6678
""")
6779

68-
def __init__(self, groups, exclusive_groups=True, **kwargs):
80+
def __init__(self, groups, exclusive_groups=True, base_layers=None, **kwargs):
6981
super().__init__()
7082
self._name = "GroupedLayerControl"
7183
self.options = remove_empty(**kwargs)
7284
if exclusive_groups:
7385
self.options["exclusiveGroups"] = list(groups.keys())
86+
self.base_layers = {}
87+
for element in base_layers or []:
88+
self.base_layers[element.layer_name] = element.get_name()
89+
element.control = False
7490
self.layers_untoggle = set()
7591
self.grouped_overlays = {}
7692
for group_name, sublist in groups.items():

‎tests/plugins/test_grouped_layer_control.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,35 @@ def test_grouped_layer_control():
3939
{fg2.get_name()}.remove();
4040
""")
4141
assert expected in out
42+
43+
44+
def test_grouped_layer_control_base_layers():
45+
m = folium.Map([40.0, 70.0], zoom_start=6, tiles=None)
46+
osm = folium.TileLayer("OpenStreetMap", name="osm").add_to(m)
47+
topo = folium.TileLayer("OpenTopoMap", name="topo", show=False).add_to(m)
48+
fg1 = folium.FeatureGroup(name="g1").add_to(m)
49+
fg2 = folium.FeatureGroup(name="g2").add_to(m)
50+
groupedlayercontrol.GroupedLayerControl(
51+
groups={"groups1": [fg1, fg2]}, base_layers=[osm, topo]
52+
).add_to(m)
53+
lc = folium.LayerControl().add_to(m)
54+
out = normalize(m._parent.render())
55+
56+
expected = normalize(f"""
57+
L.control.groupedLayers(
58+
{{
59+
"osm" : {osm.get_name()},
60+
"topo" : {topo.get_name()},
61+
}},
62+
{{
63+
"groups1" : {{
64+
"g1" : {fg1.get_name()},
65+
"g2" : {fg2.get_name()},
66+
}},
67+
}},
68+
{{"exclusiveGroups": ["groups1",],}},
69+
).addTo({m.get_name()});
70+
""")
71+
assert expected in out
72+
# The base layers are no longer listed in the regular LayerControl.
73+
assert not lc.base_layers

0 commit comments

Comments
 (0)