Skip to content

Support base layers in GroupedLayerControl - #2302

Draft
adarshsm wants to merge 1 commit into
python-visualization:mainfrom
adarshsm:grouped-layer-control-base-layers
Draft

adarshsm wants to merge 1 commit into
python-visualization:mainfrom
adarshsm:grouped-layer-control-base-layers

Conversation

@adarshsm

Copy link
Copy Markdown
Contributor

Closes #1876.

The problem

GroupedLayerControl always rendered L.control.groupedLayers(null, {...groups...}, options), so the base layers argument was always null. To get base layers you had to keep a regular LayerControl next to the grouped one, which gives two separate controls. The issue asks for both in one control. The Leaflet plugin already supports this through its first argument, as @hansthen said in the issue.

Passing base_layers= today doesn't raise. It falls into **kwargs and ends up in the JS options object as "base_layers": [...], where the plugin ignores it.

The change

  • New base_layers argument (list of layers, default None). The layers are rendered as the first argument of L.control.groupedLayers ({"name": layer, ...}). Without base_layers the output is unchanged (null).
  • Like the grouped overlays, those layers get control = False, so a regular LayerControl on the same map doesn't list them a second time.
  • Which base layer is visible on opening follows each layer's show, the same as with LayerControl. Pass show=False to all but one base layer.
  • Docstring updated.
m = folium.Map(tiles=None)
osm = folium.TileLayer("OpenStreetMap", name="osm").add_to(m)
topo = folium.TileLayer("OpenTopoMap", name="topo", show=False).add_to(m)
...
GroupedLayerControl(groups={"groups1": [fg1, fg2]}, base_layers=[osm, topo]).add_to(m)

Tests

  • New test_grouped_layer_control_base_layers checks the rendered L.control.groupedLayers({...base layers...}, {...groups...}, ...) call, and checks that a regular LayerControl added afterwards has no base layers left. It fails on main and passes with this change.
  • I also rendered the example map above and ran the generated <script> blocks through node --check to make sure the JS parses.
  • pytest tests/plugins tests/test_map.py: 95 passed. The 2 failures (test_timedynamic_geo_json without geodatasets, and test_icon_invalid_marker_colors) also fail on unmodified main in my environment. black --check and ruff check pass on the touched files.

I haven't tested this in a browser.

🤖 Generated with Claude Code

GroupedLayerControl always passed `null` as the base layers argument of
`L.control.groupedLayers`, so base layers could only go in a separate
regular LayerControl (python-visualization#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>
@hansthen

Copy link
Copy Markdown
Collaborator

@adarshsm Looks good! Thanks for picking this up.

This branch was successfully deployed

1 active deployment
pypi — f3ca260c Deployed Oct 17, 2026 by adarshsm via packages #1975
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Passing base layers to GroupedLayerControl plugin

2 participants