Publishing Surveillance Map Products

This guide is part of the Surveillance Pipeline Automation & Spatial Data Quality section. It covers the stage where analysis becomes something other people use — and where every upstream control either holds or is undone.

Concept & Epidemiological Alignment

Publication is where a surveillance pipeline’s responsibilities change shape. Upstream, the concern is correctness: are the counts right, is the cluster real. At publication the concern becomes interpretation and disclosure: will a reader understand what the map shows, and can the published product be combined with anything else to reveal an individual.

Four product types cover most agency needs, and each has a characteristic failure.

Interactive web maps built on vector tiles are the most visible product and the most exposed. The failure is publishing geometry or attributes at a finer resolution than the suppression rules permit, because a tile at a high zoom level is effectively a download of the underlying data.

Partner interfaces give other agencies programmatic access to the same aggregates. The failure is an interface that allows arbitrary queries, which lets a partner reconstruct suppressed cells through differencing — asking for a county total and every tract but one.

Static exports — maps and tables for weekly reports — are the products most often read by decision-makers. The failure is inconsistency: a figure produced by hand each week, with a different classification and a different colour ramp, so that week-over-week comparison is impossible.

Metadata accompanies all of them. The failure is its absence, which leaves a recipient unable to tell a suppressed product from an unsuppressed one, or a provisional count from a final one.

The unifying principle is that publication consumes only the output of the suppression stage, never an intermediate. A map service that reads from the analytic archive, however carefully configured, is one misconfiguration away from serving raw counts.

A further reason publication deserves its own discipline is audience. Analysts inside the agency know that a tract rate is unstable, that the last week is provisional, and that a suppressed area is not an empty one. A council member, a journalist or a worried resident knows none of that, and will read the map literally. Every design decision in this topic is partly a decision about what a literal reading of the product will conclude, and whether that conclusion is one the agency is prepared to stand behind.

Product Types and Their Controls

Product Built from Characteristic risk Control
Vector tile web map Suppressed aggregates only Fine geometry at high zoom Cap maximum zoom to the suppression geography
Partner read-only API Suppressed aggregates only Differencing across queries Fixed geographies, no arbitrary filters, rate limits
Static report exports Suppressed aggregates plus templates Week-to-week inconsistency Fixed classification breaks and template per product
Downloadable tables Suppressed aggregates Complementary suppression gaps Disclosure review of each released table set
Standards metadata Run provenance Recipient cannot interpret Lineage, extent, constraints, provisional status
One Door Out The analytic archive, containing unsuppressed counts and protected intermediates, sits inside the protected boundary and feeds only the suppression stage. The suppression stage writes a single published store of disclosure-controlled aggregates. Four publication channels — vector tiles, a partner interface, static report exports and downloadable tables — all read from that published store and nothing else. A crossed-out path shows a map service reading directly from the analytic archive, marked as the configuration that must not exist. Every product reads the suppressed store; nothing reads the archive protected boundary Analytic archive unsuppressed counts Suppression stage fails closed Published store disclosure-controlled aggregates only Vector tile web map Partner read-only interface Static report exports Downloadable tables no product reads the archive

Spatial Data Prerequisites

  • A published store separate from the analytic archive, written only by the suppression stage.
  • Fixed publication geographies — the set of area levels at which suppression was applied — with their boundary vintage recorded.
  • Generalised geometry for web display, simplified to a tolerance appropriate to the maximum zoom, with topology preserved between neighbours.
  • A web-appropriate coordinate reference system for tiles, applied at the last step so analysis stays in the equal-area working system.
  • Classification breaks fixed per product, stored as configuration, so a weekly map uses the same legend every week.
  • Provenance for every product from the run that produced it.

Production Implementation

The routine below takes suppressed aggregates, generalises geometry with shared-boundary topology, fixes classification, and writes a tile-ready layer with the zoom ceiling that the suppression geography supports.

# Publication-ready layer from suppressed aggregates with a zoom ceiling and fixed breaks.
# Pinned: geopandas==0.14.4, shapely==2.0.4, pandas==2.2.2, numpy==1.26.4
import json
import logging

import numpy as np
import pandas as pd
import geopandas as gpd
import shapely

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("publish.layer")

