1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

[Python] How to Render Webmaps using Zarr Format for Flood Data?

Discussão em 'Python' iniciado por Stack, Setembro 13, 2025.

  1. Stack

    Stack Membro Participativo

    I have very large Geotiff Files (.tiff) for Flood Data -

    $ gdalinfo flood_probability_2023-09-25_88.19823706960149_24.314907220056885.tif
    Driver: GTiff/GeoTIFF
    Files: flood_probability_2023-09-25_88.19823706960149_24.314907220056885.tif
    flood_probability_2023-09-25_88.19823706960149_24.314907220056885.tif.aux.xml
    Size is 30530, 21403
    Coordinate System is:
    GEOGCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
    MEMBER["World Geodetic System 1984 (Transit)"],
    MEMBER["World Geodetic System 1984 (G730)"],
    MEMBER["World Geodetic System 1984 (G873)"],
    MEMBER["World Geodetic System 1984 (G1150)"],
    MEMBER["World Geodetic System 1984 (G1674)"],
    MEMBER["World Geodetic System 1984 (G1762)"],
    MEMBER["World Geodetic System 1984 (G2139)"],
    ELLIPSOID["WGS 84",6378137,298.257223563,
    LENGTHUNIT["metre",1]],
    ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
    ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
    AXIS["geodetic latitude (Lat)",north,
    ORDER[1],
    ANGLEUNIT["degree",0.0174532925199433]],
    AXIS["geodetic longitude (Lon)",east,
    ORDER[2],
    ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
    SCOPE["Horizontal component of 3D system."],
    AREA["World."],
    BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]
    Data axis to CRS axis mapping: 2,1
    Origin = (86.822531536265402,25.270686920623081)
    Pixel Size = (0.000089831528412,-0.000089831528412)
    Metadata:
    AREA_OR_POINT=Area
    Image Structure Metadata:
    INTERLEAVE=PIXEL
    Corner Coordinates:
    Upper Left ( 86.8225315, 25.2706869) ( 86d49'21.11"E, 25d16'14.47"N)
    Lower Left ( 86.8225315, 23.3480227) ( 86d49'21.11"E, 23d20'52.88"N)
    Upper Right ( 89.5650881, 25.2706869) ( 89d33'54.32"E, 25d16'14.47"N)
    Lower Right ( 89.5650881, 23.3480227) ( 89d33'54.32"E, 23d20'52.88"N)
    Center ( 88.1938098, 24.3093548) ( 88d11'37.72"E, 24d18'33.68"N)
    Band 1 Block=30530x1 Type=Float64, ColorInterp=Gray
    Description = flood_label
    Min=0.000 Max=1.000
    NoData Value=nan
    Overviews: 15265x10702, 7633x5351, 3817x2676, 1909x1338, 955x669, 478x335, 239x168, 120x84, 60x42
    Metadata:
    STATISTICS_APPROXIMATE=YES
    STATISTICS_MAXIMUM=1
    STATISTICS_MEAN=0.0611193183464
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=0.23954904982336
    STATISTICS_VALID_PERCENT=100
    Band 2 Block=30530x1 Type=Float64, ColorInterp=Undefined
    Description = uncertainty
    Min=0.000 Max=0.333
    NoData Value=nan
    Overviews: 15265x10702, 7633x5351, 3817x2676, 1909x1338, 955x669, 478x335, 239x168, 120x84, 60x42
    Metadata:
    STATISTICS_APPROXIMATE=YES
    STATISTICS_MAXIMUM=0.33333333333333
    STATISTICS_MEAN=0.019859184446693
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=0.058523799713129
    STATISTICS_VALID_PERCENT=100
    Band 3 Block=30530x1 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_1
    Min=0.000 Max=1.000
    NoData Value=nan
    Overviews: 15265x10702, 7633x5351, 3817x2676, 1909x1338, 955x669, 478x335, 239x168, 120x84, 60x42
    Metadata:
    STATISTICS_APPROXIMATE=YES
    STATISTICS_MAXIMUM=1
    STATISTICS_MEAN=0.10656160176136
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=0.29088619554382
    STATISTICS_VALID_PERCENT=100
    Band 4 Block=30530x1 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_2
    Min=0.000 Max=1.000
    NoData Value=nan
    Overviews: 15265x10702, 7633x5351, 3817x2676, 1909x1338, 955x669, 478x335, 239x168, 120x84, 60x42
    Metadata:
    STATISTICS_APPROXIMATE=YES
    STATISTICS_MAXIMUM=1
    STATISTICS_MEAN=0.075278825662254
    STATISTICS_MINIMUM=0
    STATISTICS_STDDEV=0.25170630724278
    STATISTICS_VALID_PERCENT=100
    Band 5 Block=30530x1 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_3
    NoData Value=nan
    Overviews: 15265x10702, 7633x5351, 3817x2676, 1909x1338, 955x669, 478x335, 239x168, 120x84, 60x42


    I want to make a web portal to visualize this file but since the data is very large, I'm converting it to Cloud Optimized Geotiff Format first using GDAL to convert it into 512X512 manageable block size.

    $ gdal_translate input.tiff output.tiff -of COG -co COMPRESS=DEFLATE -co BIGTIFF=YES


    By Doing so, I'm able to get a slightly compressed verion with internal blocking -

    $ gdalinfo output_cog.tiff
    Driver: GTiff/GeoTIFF
    Files: output_cog.tiff
    Size is 30530, 21403
    Coordinate System is:
    GEOGCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
    MEMBER["World Geodetic System 1984 (Transit)"],
    MEMBER["World Geodetic System 1984 (G730)"],
    MEMBER["World Geodetic System 1984 (G873)"],
    MEMBER["World Geodetic System 1984 (G1150)"],
    MEMBER["World Geodetic System 1984 (G1674)"],
    MEMBER["World Geodetic System 1984 (G1762)"],
    MEMBER["World Geodetic System 1984 (G2139)"],
    ELLIPSOID["WGS 84",6378137,298.257223563,
    LENGTHUNIT["metre",1]],
    ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
    ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
    AXIS["geodetic latitude (Lat)",north,
    ORDER[1],
    ANGLEUNIT["degree",0.0174532925199433]],
    AXIS["geodetic longitude (Lon)",east,
    ORDER[2],
    ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
    SCOPE["Horizontal component of 3D system."],
    AREA["World."],
    BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]
    Data axis to CRS axis mapping: 2,1
    Origin = (86.822531536265402,25.270686920623081)
    Pixel Size = (0.000089831528412,-0.000089831528412)
    Metadata:
    AREA_OR_POINT=Area
    Image Structure Metadata:
    LAYOUT=COG
    COMPRESSION=LZW
    INTERLEAVE=PIXEL
    Corner Coordinates:
    Upper Left ( 86.8225315, 25.2706869) ( 86d49'21.11"E, 25d16'14.47"N)
    Lower Left ( 86.8225315, 23.3480227) ( 86d49'21.11"E, 23d20'52.88"N)
    Upper Right ( 89.5650881, 25.2706869) ( 89d33'54.32"E, 25d16'14.47"N)
    Lower Right ( 89.5650881, 23.3480227) ( 89d33'54.32"E, 23d20'52.88"N)
    Center ( 88.1938098, 24.3093548) ( 88d11'37.72"E, 24d18'33.68"N)
    Band 1 Block=512x512 Type=Float64, ColorInterp=Gray
    Description = flood_label
    NoData Value=nan
    Overviews: 15265x10701, 7632x5350, 3816x2675, 1908x1337, 954x668, 477x334
    Band 2 Block=512x512 Type=Float64, ColorInterp=Undefined
    Description = uncertainty
    NoData Value=nan
    Overviews: 15265x10701, 7632x5350, 3816x2675, 1908x1337, 954x668, 477x334
    Band 3 Block=512x512 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_1
    NoData Value=nan
    Overviews: 15265x10701, 7632x5350, 3816x2675, 1908x1337, 954x668, 477x334
    Band 4 Block=512x512 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_2
    NoData Value=nan
    Overviews: 15265x10701, 7632x5350, 3816x2675, 1908x1337, 954x668, 477x334
    Band 5 Block=512x512 Type=Float64, ColorInterp=Undefined
    Description = flood_prob_3
    NoData Value=nan
    Overviews: 15265x10701, 7632x5350, 3816x2675, 1908x1337, 954x668, 477x334


    I am then converting this COG file to Zarr Store using rasterio -

    LEVELS = 6
    store_2d = "./output.zarr"
    path = "./input.tiff"

    # open dataset
    ds = (
    xr.open_dataarray(path, engine="rasterio")
    .to_dataset(name="tavg")
    .squeeze()
    )

    # create the pyramid
    dt = pyramid_reproject(ds, levels=LEVELS, clear_attrs=True)

    # write to zarr
    dt.to_zarr(store_2d, zarr_format=2, consolidated=True)


    This is the information of this newly created Zarr folder -

    C:\Users\Batman\Desktop\Tech\BTP\NPyramidTryWithCarbonMaps>gdalinfo C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr
    Driver: Zarr/Zarr
    Files: C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr
    Size is 512, 512
    Subdatasets:
    SUBDATASET_1_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/0/tavg
    SUBDATASET_1_DESC=[5x128x128] /0/tavg (Float32)
    SUBDATASET_2_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/1/tavg
    SUBDATASET_2_DESC=[5x256x256] /1/tavg (Float32)
    SUBDATASET_3_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/2/tavg
    SUBDATASET_3_DESC=[5x512x512] /2/tavg (Float32)
    SUBDATASET_4_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/3/tavg
    SUBDATASET_4_DESC=[5x1024x1024] /3/tavg (Float32)
    SUBDATASET_5_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/4/tavg
    SUBDATASET_5_DESC=[5x2048x2048] /4/tavg (Float32)
    SUBDATASET_6_NAME=ZARR:"C:/Users/Batman/Desktop/Tech/BTP/Data/flood_pyramid.zarr":/5/tavg
    SUBDATASET_6_DESC=[5x4096x4096] /5/tavg (Float32)
    Corner Coordinates:
    Upper Left ( 0.0, 0.0)
    Lower Left ( 0.0, 512.0)
    Upper Right ( 512.0, 0.0)
    Lower Right ( 512.0, 512.0)
    Center ( 256.0, 256.0)



    I want to make a web portal to let the client visualize this, I want to serve this dynamically in a tiled way so that depending on the user's zoom level, data is requested from the server.

    I have looked up everything including @carbonmaps, zarrita, zarr-js, but I am unable to do this. There is no restrictions for Javascript on Frontend, any system works.

    This is the code, I am using in @carbonmaps -

    'use client';

    import { useEffect, useRef } from 'react';
    import { Map, Tile, useColormap } from '@carbonplan/maps';

    // Simple theme object (mimics CarbonPlan's dark background)
    const theme = {
    colors: {
    background: '#1a1a1a', // or '#000'
    },
    };

    const ZarrMapPage = () => {
    const canvasRef = useRef();

    // Define colormap
    const colormap = useColormap({
    name: 'fire', // Try 'warm', 'viridis', 'blues', etc.
    flip: false,
    clamp: null, // Set [min, max] if needed, or leave null
    });

    useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    // Handle HiDPI rendering
    const resize = () => {
    const { offsetWidth, offsetHeight } = canvas;
    canvas.width = offsetWidth * devicePixelRatio;
    canvas.height = offsetHeight * devicePixelRatio;
    canvas.style.width = `${offsetWidth}px`;
    canvas.style.height = `${offsetHeight}px`;
    };
    resize();
    window.addEventListener('resize', resize);

    const gl = canvas.getContext('webgl2');
    if (!gl) {
    console.error('WebGL2 is not supported');
    return;
    }

    // Create Tile layer
    const tile = new Tile({
    gl,
    source: '/data/mydata.zarr', // Adjust path to your .zarr
    variable: 'temperature', // Change to your Zarr variable
    colormap: colormap.get(),
    clim: [250, 310], // Adjust based on your data
    transform: 'identity',
    projection: 'equal-earth', // Or 'albers-usa', 'mercator'
    onLoadingStatus: (status) => console.log(status),
    });

    // Animation loop
    const loop = () => {
    tile.draw();
    requestAnimationFrame(loop);
    };
    loop();

    // Cleanup
    return () => {
    tile.destroy();
    window.removeEventListener('resize', resize);
    };
    }, [colormap]);

    return (
    <div
    style={{
    width: '100vw',
    height: '100vh',
    position: 'relative',
    background: theme.colors.background,
    }}
    >
    <Map
    settings={{
    projection: 'equal-earth',
    zoom: 1,
    center: [0, 0],
    }}
    >
    <canvas
    ref={canvasRef}
    style={{
    display: 'block',
    width: '100%',
    height: '100%',
    background: theme.colors.background,
    }}
    />
    </Map>
    </div>
    );
    };

    export default ZarrMapPage;


    But I got this error -

    mport trace for requested module:
    ./app/page.js
    ⨯ TypeError: (0 , _carbonplan_maps__WEBPACK_IMPORTED_MODULE_2__.useColormap) is not a function
    at ZarrMapPage (app\page.js:17:31)
    15 |
    16 | // Define colormap
    > 17 | const colormap = useColormap({
    | ^
    18 | name: 'fire', // Try 'warm', 'viridis', 'blues', etc.
    19 | flip: false,
    20 | clamp: null, // Set [min, max] if needed, or leave null {
    digest: '3505414644'


    I would like your help in this.

    Continue reading...

Compartilhe esta Página