Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

GIS & Geospatial Data (QGIS, GeoPandas, PostGIS)  Module 5 – Python: Shapely and GeoPandas

Overlay, dissolve, clip and areal weighting

Combine polygon layers with overlay, merge them with dissolve, cut them with clip, move counts between zones by areal weighting, and clear slivers.

  • Intermediate
  • 15 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, geopandas 1.2.0, shapely 2.1.2, pyproj 3.8.0, pandas 3.0.6 and numpy 2.5.3
  • By MySmartCoPilot
Free core, Pro depth: 6 of 15 minutes free
Free: Overlay, dissolve, clip and areal weighting each answer one question · Coverage per ward takes four steps. With a pass: 2 in-depth parts and 3 interview answers, about 9 minutes.

What you will learn

  • Combine two polygon layers with intersection, union, identity and difference overlays
  • Aggregate features by attribute with dissolve, choosing a rule for each column
  • Clean overlay results by clipping to an outline and removing slivers with a precision grid or a minimum area
  • Estimate counts for new zones by areal weighting, and state the assumption it makes

Before you start

What you’ll learn · Before you start

What you will learn

  • Combine two polygon layers with intersection, union, identity and difference overlays
  • Aggregate features by attribute with dissolve, choosing a rule for each column
  • Clean overlay results by clipping to an outline and removing slivers with a precision grid or a minimum area
  • Estimate counts for new zones by areal weighting, and state the assumption it makes

Before you start

On this page

What share of each ward lies within 1 km of a clinic? For W12 it is 82.9 %, for W10 nothing at all, and a buffer, a dissolve, an overlay and a division of areas get those numbers.

Here you meet overlay, dissolve, clip and areal weighting, four operations on polygon layers, and run them end to end on the town. Then you take each apart: the modes of overlay and the pieces nobody asked for, dissolve rules column by column, and how far a count moved by area can be from the truth.

Overlay, dissolve, clip and areal weighting each answer one question

The four operations answer four different questions. Overlay cuts two polygon layers against each other into new pieces, and each piece keeps “the properties from both” layers (GeoPandas, set operations with overlay). dissolve: Merging the features of a layer that share a value into one feature per value, with a rule for each attribute column, such as a sum for counts. merges the features that share a value, “all the geometries within a given group”, into one feature and aggregates their columns (GeoPandas, aggregation with dissolve). Clip cuts one layer to the outline of another and keeps only the first layer’s columns (GeoPandas, clip). areal weighting: Estimating a count for new zones from old ones: each piece of an overlay of the two zone systems gets the share of the old zone's count that matches its share of the old zone's area. It assumes the count is spread evenly. moves a count from one set of zones to another in proportion to the area they share; it is an estimate, not a measurement. Here they are on the town:

Four panels: an overlay cutting C2's ring into two ward pieces, a dissolve of four wards, a clip of households, and an area split.Four operations on the same townoverlaypieces carry ward and clinicW02W032 pieces from C2's ring:W02 + C2 and W03 + C2dissolveone zone, counts summedW01 to W04295 + 696 + 183 + 1,169= 2,343 householdsclip248 households keptareal weightingcounts follow the area60 %of 30040 %of 300180 + 120, if evenBlue: what each operation returns. Dashed: the input.Dark dots: households kept by the clip.

Overlay, dissolve, clip and areal weighting on the town

Text description of the diagram

Overlay: wards W02 and W03 sit side by side and clinic C2's 1 km ring lies across their shared edge. The overlay cuts the ring into two pieces, one in each ward, and each piece carries the columns of both layers: W02 with C2, and W03 with C2.

Dissolve: the four wards of the north row, W01 to W04, drawn with dashed inner edges, become one zone with a single outline. Their household counts are summed: 295 + 696 + 183 + 1,169 = 2,343.

Clip: households around C2 are dots; the 248 inside the ring are dark and kept, the others are pale and dropped. The kept households keep only their own columns.

