Map integration

The Chloris Platform provides web maps which may be integrated into your web applications. Alternatively, you may choose to export tiff files for use in your own web mapping solutions, but may still want to use Chloris map styling for consistency. This page describes the options available for integrating Chloris maps into your web applications, complete with color maps and legends.

Layers config

Each site may have different layers available, so the Chloris Platform provides a "layers config" file at {dataPath}/layers.json that describes the available layers and their properties. As of version 1.9.0, the layers config files for all sites comply with this JSON schema.

The following layers ("productTypes") are available for most sites:

  • stock
  • change
  • cumulative_change
  • forest
  • non_forest (only the non-forest pixels from the forest layer)
  • forest_area_gain
  • forest_area_loss
  • forest_area_degradation

For some productTypes, multiple variants (e.g. dynamic-30m) may be made available based on different webtiling methods, analysis resolutions, zoom levels, or other factors. See the layers config file for details.

Here is an example for how to retrieve the layers config for a reporting unit using the chloris-app-sdk in Python:


import urllib3
from chloris_app_sdk import ChlorisAppClient

http = urllib3.PoolManager()

# create the client
client = ChlorisAppClient(
    organization_id="your-organization-id",
    refresh_token="your-refresh-token", # env: CHLORIS_REFRESH_TOKEN
    # or
    # id_token="your-id-token" # env: CHLORIS_ID_TOKEN
)

reporting_unit_id = 'abcd1234'

# get the reporting unit entry with downloads (if available)
reporting_unit_entry = client.get_reporting_unit(reporting_unit_id, include_layers_config=True)

if not reporting_unit_entry.get('layers'):
    raise Exception('No layers available for this reporting unit')

print(reporting_unit_entry['layersConfig'])

Layer types

Dynamic webtile layers

For sites processed or updated since 1.6.0, the Chloris Platform provides dynamically generated webtiles for all map layers by default. Dynamic webtiles are provided as XYZ tiles via REST API of the general form: GET https://app.chloris.earth/tiles/cog/tiles/WebMercatorQuad/:z/:x/:y.webp@2x?data_path=:dataPath&product_type=:productType&analysis_completed_at=:analysisCompletedAt&year=:year

Where dataPath and analysisCompletedAt are specified on the reporting unit entry, productType is one of the available layers for the site. The @2x suffix is optional and may be omitted for lower resolution tiles. {z}, {x}, and {y} are the zoom level, and WMTS x and y coordinates of the tile, respectively. Additional parameters can be seen in the Dynamic Tiler API reference.

Example

Here is an example using MapLibre GL JS to display a dynamic webtile layer:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Add a raster tile source</title>
  <meta property="og:description" content="Add a third-party raster source to the map." />
  <meta charset='utf-8'>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.0.0/dist/maplibre-gl.css' />
  <script src='https://unpkg.com/maplibre-gl@5.0.0/dist/maplibre-gl.js'></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    html, body, #map {
      height: 100%;
    }
  </style>
</head>
<body>
<div id="map"></div>
<script type="module">
  (async () => {
    // parameters retrieved from the reporting unit entry, a sample dataset is show here.
    const dataPath = "s3://chloris-app-data/data/0183c887-9933-7751-ab91-4eed6dfd057f/019194dc-a302-7c9d-b708-ebe5e056d592_2024-08-27T17:22Z/";
    const analysisCompletedAt = "2024-08-27T21:59Z";

    // layer / year we're interested in
    const productType = "stock";
    const year = 2023;

    // get the bounds of the reporting unit layer
    const bounds = (await (await fetch(`https://app.chloris.earth/tiles/cog/bounds?data_path=${dataPath}&product_type=${productType}&year=${year}&analysis_completed_at=${analysisCompletedAt}`)).json()).bounds;

    const map = new maplibregl.Map({
      container: "map", // container id
      style: {
        "version": 8,
        "sources": {
          "stock_2023": {
            "type": "raster",
            "tiles": [
              `https://app.chloris.earth/tiles/cog/tiles/WebMercatorQuad/{z}/{x}/{y}.webp?data_path=${dataPath}&product_type=${productType}&year=${year}&analysis_completed_at=${analysisCompletedAt}`
            ],
            "scheme": "xyz",
            "minzoom": 0,
            "maxzoom": 16,
            "tileSize": 512,
            "attribution": "AGB stock data from Chloris Geospatial",
            bounds
          },
          "osm": {
            "type": "raster",
            "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
            "tileSize": 256,
            "attribution": "&copy; OpenStreetMap Contributors",
            "maxzoom": 19
          }
        },
        "layers": [
          {
            "id": "osm",
            "type": "raster",
            "source": "osm"
          },
          {
            "id": "stock_2023",
            "type": "raster",
            "source": "stock_2023",
            "minzoom": 0,
            "maxzoom": 16
          }
        ]
      },
      bounds: [[bounds[0], bounds[1]],[bounds[2], bounds[3]]],
    });
  })();
