メインコンテンツまでスキップ
For the complete documentation index, see llms.txt.

Create a temperature map

In this example, you'll process GFS temperature data from NOAA using Raster MTS. This is a multi-band dataset where each band is a single timestamp.

The goal is to create a raster-array source and add it on a map to visualize temperature.

Prerequisites​

To follow along, you'll need:

  • GFS data (sample download below)
arrow-downSample GFS temperature data

Environment variables​

Throughout this example, you'll use the following required environment variables:

  • ACCOUNT - Set this to your account username.
  • ENDPOINT - The path to the Mapbox tilesets API.
  • RECIPE_LOCATION - The local file location of your Raster MTS recipe.
  • SOURCE_NAME - The name used to create your tileset source. Once your tileset source has been created, you must reference that returned tileset source URI in your recipe.
  • SOURCE_LOCATION - The local file location of your raster source.
  • TILESET_ID - A unique identifier given to your tileset. A tileset ID always starts with your Mapbox username, followed by the tileset's unique alphanumeric identifier: username.identifier.
  • YOUR_SECRET_MAPBOX_ACCESS_TOKEN - A secret token for your Mapbox account with tilesets:write (for uploading source, creating tileset and publish job) and tilesets:read scope (for getting job status).

And when replacing these variables in code snippets or commands, refer to this list:

ACCOUNT=your-account-name
ENDPOINT="https://api.mapbox.com/tilesets/v1"
RECIPE_LOCATION="/path/to/file/gfs-temperature.json"
SOURCE_NAME=gfs-temperature-source
SOURCE_LOCATION="/path/to/file/gfs-temperature.nc"
TILESET_ID=your-account-name.gfs-temperature
YOUR_SECRET_MAPBOX_ACCESS_TOKEN="<Insert your own sk.* token here>"

Review raster source metadata​

The GDAL tool gdalinfo is a useful tool for understanding the structure of your data.

Running gdalinfo on this sample source, you'll see the (truncated) output:

$gdalinfo gfs-temperature.nc
...
Band 1 Block=1440x45 Type=Float32, ColorInterp=Undefined
NoData Value=-9999
Unit Type: K
Metadata:
amip=ta
coordinates=reftime time height_above_ground3 latitude longitude
description=Air temperature is the bulk temperature of the air, not the surface (skin) temperature.
grib=11 E130
Grib2_Generating_Process_Type=Forecast
Grib2_Level_Desc=Specified height level above ground
Grib2_Level_Type=103
Grib2_Parameter={0,0,0}
Grib2_Parameter_Category=Temperature
Grib2_Parameter_Discipline=Meteorological products
Grib2_Parameter_Name=Temperature
Grib2_Statistical_Process_Type=UnknownStatType--1
Grib_Variable_Id=VAR_0-0-0_L103
grid_mapping=LatLon_721X1440-0p13S-180p00E
long_name=Temperature @ Specified height level above ground
NETCDF_DIM_height_above_ground3=2
NETCDF_DIM_time=0
NETCDF_VARNAME=Temperature_height_above_ground
standard_name=air_temperature
units=K
_FillValue=-9999

Create a tileset source​

First, you'll create a tileset source by uploading your GFS data to MTS. If you're using the API directly, you'll need to make a request for each individual source file that you'll be referencing in your recipe. The example GFS data you're processing has only a single source file, so you'll need to make the following POST request once.

curl \
-X POST "${ENDPOINT}/sources/${ACCOUNT}/${SOURCE_NAME}?access_token=${YOUR_SECRET_MAPBOX_ACCESS_TOKEN}" \
-F file=@${SOURCE_LOCATION} \
--header "Content-Type: multipart/form-data"

Create a recipe​

A recipe is a set of instructions used for processing raster data. To use your recipe you will need to create a file and add your own information:

  1. Create a .json file named gfs-temperature.json.
  2. Paste in the recipe below.
  3. Replace {ACCOUNT} and {SOURCE_NAME} with your own values.
{
"version": 1,
"type": "rasterarray",
"sources": [
{
"uri": "mapbox://tileset-source/{ACCOUNT}/{SOURCE_NAME}"
}
],
"minzoom": 0,
"maxzoom": 3,
"layers": {
// Layer name "2t" is based on naming conventions from https://cfconventions.org/
// 2t represents air temperature at 2 meters above ground.
"2t": {
"tilesize": 256,
"offset": -100,
"scale": 0.1,
"resampling": "bilinear",
"buffer": 1,
"units": "K",
"source_rules": {
"filter":[
"all",
["==",["get","NETCDF_VARNAME"],"Temperature_height_above_ground"],
["==",["get","NETCDF_DIM_height_above_ground3"],"2"]
],
"name":["to-number",["get","NETCDF_DIM_time"]],
"order":"asc"
}
}
}
}