Areal weighting: a block of 300 households is cut by a catchment's dashed edge into 60 % and 40 % of its area. If the households are spread evenly, 180 go to one catchment and 120 to the other.

Operation Question it answers Columns of the result
Overlay Which parts of A lie in which parts of B? Both layers’
Dissolve What is each group as one shape? The group’s, aggregated
Clip What of A lies inside this outline? A’s only
Areal weighting How much of a count belongs to each new zone? The new zones’ estimates

An overlay’s how chooses which pieces to keep. Intersection keeps the pieces that lie in both layers, union every piece of either, identity all of the first layer cut by the second, difference what of the first lies outside the second, and symmetric difference what lies in exactly one.

An overlay of C2’s ring with the wards gives two pieces that know both their ward and their clinic. A clip of the households to the same ring keeps 248 households and nothing of the ring. Areal weighting assumes the count is spread evenly inside each source zone, so a block cut 60 % to 40 % gives 60 % of its households to one side.

Checkpoint

Check: What overlay, dissolve, clip and areal weighting return

  1. Question 1 of 2 A planner wants a table of the pieces where flood zones and wards overlap, with each piece's ward and flood risk. Which operation gives it?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: An intersection overlay of the wards and the flood zones

    When the result must say which feature of each layer a piece came from, use an overlay; when one layer only needs cutting to an outline, a clip.

  2. Question 2 of 2 The households are clipped to the dissolved 1 km buffers. Which columns does the result have?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The households' own columns and geometry only

    clip(households, cover) returned 2,971 households with the columns household and geometry, and nothing of the buffer layer.

Coverage per ward takes four steps

The opening’s question needs the operations in order. Follow the pipeline before running it:

Interactive · stage by stage From clinics to the share of each ward they reach Step through the four operations of coverage.py, and see what each one hands to the next.
From clinics to the share of each ward they reach, step 6 of 6. Showing Buffer the clinics (8 rings, 25.092 km² summed), Dissolve, Overlay with wards, Divide the areas (W12 82.9 %, W05 8.8 %), Every ward, Clip households. In focus: Clip households.Buffer the clinics8 rings, 25.092 km² summedDissolveone shape, 24.695 km²Overlay with wards11 pieces, ward attachedDivide the areasW12 82.9 %, W05 8.8 %Every wardreindex: W10 is 0 %Clip households2,971 inside

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Eight rings. Each clinic gets a 1 km buffer with 16 segments a quarter. The rings overlap in three places, so their areas add up to more than the ground they cover.
  2. One shape. dissolve with no column merges all eight into one MultiPolygon of 24.695 km². An overlay with the separate rings would have cut every overlap twice.
  3. Cut by the wards. overlay with how="intersection" cuts the shape at every ward edge and keeps the pieces inside wards: 11 pieces, each with its ward column.
  4. Shares of area. Each piece's area divided by its ward's 4 km² is the share within 1 km of a clinic: 82.9 % of W12, 75.5 % of W09, 8.8 % of W05.
  5. The ward with no piece. W10 has no piece at all, so it is missing until the shares are reindexed on every ward with 0. A map without that step would leave W10 blank instead of showing 0 %.
  6. Households reached. clip keeps the households inside the same shape, 2,971 of 5,000, with only their own columns. The town as a whole is 49.9 % covered.

The program does exactly that, then clips the households to the same shape:

town.py: the track's town, in metres of UTM zone 43N Python · overlay/town.py
"""The track's synthetic town in metres of UTM zone 43N (EPSG:32643): 12 square wards of 2 km, 5,000 households
from a seeded generator and 8 clinics. Every lesson of the track asks its questions about this town."""
import random

E0, N0 = 500_000, 2_000_000  # the town's south-west corner: easting and northing in metres
WARD = 2_000  # each ward is a 2 km square
COLS, ROWS = 4, 3  # 4 wards from west to east, 3 from south to north