# The finest geography suppression was applied at decides how far a viewer may zoom.
ZOOM_CEILING = {"county": 9, "tract": 12, "block_group": 13}
SIMPLIFY_M = {"county": 200.0, "tract": 25.0, "block_group": 10.0}


def build_publication_layer(suppressed: pd.DataFrame, boundaries: gpd.GeoDataFrame,
                            level: str, breaks: list[float], provenance: dict,
                            value: str = "rate") -> tuple[gpd.GeoDataFrame, dict]:
    """Join suppressed values to generalised geometry and attach tile metadata."""
    if "suppressed" not in suppressed.columns:
        raise ValueError("input is not the output of the suppression stage")
    if level not in ZOOM_CEILING:
        raise KeyError(f"no publication rules for level {level!r}")

    # Topology-preserving simplification of the whole coverage at once, so shared
    # boundaries stay shared and no slivers open between neighbours.
    b = boundaries.sort_values("geoid").reset_index(drop=True)
    coverage = shapely.coverage_simplify(b.geometry.values, SIMPLIFY_M[level])
    b = b.set_geometry(gpd.GeoSeries(coverage, crs=b.crs))

    layer = b[["geoid", "geometry"]].merge(suppressed, on="geoid", how="left")
    missing = int(layer[value].isna().sum() - layer["suppressed"].fillna(False).sum())
    if missing > 0:
        log.warning("%d areas have no value and are not marked suppressed", missing)

    # Fixed classification: the same breaks every week, never recomputed per run.
    bins = [-np.inf] + list(breaks) + [np.inf]
    layer["class"] = pd.cut(layer[value], bins=bins, labels=False).astype("Int64")
    layer.loc[layer["suppressed"].fillna(False), "class"] = pd.NA

    layer = layer.to_crs("EPSG:3857")           # web display only, at the last step
    meta = {"level": level, "maxzoom": ZOOM_CEILING[level], "minzoom": 4,
            "breaks": breaks, "run_id": provenance["run_id"],
            "config_sha256": provenance["config_sha256"],
            "boundary_vintage": provenance["boundary_vintage"],
            "provisional_after": provenance.get("provisional_from")}
    log.info("publication layer level=%s areas=%d suppressed=%d maxzoom=%d run=%s",
             level, len(layer), int(layer["suppressed"].fillna(False).sum()),
             meta["maxzoom"], meta["run_id"])
    return layer, meta

The zoom ceiling is the control most web-map deployments lack. A tile set built to the default maximum zoom lets a viewer inspect geometry at building scale, and if any attribute travels with that geometry — a rate, a flag — the tile set is a download of the data at a resolution the suppression rules never approved. Capping maximum zoom at the level suppression was applied closes that.

Fixed classification breaks are what make the weekly product comparable to itself. Recomputing quantile breaks from each week’s data means a county can change colour without changing rate, and readers comparing two weeks draw conclusions from the legend rather than the data.

Parameter Selection & Tuning

Simplification tolerance. Enough to make tiles small and fast; not so much that a reader can no longer recognise their own neighbourhood. Coverage-aware simplification is required, because simplifying polygons one at a time opens slivers between neighbours that look like data gaps.

Maximum zoom. Derived from the finest geography suppression was applied to, never from what the tiling tool allows.

Classification scheme. Fixed breaks chosen from a long historical window and reviewed annually suit a recurring product. Quantile breaks suit a one-off exploratory map and nothing else.

Update cadence. A product updated more often than the counts stabilise will show provisional numbers as though final. Match publication cadence to the reporting-delay tail, and mark provisional periods in both the map and its metadata.

Partner interface granularity. Offer the published geographies and nothing else. Every additional filter an interface accepts is a new way to difference two responses.

Edge Cases & Failure Modes

Tiles cached by a content delivery network. A corrected product does not replace tiles already cached at the edge. Version the tile path by run identifier so a correction is a new path rather than an overwrite that some viewers will not see.

Suppressed areas rendered as zero. A null rendered with the lowest colour class tells readers the area had no cases. Suppressed areas need their own distinct legend entry.

Hover tooltips that reveal more than the fill. A map whose fill shows a rate class and whose tooltip shows the count has published the count. Tooltips carry only what the product is approved to publish.

Differencing through the partner interface. A partner requesting the county total and all but one tract recovers the last tract. Complementary suppression must be applied to the whole published set, and the interface must not allow ad hoc geographies.

