Skip to main content

WMS: Web Map Service

WMS is a standard of the Open Geospatial Consortium (OGC).

WMS provides a simple HTTP interface for requesting geo-registered map images from one or more distributed geospatial databases.

References

These are links to OGC standards and websites:

Arraylake implements WMS version 1.3.0, supporting the GetCapabilities, GetMap, and GetLegendGraphic requests. GetFeatureInfo is not yet supported and returns an OperationNotSupported service exception.

WMS shares its rendering pipeline with the Tiles service: the same coordinate detection, styling, colormaps, and multiscale (pyramid) support apply to both. If you are building a web map with a tiling library such as MapLibre, Mapbox, or Leaflet, prefer the Tiles service; use WMS when integrating with GIS tools (QGIS, ArcGIS) or other software that speaks the WMS protocol or needs a simple static image.

Activating WMS for Arraylake Datasets

Enable WMS Service

WMS can be activated using the Arraylake command line interface (CLI):

al compute enable {org} wms
note

Arraylake currently only supports enabling WMS on an organization-wide basis. This is subject to change in future releases.

Dataset Requirements

WMS works best when datasets are compliant with CF Conventions, particularly around coordinates. Specifically it looks for the CRS in a grid_mapping variable (or falls back to a variable named spatial_ref or crs if a grid mapping variable is not detected). If neither of these are present, we assume the CRS to be EPSG:4326. If a projected CRS is detected, we search for projected X and Y coordinates (those with the standard_name attribute set as projection_x_coordinate and projection_y_coordinate). If a geographic CRS is detected, we search for latitude and longitude coordinate variables (those with standard_name attribute set as latitude or longitude or units attribute with degrees_north and degrees_east). If these attributes are present, we attempt to make a best guess using the names of the coordinate variables present. We strongly recommend you annotate your dataset explicitly by adding a grid mapping variable, and the associated coordinate variables with the right standard_name and units attributes.

WMS URL Structure

WMS endpoints can be accessed via the following URL schema, referred to as {base_url} below.

https://compute.earthmover.io/v1/services/wms/{org}/{repo}/{branch|commit|tag}/{path/to/group}/wms

Where

  • {org} is the name of your Arraylake organization
  • {repo} is the name of the Repo
  • {branch|commit|tag} is the branch, commit, or tag within the Repo to use to fulfill the request
  • {path/to/group} is the path to group within the Repo that contains an xarray Dataset. If the dataset is stored in the root group, this should be omitted.

All examples use the HTTP GET protocol. Specific examples in this guide use the public GFS forecast Repo.

Queries

GetCapabilities

Returns the service metadata: available layers, their bounding boxes, dimensions (e.g. time), and styles. The response is XML by default; pass format=json (or send an Accept: application/json header) to receive the same document as JSON.

curl "https://compute.earthmover.io/v1/services/wms/earthmover-public/noaa-gfs-forecast/main/wms?service=WMS&version=1.3.0&request=GetCapabilities"

Requests for version 1.1.1 are answered with a 1.3.0 capabilities document, per the WMS version negotiation rules.

GetMap

Renders a map image for a layer.

curl "https://compute.earthmover.io/v1/services/wms/earthmover-public/noaa-gfs-forecast/main/wms?service=WMS&version=1.3.0&request=GetMap&layers=temperature_2m&styles=raster/default&crs=EPSG:3857&bbox=-20037508,-20037508,20037508,20037508&width=512&height=512&colorscalerange=-30,40"

GFS temperature map

Required parameters:

  1. version: must be 1.3.0;
  2. layers: the name of the variable to render;
  3. bbox: the region to render as minx,miny,maxx,maxy, expressed in the requested CRS;
  4. width and height: the image size in pixels;

Optional parameters:

  1. crs: the Coordinate Reference System to render to. Any CRS resolvable by pyproj (e.g. any EPSG code) is supported. Defaults to EPSG:4326;
  2. styles: raster/{colormap}, where {colormap} is any of matplotlib's colormaps. Defaults to raster/default;
  3. colorscalerange=min,max: the range of the color scale. When omitted, the variable's valid_min/valid_max attributes are used if present, otherwise the range is autoscaled from the data;
  4. colormap: a custom colormap as a JSON-encoded dictionary with numeric keys (0–255) and hex color values, overriding styles;
  5. abovemaxcolor / belowmincolor: color for values outside colorscalerange. Accepts extend, transparent, a hex color, or a named color;
  6. time and elevation: select along the dataset's time and vertical dimensions;
  7. format: image/png (default) or image/jpeg;
  8. transparent: whether areas without data are transparent (default true; PNG only, JPEG is always opaque);
  9. bgcolor: background color for non-transparent maps in 0xRRGGBB format;
  10. exceptions: how errors are reported — XML (default, a ServiceExceptionReport), INIMAGE (the error is drawn into the map image), or BLANK (an empty image).