# Metres east and north of the south-west corner. C2 stands exactly on the edge of W02 and W03, on purpose.
CLINICS = {
    "C1": (1_500, 5_200), "C2": (4_000, 5_000), "C3": (6_500, 4_200), "C4": (2_700, 3_100),
    "C5": (5_200, 2_800), "C6": (900, 1_100), "C7": (5_600, 1_200), "C8": (7_400, 900),
}


def ward_bounds():
    """W01 to W12, north-west first, each as (min x, min y, max x, max y)."""
    out = {}
    for row in range(ROWS):
        for col in range(COLS):
            x0, y0 = E0 + col * WARD, N0 + (ROWS - 1 - row) * WARD
            out[f"W{row * COLS + col + 1:02d}"] = (x0, y0, x0 + WARD, y0 + WARD)
    return out


def households(seed=42, n=5_000):
    """(id, x, y) of n households, most of them around three neighbourhood centres."""
    rng = random.Random(seed)
    centres = [(2_600, 4_300, 700), (5_600, 1_500, 900), (6_900, 4_700, 500)]
    homes = []
    while len(homes) < n:
        if rng.random() < 0.7:
            cx, cy, spread = rng.choice(centres)
            # The sum of three random numbers clusters around its middle, like a bell curve.
            x = cx + spread * 2 * (rng.random() + rng.random() + rng.random() - 1.5)
            y = cy + spread * 2 * (rng.random() + rng.random() + rng.random() - 1.5)
        else:
            x, y = rng.uniform(0, COLS * WARD), rng.uniform(0, ROWS * WARD)
        if 0 < x < COLS * WARD and 0 < y < ROWS * WARD:
            homes.append((f"H{len(homes) + 1:04d}", round(E0 + x, 1), round(N0 + y, 1)))
    return homes


def clinics():
    """(id, x, y) of the 8 clinics."""
    return [(k, E0 + x, N0 + y) for k, (x, y) in CLINICS.items()]
layers.py: wards, buffers, census blocks, catchments and zones Python · overlay/layers.py
"""The town's layers in EPSG:32643 for overlays: wards, households, clinics and their 1 km buffers, 24 census blocks
(each ward split in two at a seeded line), the clinics' catchments (the area nearer to each clinic than to any other),
and two planning zones whose shared edge was digitised a few millimetres off the ward boundary."""
import random

import geopandas as gpd
import shapely
from town import COLS, E0, N0, ROWS, WARD, clinics, households, ward_bounds

CRS = "EPSG:32643"


def wards():
    bounds = ward_bounds()
    return gpd.GeoDataFrame({"ward": list(bounds)}, geometry=[shapely.box(*b) for b in bounds.values()], crs=CRS)


def homes():
    rows = households()
    return gpd.GeoDataFrame({"household": [h for h, _, _ in rows]}, geometry=shapely.points([(x, y) for _, x, y in rows]), crs=CRS)


def clinic_points():
    rows = clinics()
    return gpd.GeoDataFrame({"clinic": [c for c, _, _ in rows]}, geometry=shapely.points([(x, y) for _, x, y in rows]), crs=CRS)


def rings(distance=1_000):
    c = clinic_points()
    return c.set_geometry(c.buffer(distance, quad_segs=16))


def blocks(seed=7):
    """24 census blocks: each ward cut in two by a north-south line at 500 to 1,500 m from its west edge."""
    rng = random.Random(seed)
    rows = []
    for ward, (x0, y0, x1, y1) in ward_bounds().items():
        cut = x0 + rng.randrange(500, 1_501, 100)
        rows += [(ward + "a", ward, shapely.box(x0, y0, cut, y1)), (ward + "b", ward, shapely.box(cut, y0, x1, y1))]
    b = gpd.GeoDataFrame({"block": [r[0] for r in rows], "ward": [r[1] for r in rows]}, geometry=[r[2] for r in rows], crs=CRS)
    inside = gpd.sjoin(homes(), b, predicate="within").groupby("block").size()
    b["households"] = b["block"].map(inside).fillna(0).astype(int)
    return b


