Week 9: Ripley’s K Worked Example
From a GIScience question to an interactive MVC application · 15.06.2026
Materials
Download Week 9 Slides (PDF) →
Download the complete Week 9 Java project (ZIP) →
Learning Goals
This week brings the course ideas together in one complete example. By the end, you should be able to:
- distinguish clustered, random, and dispersed point patterns;
- explain why Ripley’s K is evaluated at several distance scales;
- compare an observed K value with complete spatial randomness (CSR);
- explain simulation envelopes and translation edge correction;
- translate the analysis into classes, loops, conditions, and an MVC application.
1. From a Spatial Question to a Measurement
The question: are the events in a study area more clustered or more dispersed than we would expect from a random pattern?
The events could be trees, disease cases, shops, crimes, or traffic accidents. Their meanings differ, but the program receives the same abstraction: a list of (x, y) coordinates inside a study window.
Ripley’s K starts with a simple operation: choose an event, draw a circle of radius d, and count the other events inside it. Repeat this for every event and for several radii. The important question is therefore not simply “is the pattern clustered?”, but “at which distances is it clustered or dispersed?”
| Observed result | Interpretation at distance d |
|---|---|
| More neighbours than under CSR | Clustered |
| Similar neighbour counts to CSR | Consistent with CSR |
| Fewer neighbours than under CSR | Dispersed |
K and the easier-to-read L transformation
Under theoretical CSR, the expected value is K(d) = pi * d^2. Because K naturally grows as the radius grows, we also calculate:
L(d) - d = sqrt(K(d) / pi) - d
This transformation moves the theoretical random reference to zero: values above zero suggest clustering, values below zero suggest dispersion, and values near zero suggest a pattern close to CSR. The simulation envelope gives the stronger comparison used by the application.
2. Randomness, Envelopes and Edges
Monte Carlo simulation
One random pattern can be unusual by chance, so the program generates 199 CSR patterns. Each simulation uses the same number of events and the same 800 × 600 study window as the observed pattern. At each radius, the central 95% of simulated K values forms a pointwise simulation envelope.
- Above the upper envelope: evidence of clustering at that radius.
- Inside the envelope: consistent with CSR at that radius.
- Below the lower envelope: evidence of dispersion at that radius.
Translation edge correction
An event near the boundary has less observable space around it: some possible neighbours would lie outside the study window. The implementation compensates for this using the overlap between the window and a translated copy of itself.
overlapArea = (width - abs(dx)) * (height - abs(dy))
edgeWeight = studyArea / overlapArea
Pairs with less observable overlap receive a larger weight. This corrects a measurement problem; it does not invent points outside the window.
3. The Interactive Application
Code/Week9/
|-- src/at/ac/univie/gis/week9/ripleyk/
| |-- model/
| | |-- EventPoint.java one coordinate pair
| | |-- RipleyKModel.java events, K estimator and simulations
| | `-- RipleyKResult.java one result row and its interpretation
| |-- view/
| | `-- RipleyKView.java draws events and scan circles
| `-- controller/
| `-- RipleyKController.java input, analysis and result table
`-- test/
`-- RipleyKModelCheck.java repeatable numerical checks
Run: at.ac.univie.gis.week9.ripleyk.controller.RipleyKController.
Click in the white study area to create a point pattern, then select Compute K. The pattern is frozen, scan circles are shown, and a result table reports radii 25, 50, 75, and 100 pixels.
Model: geometry without GUI dependencies
EventPoint deliberately does not use java.awt.Point. The model represents spatial data and performs the analysis without depending on Swing or AWT, so the numerical logic can be tested independently.
public class EventPoint {
private final double x;
private final double y;
public EventPoint(double x, double y) {
this.x = x;
this.y = y;
}
public double distanceTo(EventPoint other) {
double dx = x - other.x;
double dy = y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
Controller: listen, update, repaint
The controller repeats the interaction cycle from Weeks 7 and 8. It receives a mouse event, updates the model, and asks the view to redraw. Once analysis starts, the point pattern is frozen so the displayed results still match the data.
view.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (model.isAnalysisMode()) {
status.setText("The pattern is frozen in analysis mode.");
return;
}
model.addEvent(e.getX(), e.getY());
view.repaint();
}
});
Core estimator: formula becomes loops and conditions
The mathematical notation becomes an ordered-pair loop. For each pair, the model calculates an edge weight and one distance, then checks that distance against every radius.
for (int i = 0; i < n; i++) {
EventPoint first = points.get(i);
for (int j = 0; j < n; j++) {
if (i == j) {
continue;
}
EventPoint second = points.get(j);
double dx = Math.abs(first.getX() - second.getX());
double dy = Math.abs(first.getY() - second.getY());
double overlapArea = (width - dx) * (height - dy);
double edgeWeight = area / overlapArea;
double distance = first.distanceTo(second);
for (int r = 0; r < radii.length; r++) {
if (distance <= radii[r]) {
weightedCounts[r] += edgeWeight;
}
}
}
}
After counting, each radius is normalised by the study area and the number of ordered event pairs:
K[d] = area * weightedCounts[d] / (n * (n - 1))
Monte Carlo: a loop around the same estimator
The random reference does not require a second K algorithm. The model generates CSR point sets and calls the same computeK() method used for the observed events.
for (int simulation = 0;
simulation < simulationCount;
simulation++) {
List<EventPoint> randomEvents = new ArrayList<>();
for (int i = 0; i < events.size(); i++) {
randomEvents.add(new EventPoint(
random.nextDouble() * width,
random.nextDouble() * height));
}
double[] simulatedK = computeK(randomEvents, width, height);
// Store one simulated value for each radius.
}
Result object: data and interpretation stay together
Each RipleyKResult represents one row in the table. It stores the radius, observed and expected K, L(d)-d, and both envelope limits. Its interpretation rule is explicit and reusable:
public String getInterpretation() {
if (observedK > upperEnvelope) {
return "Clustered";
}
if (observedK < lowerEnvelope) {
return "Dispersed";
}
return "Consistent with CSR";
}
4. How to Read the Result Table
| Column | Meaning |
|---|---|
Radius d |
The distance scale currently being analysed. |
Observed K |
The edge-corrected estimate for the points you clicked. |
CSR pi*d^2 |
The theoretical K value under complete spatial randomness. |
L(d)-d |
A transformed value whose theoretical CSR reference is zero. |
95% lower / upper |
The pointwise envelope from the 199 simulated CSR patterns. |
Interpretation |
Clustered, dispersed, or consistent with CSR at this radius. |
Interpret one radius at a time. A point pattern can be clustered at short distances, consistent with CSR at medium distances, and dispersed at longer distances. Avoid assigning one global label unless the result is stable across the full distance range.
The demo measures distance in pixels. Real GIS analyses should use an appropriate projected coordinate reference system with meaningful distance units, not raw longitude and latitude.
5. The Complete Modelling Cycle
- Phenomenon: events occur in a bounded study area.
- Question: does their arrangement differ from spatial randomness?
- Conceptual model: events, distances, neighbours, scale, boundaries, and a random reference.
- Object model:
EventPoint,RipleyKModel,RipleyKResult, view, and controller. - Algorithm: pair loops, distance tests, edge weights, normalisation, simulation, and percentiles.
- Interface: draw a pattern, compute K, and interpret one table row per radius.
This is the central lesson of the worked example: a GIScience method becomes software by making its concepts, responsibilities, state changes, and calculations explicit.