Thematic maps
Three thematic maps, each written as one classify: block on an ordinary
layer. Every one compiles to a plain MapLibre expression and generates its
legend. How it works, and every option: Thematic maps.
Choropleth — quantile classes from the data
Section titled “Choropleth — quantile classes from the data”Median household income by tract, in five quantile classes (the same number
of tracts in each). The breaks are computed when the GeoJSON loads; the
legend — automatic, since the document declares none — shows their real
edges, formatted as currency. Tracts with no value
— null, missing, "", "n/a" in this sample — are light grey, and the
numeric strings a CSV export leaves behind ("48200") count as numbers.
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json# A choropleth: tracts coloured by median income in five quantile classes.# The breaks are computed from the data when it loads (GeoJSON source), and# the legend shows their real edges. Tracts with no value draw light grey.# No legend: block — a map with a classify: layer gets its legend# automatically (legend: false turns it off).# Data: synthetic tracts made for this example.type: mapid: classify-choroplethconfig: center: [-75.19, 39.936] zoom: 12 mapStyle: "https://tiles.openfreemap.org/styles/positron"sources: tracts: type: geojson url: /data/classify/sample-tracts.geojsonlayers: - id: income type: fill source: tracts label: Median household income classify: field: median_income method: quantile classes: 5 palette: Blues format: { currency: USD, max-fraction-digits: 0 } paint: fill-opacity: 0.85 fill-outline-color: "#ffffff" interactive: click: popup: - h4: - property: tract - p: - str: "Median income: " - property: median_incomeA rate — cases per 100,000 residents
Section titled “A rate — cases per 100,000 residents”normalize: population and multiply: 100000 turn a count into a rate, and
the natural breaks are computed on the rate. The tract with no residents is
no data (grey), not an Infinity class.
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json# A rate, not a count: cases per 100,000 residents in each tract. normalize:# divides by population and multiply: scales it; breaks (here jenks) are# computed on the rate. A tract with no residents (population 0 or missing)# is no data — never an Infinity class. Data: synthetic tracts.type: mapid: classify-rateconfig: center: [-75.19, 39.936] zoom: 12 mapStyle: "https://tiles.openfreemap.org/styles/positron"sources: tracts: type: geojson url: /data/classify/sample-tracts.geojsonlayers: - id: rate type: fill source: tracts label: Cases per 100,000 residents classify: field: cases normalize: population multiply: 100000 method: jenks classes: 5 palette: OrRd format: { max-fraction-digits: 0 } paint: fill-opacity: 0.85 fill-outline-color: "#ffffff"Graduated symbols — natural breaks, colour and size
Section titled “Graduated symbols — natural breaks, colour and size”World cities by population in five natural-breaks (jenks) classes. One block
drives both circle-color and circle-radius from the same breaks.
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json# Graduated symbols: world cities sized and coloured by population in five# natural-breaks (jenks) classes. One classify block drives circle-color and# circle-radius from the same breaks; the legend draws each class's circle.# Data: Natural Earth populated places (public domain).type: mapid: classify-graduatedconfig: center: [10, 25] zoom: 1.3 mapStyle: "https://tiles.openfreemap.org/styles/positron"legend: position: bottom-leftsources: cities: type: geojson url: /data/classify/world-cities.geojsonlayers: - id: cities type: circle source: cities label: City population classify: field: pop method: jenks classes: 5 palette: YlOrRd radius: [2, 4, 7, 10, 14] paint: circle-opacity: 0.85 circle-stroke-color: "#ffffff" circle-stroke-width: 1 interactive: click: popup: - h4: - property: name - p: - str: "Population: " - property: pop format: ",.0f"Categories over vector tiles
Section titled “Categories over vector tiles”The demo tiles’ countries coloured by continent with okabe-ito, a
colour-blind-safe palette. Categories compile to a match and need no data
scan, so they work on a basemap’s vector tiles; values not listed
(Antarctica) take the other: colour.
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json# Categories over vector tiles: the demo tiles' countries coloured by# continent with a CVD-safe palette. Categories need no data scan, so they# work on tiled sources exactly as on GeoJSON (computed breaks do not).type: mapid: classify-categoriesconfig: center: [15, 20] zoom: 1.2 mapStyle: "https://demotiles.maplibre.org/style.json"legend: position: bottom-leftlayers: - id: continents type: fill source: maplibre source-layer: countries before: countries-boundary label: Continent classify: field: CONTINENT categories: [Africa, Asia, Europe, North America, South America, Oceania] palette: okabe-ito other: "#d9d9d9" paint: fill-opacity: 1Export
Section titled “Export”mlym emit choropleth.yaml writes a style.json whose fill-color is the
compiled step (with the breaks computed from the data at export) and whose
layer metadata["maplibre-yaml:classify"] records the classes. It opens in
Maputnik and renders in any MapLibre map — no maplibre-yaml required.