</script>
</body>
</html>

Pre-computed webtile layers (deprecated)

Deprecation notice: This feature and the following section of our docs is outdated and will be removed in a future version.

Prior to 1.6.0, the Chloris Platform provided pre-computed webtiles for all sites. These are still available for sites that were analyzed prior to 1.6.0, but new sites and updates to existing sites will not have pre-computed webtiles available.

The Chloris Platform produces TMS tiles for each site in the platform. The exact symbology information for each is available at :dataPath/layers.json and tiles themselves are available at :dataPath/:layerName/:year?/:z/:x/:y.webp for authenticated users. If you are used to XYZ tiles, the y coordinate in TMS is flipped (i.e. y = 2^z - 1 - y). In general, zoom levels 0-13 are produced in 512px by 512px resolution tiles (effective 9.555m / pixel on the equator). However, the layers config file(layers.json) contains the exact zoom levels for each layer so there is no guesswork. The :year? parameter is omitted for non-annual products.

Colormaps and legends

Whether you are using our webtiles or your own custom solution, we recommend using the following color maps and legends for consistency when showing Chloris data. These are the same color maps and legends used in the Chloris Platform web interface, with only minor modifications to make it easier for you to integrate them into your own applications. We present them here in TOML format, realizing that you will likely need to translate them into the format used by your mapping library. Other formats are available upon request.

Annual Stock

Stock maps are presented using a continuous color ramp, aligned to values 0 to 650 t/ha, using percentages so the exact values can be adjusted to individual sites. We recommend displaying values exceeding this range as 650 t/ha as they are likely to be outliers.

[2024-04-09_stock_light_650]
comment = "for use up to 650 t/ha. Values should be clamped to 650 t/ha"
clamp_max = 650
continuous = true
continuous_percentages = [0.0, 1e-6, 0.08, 0.17, 0.26, 0.37, 0.46, 0.56, 0.68, 0.83, 0.90, 1.0, ]
colors = [[255, 255, 255, 255, ],
[252, 252, 252, 255, ],
[223, 214, 180, 255, ],
[215, 224, 130, 255, ],
[137, 219, 55, 255, ],
[53, 194, 41, 255, ],
[17, 166, 68, 255, ],
[17, 135, 168, 255, ],
[21, 87, 158, 255, ],
[72, 11, 138, 255, ],
[65, 7, 110, 255, ],
[191, 20, 140, 255, ],
]

Annual stock legend images

The following images may be linked to in your application to provide a legend for the stock map:

landscape_stock_t_ha.png landscape_stock_tco2e_ha.png landscape_stock_t_km2.png landscape_stock_tco2e_km2.png

portrait_stock_t_ha.png portrait_stock_tco2e_ha.png portrait_stock_tco2e_km2.png portrait_stock_t_km2.png

Annual change

Change maps are presented using a diverging color ramp using discrete bins. If your mapping library does not support binning, displaying the values as a continuous color ramp is also acceptable, but you may need to define percentage-based values for the color ramp to align with your data. In general, losses may be larger than gains in any given year, as deforestation may happen suddenly, but growth is more gradual.

[2022-11-18_change_light]
comment = "values are in tons, but based on tco2e, as shown in labels"
diverging = true
diverging_symmetric = false
value_mass_units = "t"
value_area_units = "ha"
discrete_bin_values = [
    -9999.0,
    -190.90909090909090909091,
    -109.09090909090909090909,
    -54.54545454545454545455,
    -27.27272727272727272727,
    -5.45454545454545454545,
    0.0,
    0.54545454545454545455,
    2.72727272727272727273,
    5.45454545454545454545,
    10.90909090909090909091,
    21.81818181818181818182,
    9999.0,
]
discrete_bin_labels = ["< -350", "-350", "-200", "-100", "-50", "-10", "0", "1", "5", "10", "20", "40", "> 40", ]
colors = [
    [74, 16, 11, 255],
    [115, 40, 33, 255],
    [222, 91, 62, 255],
    [227, 163, 79, 255],
    [230, 190, 96, 255],
    [247, 239, 205, 255],
    [255, 255, 255, 255],
    [218, 232, 213, 255],
    [180, 217, 171, 255],
    [133, 184, 121, 255],
    [69, 135, 62, 255],
    [31, 117, 21, 255],
    [25, 79, 68, 255],
]
null_color = [255, 255, 255, 0, ]

Annual change legend images

The following images may be linked to in your application to provide a legend for the change map:

landscape_change_t_ha.png landscape_change_tco2e_ha.png landscape_change_t_km2.png landscape_change_tco2e_km2.png

portrait_change_t_ha.png portrait_change_tco2e_ha.png portrait_change_tco2e_km2.png portrait_change_t_km2.png