Any other dataset dimension can be selected by passing it as a query parameter named after the dimension, for example &step=1+hour for a dataset with a step dimension. Unselected extra dimensions default to their first value.

note

Per the WMS 1.3.0 specification, bbox coordinates follow the axis order of the requested CRS. For north-first CRSes like EPSG:4326 this means bbox=miny,minx,maxy,maxx (latitude first), while EPSG:3857 uses the familiar minx,miny,maxx,maxy.

For multiscale (pyramid) datasets, the service automatically renders from the overview level best matching the requested resolution, and reports the level used in the X-Multiscale-Level response header.

GetLegendGraphic

Returns a legend image for a layer, matching the styling parameters used in GetMap requests.

curl "https://compute.earthmover.io/v1/services/wms/earthmover-public/noaa-gfs-forecast/main/wms?service=WMS&version=1.3.0&request=GetLegendGraphic&layer=temperature_2m&colorscalerange=-30,40&width=400&height=100"

GFS temperature legend

Parameters:

  • layer: the name of the variable to generate a legend for (required);
  • styles, colorscalerange, colormap, abovemaxcolor, belowmincolor: should match the values used in the corresponding GetMap request;
  • width and height: the image size in pixels (default 100×100);
  • vertical: orient the colorbar vertically (default false);
  • show_label: whether to draw the layer's long_name [units] as the axis label (default true).

Integrating with Tools

QGIS

The service produces standard WMS 1.3.0 capabilities documents, so it can be added to QGIS as a regular WMS layer.

  1. Right-click on WMS/WMTS in the Browser (left sidebar by default) and add a "New Connection".
  2. In the URL box, use the {base_url} for your dataset, e.g. https://compute.earthmover.io/v1/services/wms/earthmover-public/noaa-gfs-forecast/main/wms. If your service is not public, configure Basic Authentication for the connection.
  3. Expand the connection and add any of its layers to your project.

MapLibre/Mapbox

A WMS GetMap request returns a single georeferenced image for exactly the region you ask for. In MapLibre (or Mapbox) this maps naturally onto an image source: one GetMap request draped over the basemap at its corner coordinates. WMS also works as a tiled raster source (a tiles URL template with the {bbox-epsg-3857} token), but this example demonstrates the single-image case.

This example drapes a single map image of 2-meter temperature over the continental United States.

Coordinate system handling

The service reprojects data from the dataset's native CRS to whatever crs you request, so the choice of request CRS is about matching the display, not the data. MapLibre renders in Web Mercator, and an image source stretches the image linearly in mercator space between its corners — so:

  1. Request the image with crs=EPSG:3857 and a bbox in mercator meters.
  2. Give the image source the same four bbox corners, converted to longitude/latitude — that is the coordinate system MapLibre expects for coordinates, regardless of the image's CRS.
Code
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Arraylake WMS Example (MapLibre)</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href='https://unpkg.com/maplibre-gl@5.9.0/dist/maplibre-gl.css' rel='stylesheet'>
<script src='https://unpkg.com/maplibre-gl@5.9.0/dist/maplibre-gl.js'></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id='map'></div>
<script>
const map = new maplibregl.Map({
container: 'map',
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
zoom: 3,
center: [-95, 38],
});

map.on('style.load', () => {
// GetMap request for the continental US in EPSG:3857
// (bbox is lon -130..-60, lat 20..55 in mercator meters)
map.addSource('wms-image-source', {
'type': 'image',
'url': 'https://compute.earthmover.io/v1/services/wms/earthmover-public/noaa-gfs-forecast/main/wms?service=WMS&version=1.3.0&request=GetMap&layers=temperature_2m&styles=raster/default&crs=EPSG:3857&bbox=-14471534,2273031,-6679169,7361866&width=1024&height=669&colorscalerange=-30,40&transparent=true',
// The same corners as the bbox, in lon/lat
'coordinates': [
[-130, 55],
[-60, 55],
[-60, 20],
[-130, 20]
]
});
map.addLayer(
{
'id': 'wms-image-layer',
'type': 'raster',
'source': 'wms-image-source',
'paint': {'raster-opacity': 0.8}
}
);
});
</script>

</body>
</html>

Help! I don't see anything!

  1. Make sure all required parameters are set (see the GetMap section), and check the bbox axis order for your CRS.
  2. If you get a 413 response, the request covers too much data at full resolution. Request a smaller area or fewer pixels, or add multiscale overviews to your dataset.
  3. Ensure the dataset's coordinate variables have appropriate CF attributes set (see Dataset Requirements).
  4. If no colorscalerange is given and the data has no valid_min/valid_max attributes, the color scale is autoscaled per request — set colorscalerange explicitly for consistent styling.