def catchments():
    """The part of the town nearer to each clinic than to any other (Voronoi cells, cut to the town)."""
    c = clinic_points()
    town = shapely.box(E0, N0, E0 + COLS * WARD, N0 + ROWS * WARD)
    cells = shapely.voronoi_polygons(shapely.MultiPoint(list(c.geometry)), extend_to=town)
    rows = []
    for cell in cells.geoms:
        name = c.loc[c.intersects(cell), "clinic"].iloc[0]
        rows.append((name, cell.intersection(town)))
    out = gpd.GeoDataFrame({"clinic": [r[0] for r in rows]}, geometry=[r[1] for r in rows], crs=CRS)
    return out.sort_values("clinic").reset_index(drop=True)


def zones():
    """Two planning zones split along y = 2,004,000, but digitised with the edge a few millimetres off."""
    wobble = [0.003, -0.002, 0.004, -0.001, 0.002]
    edge = [(E0 + i * WARD, N0 + 2 * WARD + d) for i, d in enumerate(wobble)]
    north = shapely.Polygon([(E0, N0 + ROWS * WARD), *edge, (E0 + COLS * WARD, N0 + ROWS * WARD)])
    south = shapely.Polygon([(E0, N0), (E0 + COLS * WARD, N0), *edge[::-1]])
    return gpd.GeoDataFrame({"zone": ["North", "South"]}, geometry=[north, south], crs=CRS)
The share of each ward within 1 km of a clinic Python · overlay/coverage.py
"""What share of each ward lies within 1 km of a clinic? Buffer the clinics, dissolve the buffers into one shape,
overlay it with the wards, and divide each piece's area by its ward's; compare W12 with the rings overlaid without the
dissolve; then clip the households to the same shape."""
import geopandas as gpd
from layers import homes, rings, wards

w = wards()
cover = rings(1_000).dissolve()  # 8 buffers become one MultiPolygon, overlaps counted once
print(f"dissolved buffers: {len(cover)} row, a {cover.geom_type.iloc[0]} of {cover.area.iloc[0] / 1e6:.3f} km²")

# Each ward cut to the covered area. keep_geom_type=True keeps polygons only: where a buffer meets a ward
# at a single corner, the intersection there is a point, and an area table has no use for it.
pieces = w.overlay(cover[["geometry"]], how="intersection", keep_geom_type=True)
pieces["share"] = pieces.area / (2_000 * 2_000)
share = pieces.set_index("ward")["share"].reindex(w["ward"], fill_value=0)
print(f"{len(pieces)} pieces; share of each ward within 1 km of a clinic:")
for (ward, s) in share.items():
    print(f"  {ward} {s:6.1%}  {'#' * round(s * 20)}")
print(f"the town: {pieces.area.sum() / w.area.sum():.1%} of {w.area.sum() / 1e6:.0f} km²")

# The same overlay with the 8 rings as they are: ground where two rings overlap becomes one piece per ring.
loose = w.overlay(rings(1_000), how="intersection", keep_geom_type=True)
w12 = loose.loc[loose["ward"] == "W12"].area.sum() / (2_000 * 2_000)
print(f"W12 from the 8 rings without the dissolve: {w12:.1%}")

reached = gpd.clip(homes(), cover)
print(f"\nclip(households, cover): {len(reached):,} of 5,000 households, with their own columns {reached.columns.tolist()}")
c2_ring = rings(1_000).query("clinic == 'C2'")
print(f"clip(households, C2's ring alone): {len(gpd.clip(homes(), c2_ring))} households")

Output

