PermafrostDiscoveryGateway / pdg-portal

Design and mockup documents for the PDG portal
Apache License 2.0
0 stars 0 forks source link

Add the North Slope Drained Lake Basin classification layer to the portal #32

Closed robyngit closed 1 year ago

robyngit commented 1 year ago

We would like to have this layer in the portal by the Dec 8th webinar, when the author of this dataset, Helena, will be presenting.

This data set is the first step in Helena's pan-arctic mapping workflow.

Archived on the ADC here: https://arcticdata.io/catalog/view/doi%3A10.18739%2FA2K35MF71 The paper that resulted from this analysis: https://www.mdpi.com/2072-4292/13/13/2539

Note: there's also two other drained lake basin datasets that we published at the ADC that could get added to the viewer:

robyngit commented 1 year ago

This layer is now on the production portal, with imagery tiles stored at /data/tiles/10.18739/A2K35MF71/urn:uuid:15830bf6-1d20-405f-90c6-5011058fc8fd/.

To create the tiles, a custom script was created since we don't yet have a standardized workflow for GeoTIFF inputs:

make-tiles.py ```python from rio_tiler.io import COGReader import morecantile from pathlib import Path import os import numpy as np from pdgraster import WebImage, Palette from colormaps.colormap import Colormap import colormaps as cmaps base_dir = Path( '/home/thiessenbock/PDG-test/exploratory/bergstedt-2021-lake-basin') tiles_dir = str(base_dir.joinpath('tiled_data')) filepath = str(base_dir.joinpath('dlb_class_final.tif')) tms_id = 'WGS1984Quad' tms = morecantile.tms.get(tms_id) min_zoom = 0 max_zoom = 12 # colors from DLB.lyrx # No DLB = 0; RGB: 252, 141, 89 col_0 = '#FC8D59' # Ambiguous = 0.5; RGB: 255, 255, 191 col_0point5 = '#FFFFBF' # DLB = 1; RGB: 145, 191, 219, col_1 = '#91BFDB' # No data nodata_color = '#ffffff00' reverse_palette = False max_value = 1 min_value = 0 palette = [[col_0, col_0point5, col_1], nodata_color] all_z = range(max_zoom, min_zoom - 1, -1) def make_img_tiles( z, filepath, tms_id, out_dir, palette, reverse_palette=False, min_value=None, max_value=None): tms = morecantile.tms.get(tms_id) reader = COGReader(filepath, tms=tms) west, south, east, north = reader.bounds tiles_to_generate = tms.tiles(west, south, east, north, [z]) tiles_generated = [] for tile in tiles_to_generate: data_future = make_img_tile( filepath, tms_id, tile, out_dir, palette, reverse_palette, min_value, max_value) tiles_generated.append(data_future) return tiles_generated def make_img_tile( filepath, tms_id, tile, out_dir, palette, reverse_palette=False, min_value=None, max_value=None): print(f'Making tile {tile}') tms = morecantile.tms.get(tms_id) reader = COGReader(filepath, tms=tms) tms_id = reader.tms.identifier nodata_val = reader.info().nodata_value num_bands = reader.dataset.count band_names = reader.dataset.descriptions x, y, z = tile.x, tile.y, tile.z tile_data = reader.tile(x, y, z) data_all_bands = tile_data.as_masked().data out_paths = [] for i in range(num_bands): data = data_all_bands[i] band_name = band_names[i] or f'band_{str(i + 1)}' if np.sum(data != nodata_val) > 0: nodata_color = palette[1] colors = palette[0] if isinstance(colors, str): cmap_palette = getattr(cmaps, colors) if reverse_palette: cmap_palette = Colormap(cmap_palette.reversed().colors) palette = Palette(cmap_palette, nodata_color) else: if reverse_palette: colors = colors[::-1] palette = Palette(colors, nodata_color) png = WebImage( data, palette=palette, min_val=min_value, max_val=max_value, nodata_val=nodata_val, ) tile_path = f'{band_name}/{tms_id}/{z}/{x}/{y}.png' path = os.path.join(out_dir, tile_path) tile_dir = os.path.dirname(path) if tile_dir and not os.path.exists(tile_dir): os.makedirs(tile_dir) png.save(path) out_paths.append(path) return out_paths tiles_generated = [] for z in all_z: print(f'Generating tiles for zoom level {z}') tiles = make_img_tiles( z, filepath, tms_id, tiles_dir, palette, reverse_palette, min_value, max_value ) tiles_generated.append(tiles) ```

Here is the configuration for the layer in the Cesium map config in MetacatUI:

{
  "type": "WebMapTileServiceImageryProvider",
  "label": "Drained Lake Basins, North Slope, 2014-2019",
  "description": "This data set contains a classification of the North Slope, Alaska for drained lake basins (DLBs) based on Landsat-8 imagery of the years 2014-2019, and covers greater than 71,000 km2. Areas classified as ambiguous could not be classified as DLB or noDLB with sufficient certainty. It is based on a novel and scalable remote sensing-based approach to identify DLBs in lowland permafrost regions.",
  "attribution": "Helena Bergstedt, Benjamin Jones, Kenneth Hinkel, Louise Farquharson, Benjamin Gaglioti, et al. 2021. Drained Lake Basin classification based on Landsat-8 imagery, North Slope, Alaska 2014 -2019. Arctic Data Center. doi:10.18739/A2K35MF71.",
  "moreInfoLink": "https://arcticdata.io/catalog/view/doi%3A10.18739%2FA2K35MF71",
  "downloadLink": "https://arcticdata.io/catalog/view/doi%3A10.18739%2FA2K35MF71#urn%3Auuid%3A15830bf6-1d20-405f-90c6-5011058fc8fd",
  "id": "doi:10.18739/A2K35MF71",
  "visible": true,
  "cesiumOptions": {
    "url": "https://arcticdata.io/data/tiles/10.18739/A2K35MF71/urn:uuid:15830bf6-1d20-405f-90c6-5011058fc8fd/band_1/WGS1984Quad/{TileMatrix}/{TileCol}/{TileRow}.png",
    "tilingScheme": "GeographicTilingScheme",
    "rectangle": [
      -171.329107983504,
      66.16074244427435,
      -136.6488120854937,
      72.25092330368847
    ]
  },
  "colorPalette": {
    "paletteType": "categorical",
    "property": "DLB Classification",
    "colors": [
      {
        "color": "#FC8D59",
        "value": "No Drained Lake Basin"
      },
      {
        "color": "#FFFFBF",
        "value": "Ambiguous"
      },
      {
        "color": "#91BFDB",
        "value": "Drained Lake Basin"
      }
    ]
  }
}

I will make new issues for the remaining two drained lake basin datasets