Rates on tiny denominators that pass suppression. A tract with 40 residents and 2 cases passes a numerator threshold of 1 and displays a rate of 5,000 per 100,000, which dominates the colour ramp and the reader’s attention. Suppression addresses disclosure, not stability. Apply a separate reliability rule — withhold or flag rates whose denominator or relative standard error falls outside a stated bound — and give unreliable rates a visual treatment distinct from both suppressed and reliable ones.

Accessibility of the map itself. A choropleth that encodes meaning only in colour excludes readers with colour vision deficiency and fails on greyscale printouts of the weekly report. Choose ramps that are distinguishable in luminance, include the value in an accessible table beside the map, and provide a text description of the main pattern for screen-reader users.

Static exports built by hand. A weekly map rebuilt manually drifts in colour, legend and extent. Automate the export from a fixed template, as in Automating Static Map Exports for Weekly Reports.

Fixed Breaks Make Weeks Comparable A single county with an unchanged rate across two weeks. Under quantile breaks recomputed from each week's data, the county falls in the middle class one week and the top class the next, because other counties' rates fell and moved the breaks. A reader comparing the maps concludes the county worsened. Under fixed breaks chosen from a long historical window, the county stays in the same class both weeks, and a class change can only mean its own rate changed. Same rate, different colour — unless the breaks are fixed Recomputed quantile breaks week 36 rate 41, middle class week 37 rate 41, top class looks worse; did not change Fixed breaks week 36 rate 41, middle class week 37 rate 41, middle class a colour change means a rate change Store the breaks as product configuration, review them annually, and never recompute them from the week being mapped Quantile breaks belong in one-off exploration, not in a recurring product

The reliability rule in that list needs its own visual treatment, distinct from both suppression and ordinary values, so a reader can tell the three states apart at a glance:

Three States, Three Treatments A legend and sample map showing three kinds of area. Reliable rates are drawn with the ordinary colour ramp. Rates that pass suppression but have a small denominator or a large relative standard error are drawn with the same colour but a fine dot overlay, marking them as unstable. Suppressed areas are drawn with diagonal hatching and no colour. The three are visually distinct in greyscale, so a printed report preserves the difference between a withheld value, an unreliable one and a trustworthy one. Withheld, unstable and reliable must never look alike reliable ordinary colour ramp unstable colour plus dot overlay suppressed hatched, no colour all three remain distinguishable when the report is printed in greyscale

Compliance & Audit Controls

Every published product must be traceable to a single run, a single suppression pass and a single boundary vintage, and that trace must travel with the product in its metadata. The standards content — lineage, extent, constraints on use, contact and provisional status — is set out in Documenting a Release With ISO 19115 Metadata.

The publication infrastructure is part of the disclosure perimeter. The web map service, the partner interface and the export job should hold credentials only to the published store, never to the analytic archive, so that no configuration error in those services can expose unsuppressed data. Review the set of released tables as a whole under the disclosure process in Privacy-Preserving Spatial Analytics rather than product by product, because differencing attacks combine products.

Production Implementation Checklist

Frequently Asked Questions

Can the web map read directly from our analysis database with a view that applies suppression? It can, and it should not. A view is a configuration, and a single change to it, or a second view created for a different purpose, exposes the archive. A separate published store written only by the suppression stage makes the safe path structural rather than dependent on every future configuration being right.

Why cap zoom if the data are already aggregated to tracts? Because the geometry itself is published at whatever resolution the tiles allow, and some attributes — suppression flags, provisional markers — can still carry information at fine scale. Capping zoom also prevents readers from over-interpreting boundaries, which were never meant to be read at building scale.

How should a correction to a published map be handled? As a new version with its own run identifier, not an overwrite. Publish a correction notice that states what changed and why, keep the superseded version retrievable, and version tile paths so caches cannot keep serving the old product silently.

What should a partner interface allow? Retrieval of the published aggregates at the published geographies for published periods, and nothing else. Arbitrary spatial filters, custom geographies and fine-grained time slicing each create differencing opportunities that the suppression stage never evaluated.

How often should classification breaks be revisited? On a fixed schedule, such as annually, and whenever the distribution of values has moved so far that most areas fall in one class. Record every revision with its date, because a break change is a discontinuity in the product’s visual history.