dissolved buffers: 1 row, a MultiPolygon of 24.695 km²
11 pieces; share of each ward within 1 km of a clinic:
  W01  59.1%  ############
  W02  55.9%  ###########
  W03  49.3%  ##########
  W04  39.0%  ########
  W05   8.8%  ##
  W06  69.6%  ##############
  W07  75.1%  ###############
  W08  28.4%  ######
  W09  75.5%  ###############
  W10   0.0%  
  W11  55.6%  ###########
  W12  82.9%  #################
the town: 49.9% of 48 km²
W12 from the 8 rings without the dissolve: 85.3%

clip(households, cover): 2,971 of 5,000 households, with their own columns ['household', 'geometry']
clip(households, C2's ring alone): 248 households

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 coverage.py

Half the town, 49.9 %, lies within 1 km of a clinic, but the wards range from 82.9 % for W12 to 0 % for W10, which has no piece at all and returns only through reindex. The clip found 2,971 households inside, the count of the Shapely lesson’s union.

Overlaying the buffers before dissolving them

Overlaid as eight separate rings, the buffers cut each overlap twice, and the pieces of W12 add up to 85.3 % of the ward instead of 82.9 %. Dissolve the buffers first, so that every place is counted once.

Area Converter Turn the pieces' square metres into hectares or acres when a report needs them: 4,000,000 m² is one ward, 400 ha.

Checkpoint

Check: Coverage per ward, step by step

  1. Question 1 of 2 An analyst overlays the wards with the 8 separate rings, without dissolving them, and sums the pieces' areas per ward. What happens to W12's covered share?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It rises to 85.3 % instead of 82.9 %, because the overlap of two rings in W12 is counted twice

    Dissolve the buffers first. coverage.py dissolves the 8 rings into one shape of 24.695 km², so every place is counted once and W12 is 82.9 % covered.

  2. Question 2 of 2 The overlay of the wards with the dissolved buffers returns 11 pieces for 12 wards. Which ward is missing, and why?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: W10, because no part of it lies within 1 km of a clinic, so it has no piece

    W10 has no piece at all, so a table made from the pieces leaves it out; reindex on every ward with fill_value=0, or a map shows W10 blank instead of 0 %.

Overlays in depth: five modes, stray points and slivers, measured Pro: opens with a Pro, Premium or Ultimate pass

Overlay has five modes, and each answers a different question about the same two layers. It can also hand back pieces you did not ask for, points where shapes touch and slivers where edges were drawn twice; all of them are measured here on the wards and the clinics’ buffers.

In this part:

  • Five overlay modes on the same two layers
  • Stray points where a ring touches a corner of two wards
  • Slivers from an edge digitised twice, and two ways to remove them

2 runnable examples (Python) · about 6 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Dissolve rules and areal weighting, with the errors measured Pro: opens with a Pro, Premium or Ultimate pass

Dissolving and reallocating move numbers, and every column needs its own rule. Here 24 census blocks are dissolved back into their wards and reallocated to the clinics’ catchments, and each result is compared with the households that really live there.

In this part:

  • Each column needs its own aggregation rule
  • Areal weighting assumes an even spread, and the errors show where it fails
  • When to trust a count moved by area

2 runnable examples (Python) · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: move counts by area, and measure the error

Write the two functions of a reallocation, the estimate by area and its error against true counts, and run their sample tests:

Exercise · Medium · Python

Move counts between zones by area, and measure the error

Write two functions in weights.py. reallocate(counts, areas, pieces) estimates a count for each target zone by area weighting: counts and areas give each source zone's count and area, and pieces is a list of (source, target, area), the pieces an overlay of the two zone systems returns. Each piece receives the source's count times the piece's share of the source's area. Return {target: estimate}, rounded to 1 decimal. errors(estimates, truth) returns each target's error as a percentage of its true count, (estimate − truth) ÷ truth × 100, rounded to 1 decimal.

The sample tests use the lesson's example of a 300-household block cut 60 % to 40 %, and two blocks of the town.

Starter code · weights.py

def reallocate(counts, areas, pieces):
    """{target: estimated count}: each piece of an overlay gets its source's count in proportion to its area."""
    # Replace this line: add counts[source] * area / areas[source] to each target, then round to 1 decimal.
    return {}


def errors(estimates, truth):
    """{target: error in % of the true count}, rounded to 1 decimal."""
    # Replace this line: (estimate - truth) / truth * 100 for every target.
    return {}
The sample tests · test_weights.py
from weights import errors, reallocate


def test_one_block_cut_sixty_forty():
    """splits a block of 300 households cut 60 % to 40 % into 180 and 120"""
    got = reallocate({"B1": 300}, {"B1": 1.0}, [("B1", "east", 0.6), ("B1", "west", 0.4)])
    assert got == {"east": 180.0, "west": 120.0}


def test_two_blocks_into_two_zones():
    """adds the pieces of two blocks per zone and keeps the total"""
    counts = {"W06a": 296, "W06b": 120}
    areas = {"W06a": 2.8, "W06b": 1.2}
    pieces = [("W06a", "C4", 2.1), ("W06a", "C2", 0.7), ("W06b", "C4", 0.3), ("W06b", "C5", 0.9)]
    got = reallocate(counts, areas, pieces)
    assert got == {"C4": 252.0, "C2": 74.0, "C5": 90.0}
    assert round(sum(got.values()), 6) == 416


def test_a_source_outside_every_target():
    """gives nothing from a block that no target zone overlaps"""
    assert reallocate({"A": 50, "B": 80}, {"A": 2.0, "B": 2.0}, [("A", "Z", 1.0)]) == {"Z": 25.0}


def test_errors_in_percent():
    """measures the error of each estimate against the true count"""
    assert errors({"C1": 601.0, "C8": 324.0}, {"C1": 572, "C8": 249}) == {"C1": 5.1, "C8": 30.1}
    assert errors({"C5": 454.0}, {"C5": 454}) == {"C5": 0.0}
A hint

Loop over the pieces and add counts[source] * area / areas[source] to the target's running total in a dict; round at the end. For the errors, loop over the targets of truth.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Practice that adapts to you

Practise this lesson

6 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 6 Which columns do the pieces of an intersection overlay of wards and rings carry?

    Choose one answer.

    Show the answer: Question 1 of 6

    Answer: The columns of both layers, here ward and clinic

    The C2 ring cut by W02 and W03 became two pieces, each with its ward and its clinic.

  2. Question 2 of 6 A block of 300 households is cut by a catchment's edge into 60 % and 40 % of its area. What does areal weighting give each side, and what does it assume?

    Choose one answer.

    Show the answer: Question 2 of 6

    Answer: 180 and 120, assuming the households are spread evenly over the block

    300 × 0.6 = 180 and 300 × 0.4 = 120. The numbers are only as good as the assumption that households are spread evenly inside the block.

  3. Question 3 of 6 Census counts come per block, and a health department wants them per clinic catchment, which crosses blocks. Which operations, in which order?

    Choose one answer.

    Show the answer: Question 3 of 6

    Answer: Overlay the blocks with the catchments, share each block's count among its pieces by area, then sum the pieces per catchment

    Moving counts between zone systems that do not nest is areal weighting: overlay, weights by area, sum.

  4. Question 4 of 6 In what order does coverage.py work?

    Choose one answer.

    Show the answer: Question 4 of 6

    Answer: Buffer the clinics, dissolve the buffers, overlay them with the wards, divide each piece's area by its ward's

    Buffer, dissolve, overlay, divide, and reindex so a ward without a piece shows 0 %.

  5. Question 5 of 6 W12's piece of the dissolved cover is 3.316 km² of its 4 km². What share of W12 lies within 1 km of a clinic, in percent to one decimal?

    Type a number.

    Show the answer: Question 5 of 6

    Answer: 82.9 % (anything from 82.8 to 83 counts)

    3.316 ÷ 4 = 0.829, the 82.9 % that coverage.py prints for W12.

  6. Question 6 of 6 A map of covered shares is built from the pieces of the overlay and shows W10 blank. What change makes it right?

    Choose one answer.

    Show the answer: Question 6 of 6

    Answer: Reindex the shares on every ward with fill_value=0, so W10 shows 0 %

    Results built from pieces cover only the places that produced a piece. Reindex on the full list of wards before mapping or reporting.

Interview questions

Warm-up (fresher): What is the difference between clip and an intersection overlay?

Both keep only the parts of a layer that fall inside another. Clip treats the second layer as an outline and returns the first layer’s features cut to it, with their own columns only. An intersection overlay treats both layers as data: a ring cut by two wards becomes two pieces that each know their ward and their clinic. Clip a layer to a study area; overlay when each piece must say where it came from.

Three longer questions continue in the module’s bank, each with what it tests and how to start:

  1. Fresher to mid

    A coverage report says 85.3 % of ward W12 lies within 1 km of a clinic, but the planning team measured 82.9 % on the same data. The report overlays the wards with each clinic's buffer and sums the pieces per ward. Explain the gap and rebuild the calculation so that it cannot recur.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    Census blocks with households and a density column are dissolved into wards with aggfunc={"households": "sum", "density": "mean"}. A ward of 4 km² holds 1,169 households, yet its density comes out well below what those two numbers give. What is wrong, what is the right density, and how do you set up the dissolve?

    Model answer, Pro. First step and follow-ups

  3. Mid to senior

    A health department has households per census block and needs households per clinic catchment, whose boundaries cross the blocks. Describe how you would estimate them, how wrong the estimates can be, and how you would report them honestly.

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Which question does each of overlay, dissolve, clip and areal weighting answer?

    Overlay: which parts of A lie in which parts of B, keeping both layers' columns. Dissolve: what each group is as one shape, with its columns aggregated. Clip: what of A lies inside an outline, with A's columns only. Areal weighting: how much of a count belongs to each new zone, as an estimate.

  2. Which pieces does each overlay mode keep?

    Intersection keeps the pieces in both layers; union every piece of either; identity all of the first layer, cut by the second; difference what of the first lies outside the second; symmetric difference what lies in exactly one.

  3. What does areal weighting assume about a count?

    That it is spread evenly inside each source zone, so a block cut 60 % to 40 % hands 60 % of its households to one side. The result is an estimate, not a measurement.

  4. Which steps answer "what share of each ward lies within 1 km of a clinic"?

    Buffer the clinics, dissolve the buffers into one shape, overlay it with the wards, work out each piece's share of its ward's area, and reindex so that a ward with no piece, such as W10, shows 0. W12 came out at 82.9 % and the whole town at 49.9 %.

  5. Why dissolve the buffers before overlaying them with the wards?

    As separate rings, every overlap is cut out and counted twice: W12's pieces added up to 85.3 % of the ward instead of 82.9 %.

  6. How does clip differ from an intersection overlay?

    Clip treats the second layer as an outline and returns the first layer's features cut to it, with their own columns only. An intersection overlay treats both layers as data, so each piece knows its place in both, such as its ward and its clinic.

Key takeaways

  • Overlay cuts two layers into pieces that keep both layers’ columns, dissolve merges features by a value, clip cuts a layer to an outline and keeps its own columns, and areal weighting moves counts by shared area.
  • Coverage per ward is a buffer, a dissolve, an overlay and a division of areas, with every ward reindexed so that a ward with no piece shows 0.
  • Dissolve buffers before an overlay, or each overlap is counted twice.

Terms in this lesson

areal weighting
Estimating a count for new zones from old ones: each piece of an overlay of the two zone systems gets the share of the old zone's count that matches its share of the old zone's area. It assumes the count is spread evenly.
dissolve
Merging the features of a layer that share a value into one feature per value, with a rule for each attribute column, such as a sum for counts.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.