Clustered Data
MapServer can combine point features together into clusters based on their location, using the CLUSTER directive.
In our example points representing trees are clustered together, with the number of points in each cluster used as the label.
Mapfile Notes
The Mapfile contains a class for clustered features, and a class for non-clustered features. If there is no expression
in the CLASS
then it will be applied to all features. A feature is checked against each CLASS
until a match is found,
from first to last. If you want to add a "catch-all" CLASS
then add it last in the Mapfile without an EXPRESSION
.
# class for clustered features
CLASS
EXPRESSION ("[Cluster_FeatureCount]" != "1")
...
END
# add a class for non-clustered features
CLASS
...
Code
Example
- MapServer request: http://localhost:5000/?map=/etc/mapserver/clusters.map&mode=map&layer=trees
- OpenLayers example: http://localhost:5001/clusters.html
clusters.js
import '../css/style.css';
import ImageWMS from 'ol/source/ImageWMS.js';
import Map from 'ol/Map.js';
import OSM from 'ol/source/OSM.js';
import View from 'ol/View.js';
import { Image as ImageLayer, Tile as TileLayer } from 'ol/layer.js';
const mapserverUrl = import.meta.env.VITE_MAPSERVER_BASE_URL;
const mapfilesPath = import.meta.env.VITE_MAPFILES_PATH;
const layers = [
new TileLayer({
source: new OSM(),
}),
new ImageLayer({
extent: [2968743.65508978, 8038921.67212233, 2982981.8632402, 8053818.05714347],
source: new ImageWMS({
url: mapserverUrl + mapfilesPath + 'clusters.map&',
params: { 'LAYERS': 'trees', 'STYLES': '' },
ratio: 1
}),
}),
];
const map = new Map({
layers: layers,
target: 'map',
view: new View({
center: [2975862.75916499, 8046369.8646329],
zoom: 14,
}),
});
clusters.map
MAP
NAME "Clusters"
EXTENT 26.668678 58.339241 26.796582 58.40941
UNITS DD
SIZE 800 600
PROJECTION
"init=epsg:4326"
END
FONTSET "data/fonts/fontset.txt"
WEB
METADATA
"ows_enable_request" "*"
"ows_srs" "EPSG:4326 EPSG:3857"
END
END
SYMBOL
NAME "circle"
TYPE ELLIPSE
POINTS
1 1
END
FILLED TRUE
END
LAYER
NAME "trees"
STATUS OFF
TYPE POINT
CONNECTIONTYPE OGR
# cluster does not seem to work with the native FLATGEOBUF driver
# CONNECTIONTYPE FLATGEOBUF
# DATA "data/osm/natural.fgb"
CONNECTION "data/osm/natural.fgb"
CLUSTER
MAXDISTANCE 20
REGION "ellipse"
END
# LABELITEM "Cluster_FeatureCount"
# PROCESSING "CLUSTER_ALGORITHM=SIMPLE"
# PROCESSING "CLUSTER_GET_ALL_SHAPES=OFF"
# PROCESSING "CLUSTER_KEEP_LOCATIONS=OFF"
CLASSITEM "Cluster_FeatureCount"
# class for clustered features
CLASS
EXPRESSION ("[Cluster_FeatureCount]" != "1")
STYLE
SIZE 30
# In MapServer 8.2 we can use an expression for SIZE
# SIZE ([Cluster_FeatureCount] / 3)
SYMBOL "circle"
COLOR "#4A993A"
END
LABEL
FONT "LiberationSans"
TEXT "[Cluster_FeatureCount]"
TYPE TRUETYPE
SIZE 12
COLOR 255 255 255
ALIGN CENTER
FORCE TRUE # otherwise numbers can disappear
END
END
# add a class for non-clustered features
CLASS
STYLE
SIZE 20
SYMBOL "circle"
COLOR "#4A993A"
END
LABEL
FONT "LiberationSans"
TEXT "1"
TYPE TRUETYPE
SIZE 10
COLOR 255 255 255
ALIGN CENTER
END
END
END
END
Exercises
-
Try changing the
MAXDISTANCE
andREGION
parameters to see the effect this has on clustering.