LayerGroup & FeatureGroup
Bundle N layers so they can be added, removed, toggled, or measured as one — wraps Leaflet 2's LayerGroup / FeatureGroup.
---
.. llms_copy::LayerGroup & FeatureGroup
.. toc::
Overview
dl2.LayerGroup and dl2.FeatureGroup mirror Leaflet's container primitives:
| Component | When to use it | |-------------|----------------| | LayerGroup | Bundle any layers so a single addTo / remove shows or hides the whole set. Pair with dl2.Overlay inside a LayersControl to toggle the entire group as one entry. | | FeatureGroup | Like LayerGroup, but extends leaflet.FeatureGroup — also emits a combined geojson (vector children), a single n_clicks no matter which child was clicked, and an n_layers counter that bumps on add/remove. Pair with EditControl when you want to ship the user's drawings out of the map as one piece. |
Both components also accept any layer as a child via the same React context that <Map> uses — children attach to the group via a proxy map instead of the real map directly.
Live demo
A switch toggles a LayerGroup of three markers on/off. Below it, a FeatureGroup aggregates four shapes and reports its combined geojson and the bumping n_clicks counter.
.. exec::docs.layer-group.example :code: false
Source
```python
File: docs/layer-group/example.py
""" LayerGroup & FeatureGroup — limited working example.
Top map: a LayerGroup containing three markers — toggle them all on/off with one switch (the group itself is conditionally rendered, so all children come and go together).
Bottom map: a FeatureGroup wrapping three vector layers + a marker. Click any of them and FeatureGroup's n_clicks bumps; the readout shows the combined GeoJSON it emits. """
import json
import dash_leaflet2 as dl2 import dash_mantine_components as dmc from dash import Input, Output, callback, html from dl2_tiles import ESRI_CANVAS, register_theme_swap from dl2_locations import PHILADELPHIA from dl2_shared import code_panel, header, info_panel
Basemap pair for this page — dl2_tiles owns the light/dark wiring.
TILES = ESRI_CANVAS
CODE_LG = """dl2.Map(children=[ dl2.TileLayer(), dl2.LayerGroup(children=[ dl2.Marker(position=PHILADELPHIA.center), dl2.Marker(position=PHILADELPHIA.at(2.2, 2.9)), dl2.Marker(position=PHILADELPHIA.at(-2.2, -2.9)), ]) if show_markers else None, ])"""
CODE_FG = """dl2.Map(children=[ dl2.TileLayer(), dl2.FeatureGroup(id="fg", children=[ dl2.Polygon(positions=[...]), dl2.Polyline(positions=[...]), dl2.Circle(center=[...], radius=400), dl2.Marker(position=[...]), ]), ])
@callback(Output("fg-readout","children"), Input("fg","geojson")) def show(geojson): ..."""
component = dmc.Stack( [ header( "LayerGroup & FeatureGroup", "LayerGroup bundles N layers so one switch hides them all. " "FeatureGroup adds aggregate event + GeoJSON output — click any child and " "n_clicks bumps; add/remove children and n_layers bumps too.", badge="dl2.LayerGroup / FeatureGroup", ),
dmc.Title("1. LayerGroup", order=3, mt="md"), dmc.Grid( [ dmc.GridCol( dmc.Paper( dl2.Map( id="lg-map", center=PHILADELPHIA.center, zoom=12, style={"height": "45vh"}, children=[ dl2.TileLayer(id="lg-tile", **TILES.kwargs("light")), html.Div(id="lg-container"), ], ), shadow="sm", radius="md", withBorder=True, style={"overflow": "hidden", "height": "45vh"}, ), span=8, ), dmc.GridCol( info_panel( "Toggle the whole group", dmc.Switch( id="lg-toggle", checked=True, label="Show three markers (all in one LayerGroup)", ), ), span=4, ), ], gutter="md", ), code_panel("LayerGroup", CODE_LG),
dmc.Title("2. FeatureGroup", order=3, mt="md"), dmc.Grid( [ dmc.GridCol( dmc.Paper( dl2.Map( id="fg-map", center=PHILADELPHIA.center, zoom=12, style={"height": "45vh"}, children=[ dl2.TileLayer(), dl2.FeatureGroup( id="fg", children=[ dl2.Polygon( # (north_km, east_km) from the # city centre — the shape keeps its # real-world size at any latitude. positions=PHILADELPHIA.ring([ (2.2, -4.9), (4.5, 1.0), (2.2, 5.9), (0.0, 0.0), ]), color="#228be6", fillOpacity=0.35, ), dl2.Polyline( positions=PHILADELPHIA.ring([ (-3.3, -4.9), (-3.3, 1.0), (-3.3, 6.9), ]), color="#fa5252", weight=3, ), dl2.Circle( center=PHILADELPHIA.at(1.1, 2.9), radius=600, color="#40c057", fillOpacity=0.25, ), dl2.Marker(position=PHILADELPHIA.at(-1.1, -1.0)), ], ), ], ), shadow="sm", radius="md", withBorder=True, style={"overflow": "hidden", "height": "45vh"}, ), span=8, ), dmc.GridCol( dmc.Stack( [ info_panel( "Group n_clicks", dmc.Badge(id="fg-clicks", color="blue", variant="light", children="0"), ), info_panel( "Combined geojson (vector children)", dmc.Code( id="fg-geojson-readout", block=True, children="(click a shape)", style={"maxHeight": "20vh", "overflow": "auto"}, ), ), ], gap="md", ), span=4, ), ], gutter="md", ), code_panel("FeatureGroup", CODE_FG), ], gap="md", )
@callback(Output("lg-container", "children"), Input("lg-toggle", "checked")) def render_group(show): if not show: return [] return dl2.LayerGroup( children=[ dl2.Marker(position=PHILADELPHIA.center), dl2.Marker(position=PHILADELPHIA.at(2.2, 2.9)), dl2.Marker(position=PHILADELPHIA.at(-2.2, -2.9)), ] )
@callback(Output("fg-clicks", "children"), Input("fg", "n_clicks")) def show_clicks(n): return str(n or 0)
@callback(Output("fg-geojson-readout", "children"), Input("fg", "geojson")) def show_geojson(gj): if not gj: return "(no children yet)" return json.dumps(gj, indent=2)[:2000]
Light/dark basemap, driven off the color-scheme store.
register_theme_swap("lg-tile", TILES) ```
:defaultExpanded: false :withExpandedButton: true
---
*Source: /layer-group*
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /layer-group/llms.txt — LLM-friendly documentation
- /sitemap.xml
- /robots.txt