Finer geometry in zooms and cartouches

A map is often drawn from a generalised (simplified) layer: the file stays light and the main map looks clean. Once a dense area is magnified in a Zoom window or an Inset, the same outlines look coarse. If you have the same areas at a finer level of generalisation, the detail option draws the zoom and the cartouches from it, without losing the layer’s symbology.

How it works

  1. The layer is classified, coloured and given its opacity from its own data, exactly as without detail.

  2. For a zoom or a cartouche, the finer geometries are joined to those results through a key (detail_join), so each finer outline takes the class, colour and values of its area.

  3. The finer outlines are drawn instead of the generalised ones. The main map is not touched.

m = (
    mp.Map(gdf_generalised, bbox=bbox)
    + mp.Basemap(detail=gdf_fine)
    + mp.Choropleth(
        gdf_generalised, column="rate",
        detail=gdf_fine,          # finer outlines for the zoom and the insets
        detail_join="COD_GEO",    # column present in both frames
    )
    + mp.Zoom(paris_bbox, x=520, y=90, width=250, height=250)
)

The gallery shows the result side by side, with and without detail: Finer geometry in a zoom window.

The two options

detail

The finer geometry, as a GeoDataFrame, which is used on the zoom and on every cartouche. A dict chooses the targets:

detail={"zoom": gdf_a, "cartouches": gdf_b, 0: gdf_c}

"zoom" is the zoom window, "cartouches" every cartouche, and an integer one cartouche by its index (0 is the first). A cartouche index wins over "cartouches". A target with no entry keeps the layer’s own geometry. The finer frame can be in any CRS: it is reprojected to the layer’s.

detail_join

The key shared by the layer’s data and the finer geometries.

Value

Join

"COD_GEO"

A column with this name, present in both frames.

("code", "COD_GEO")

code in the layer’s frame, COD_GEO in the finer one.

None (default)

The index of both frames.

Layers that accept it

Layer

What detail changes

Choropleth, Category

The polygons drawn in the zoom and the cartouches. Classes, colours, opacity, dissolve and the hatching of areas without data follow.

Proportional

The centres of the circles. Values, radii and colours stay those of the layer.

Situation

The positions of the markers, taken from the centroid of the finer outline.

Label

The positions of the labels of a zoom or cartouche:<i> target. The text and the priority stay those of the layer; an area made of several parts is labelled once. Labels on the main map are unchanged.

Basemap, Vector

The polygons or lines drawn in the zoom and the cartouches. No join is needed: the finer geometries replace the layer’s, so they have no detail_join.

Good to know

One finer geometry per key, or several. Several finer rows may share a key (an area split into islands): each part takes the area’s colour. Labels collapse the parts into one.

Unique keys on the layer side. The layer’s key must be unique, otherwise its symbology cannot be matched to the finer geometries unambiguously, and a ValueError explains it. Rows of the finer frame with no match are ignored.

Same type of key on both sides. A key that is text in one frame and numeric in the other ("01" and 1) cannot match, and raises a ValueError saying so. Convert one of them first, for example gdf["COD_GEO"] = gdf["COD_GEO"].astype(str). Text that looks alike but differs, such as "1" and "01", is not detected: it shows as missing finer geometries (see below).

Areas without a finer geometry are not drawn in the zoom and the cartouches, and a UserWarning lists the first of them. It usually means that the key does not match: check detail_join.

Identifiers stay those of the main map, so hover tooltips of an interactive export still work in the zoom.

Proportional circles and labels at the edge. A finer outline can move a centroid into or out of a zoom window, so a symbol close to the edge may appear or disappear compared with the generalised layer.

No YAML export. A GeoDataFrame is not a plain value, so to_yaml of a map that uses detail raises a TypeError that says so, rather than dropping the option silently.

Errors you may meet

Message

Cause

detail join: column 'x' is not in the choropleth data

detail_join names a column missing from the layer’s frame (the message lists the columns that exist, and names the layer: choropleth, category, proportional, situation or label); the same message with detail for the finer frame.

detail join: the key of the choropleth data has duplicates

Several rows of the layer share a key.

detail join: the key is int64 in the choropleth data but object ...

One frame has text keys and the other numeric keys: convert one side.

detail: unknown target 'main'

A dict key other than "zoom", "cartouches" or an integer. The main map has no detail: it is drawn from the layer itself.

detail[...] must be a GeoDataFrame

A dict value is not a GeoDataFrame.