Note

The source_rules field allows you to select a single band within a raster file. For example, in this recipe, the temperature data exists in a band labeled with "Temperature_height_above_ground".

The following construct indicates that Raster MTS should only process bands that have a NETCDF_VARNAME that includes Temperature_height_above_ground where the NETCDF_DIM_height_above_ground3 dimension is 2.

"filter":[
"all",
["==",["get","NETCDF_VARNAME"],"Temperature_height_above_ground"],
["==",["get","NETCDF_DIM_height_above_ground3"],"2"]
],

The recipe then names the constructed slice of data with:

"name":["to-number",["get","NETCDF_DIM_time"]],

These value will be later available as "band" used to add on the map.

The recipe then organizes those distinct slices of data with:

"sort_key":["to-number",["get","NETCDF_DIM_time"]],
"order":"asc"

Create an empty tileset​

Now you will create an empty tileset and provide the recipe to be used for processing.

curl \
-X POST "${ENDPOINT}/${TILESET_ID}?access_token=${YOUR_SECRET_MAPBOX_ACCESS_TOKEN}" \
-d @"${RECIPE_LOCATION}" \
--header "Content-Type:application/json"

Note

If you're using the API directly, you'll need to wrap your recipe in an additional JSON structure to include a recipe and name property.

{
"recipe": {...},
"name": "example_tileset_name"
}

Publish a tileset​

At this point you have uploaded a source, created an empty tileset, and provided a recipe to be used for processing the source to this tileset. Now you can start processing your tileset by publishing it.

curl -X POST "${ENDPOINT}/${TILESET_ID}/publish?access_token=${YOUR_SECRET_MAPBOX_ACCESS_TOKEN}"

Review tileset job information​

At this point, Raster MTS will begin to process your job with a job_id. You can retrieve your job's information by calling the API endpoint below with your job_id.

$curl "\${ENDPOINT}/\${TILESET_ID}/jobs/{job_id}?access_token=\${YOUR_SECRET_MAPBOX_ACCESS_TOKEN}"

Review tileset TileJSON​

Once the tileset is finished processing, you can retrieve TileJSON for this tileset, which stores all the useful metadata that can be used for map visualizations.

$curl "\${ENDPOINT}/\${TILESET_ID}.json?access_token=\${YOUR_SECRET_MAPBOX_ACCESS_TOKEN}"

Below is the (truncated) output

"raster_layers": [
{
"fields": {
// Values extracted from NetCDF's "NETCDF_DIM_time" variables become bands
// Used in "raster-array-band" paint property
"bands": ["0", "3", "6"...],
"buffer": 1,
"name": "2t",
"offset": 0,
// Used in "raster-color-range" paint property
"range": [
204.5353240966797,
323.64263916015625
],
"scale": 1,
"tilesize": 256,
"units": ""
},
// Used in "raster-array-layer" layout property
"id": "2t",
"maxzoom": 3,
"minzoom": 0
}
],

The id, band and range keys in the TileJSON identify which layer and band to display and how to assign colors to the values.

Add tileset to map​

Using this tileset as a raster-array source, you will add it as a raster layer on the map.

You will use raster-array-band to allot value 3, which represents the band named 3 in the source NetCDF file. You will use paint properties to assign color using Mapbox GL JS.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Create a temperature map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.28.1/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.28.1/mapbox-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 mapboxgl.Map({
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
container: 'map',
style: 'mapbox://styles/mapbox/light-v11',
zoom: 0,
center: [0, 0],
projection: 'mercator'
});

map.on('load', () => {
map.addSource('gfs-temperature', {
type: 'raster-array',
// Replace this URL with a 'mapbox://TILESET_ID'
url: 'mapbox://mapbox.gfs-temperature',
tileSize: 256
});
map.addLayer({
id: 'gfs-temperature-layer',
type: 'raster',
source: 'gfs-temperature',
// If your tileset has multiple layers, you can specify which one to use with the 'source-layer'.
// In this example we're specifying the '2t' temperature layer defined in the recipe above.
'source-layer': '2t',
paint: {
'raster-color-range': [204, 323],
'raster-array-band': '3',
'raster-color': [
'interpolate',
['linear'],
['raster-value'],
204,
'#50509B',
266,
'#FAFAA0',
323,
'#96053C'
],
'raster-resampling': 'nearest'
}
});
});
</script>

</body>
</html>

Troubleshooting​

Here are solutions to some common integration problems:

Empty Tileset

  • If you receive an empty tileset error when trying to publish, check that you updated the recipe with your credentials in the Create A Recipe step.
このexampleは役に立ちましたか?