COG ImageryTileLayer renderers

1220
8
Jump to solution
11-28-2022 03:11 AM
TumasGuogis
New Contributor II

Hello, I have COGs with integer values, and I'd like to be able to assign colors to value ranges, e.g.: 0-200 - blue, 200-400 - green, etc., but the only renderer that seems to work is the automatically assigned stretch-renderer. I've tried uniqueValueRenderer, which the API reference suggests is my only option without statistics files, but the entire raster shows up as black. Could I possibly get a working example or something? Thanks.

   The way I tried it (supposed to make entire raster cyan, but it shows up as black):
Spoiler
const uvr = new UniqueValueRenderer({
      field: "Raster.ServicePixelValue",
        uniqueValueInfos: []
      });
      for(let i = 0; i < max; i++){
        const uniqueValue = new UniqueValueInfo({
          value:i,
          symbol: {
            type: "simple-fill",
            color: "#00ffff"
          }
        })
        uvr.uniqueValueInfos.push(uniqueValue);
      };

    const layer = new ImageryTileLayer({
      bandIds: [1],
      interpolation: "nearest",
      renderer: uvr
    });
 
0 Kudos
1 Solution

Accepted Solutions
TumasGuogis
New Contributor II

ClassBreaksRenderer worked! I must've been doing something wrong when I was trying it before.. 

Thank you again for your time. 

    const renderer = new ClassBreaksRenderer({
      field: "Value"
    })
    
    renderer.addClassBreakInfo({
      minValue: -250,
      maxValue: 0,
      symbol:{
        type:"simple-fill",
        color:"#00FFFF"
      }
    })

    const layer = new ImageryTileLayer({
      url: "http://localhost:6061/raster.tif",
      interpolation: "nearest",
      renderer: renderer
    })

 

TumasGuogis_0-1669927692134.png

 

View solution in original post

0 Kudos
8 Replies
UndralBatsukh
Esri Regular Contributor

Hi there, 

It looks like your COG file has more than one band (based on your code snippet). The UniqueValueRenderer cannot be applied to a service or COG that has more than one band. 

To assign UniqueValueRenderer to an ImageryTileLayer with COG the following two conditions must be met:

  1. The COG file must have only one band.
  2. Set the UVR.field to "Value". The Raster.ServicePixelValue field is only used for popupTemplate. You can find the more info about it from here: https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#rast...

Hope this helps. 

TumasGuogis
New Contributor II

Thanks for the reply. My raster does have only 1 band. I have changed the UVR field property to "Value" and removed the bandIds property from the layer... Same result. Anything else that could be the issue?

0 Kudos
UndralBatsukh
Esri Regular Contributor

Assuming you have a categorical data. Not sure why it is still black. I cant think of anything else without looking at the image itself. Can you share your COG? 

0 Kudos
TumasGuogis
New Contributor II

Here it is. I had to ZIP it since .tif isn't allowed

0 Kudos
UndralBatsukh
Esri Regular Contributor

Thank you so much for providing me with the cog file. So several things. 

The imagery is black for two reasons. First, the pixel values for your COG file ranges between -55 to -227 and it has 153 unique values. However, you are looping through where i=0 to max number and applying the i value to uniqueValueInfo.value which does not exist in your image. Even if you fix this your image will be still black. See the following for why.

Second and the more important reason is that your cog tif file has pixel type of Int32 which translates to ImageryTileLayer.rasterInfo.pixelType of "S32".  So I must amend my previous statement about assigning UniqueValueRenderer to an ImageryTileLayer... the following conditions must be met:

  1. The image must have only one band.

  2. Image must either
    -- have a raster attribute table: you can use any numeric or string field from the table in UV.
    --or u8 / s8 pixel type: you can only use "Value" field.

To apply UniqueValueRenderer to your COG you need to add attribute table to your image or change the pixel type to either u8 or s8. I have tested the image by changing the image pixel type and verified that it works. The u8 pixel values must range between 0 - 255, and s8 pixel values must range between -128 - 127. See pixelType doc for more info on pixel value ranges. 

To convert your COG to have pixelType of u8 or s8, it is probably easiest to use ArcGIS PRO. First use, Plus function geoprocessing tool with a constant number (256 for example) + your tif. You know your data better so please adjust accordingly. Then use the Copy Raster Geoprocessing tool to convert the tif file to COG. For example, I did use the following params.

Screen Shot 2022-11-30 at 10.23.11 AM.png

Then I use able to add and assign UVR to your COG successfully. I used only 10 color combos for the following image... 

Screen Shot 2022-11-30 at 10.31.57 AM.png

 

TumasGuogis
New Contributor II

Thanks for all your help.

Sadly my data will not fit into 8 bits (nor am I keen to build attribute tables for each raster I generate). I did try building attribute tables via arcgis pro just to test though and my raster is still black.

Ideally I'd just set ranges with classBreaksRenderer but it seems there's no way to get this to work either?

0 Kudos
UndralBatsukh
Esri Regular Contributor

ClassbreaksRenderer should work! Please feel free to share your code with me. 

You can also use RasterStretchRenderer for your cog. The following an example that works your cog. Please refer to this doc to learn more about stretching: https://pro.arcgis.com/en/pro-app/latest/help/data/imagery/histogram-stretching.htm

 const layer = new ImageryTileLayer({
   renderer: new RasterStretchRenderer({
   stretchType: "min-max",
   statistics: [[-227, 50, -172, 19]],
   useGamma: false,
   computeGamma: false,
   dra: false,
   gamma: [1],
   colorRamp: {
     type: "multipart",
     colorRamps: [
       new AlgorithmicColorRamp({
          algorithm: "hsv",
          fromColor: [255, 45, 8, 255],
          toColor: [255, 57, 251, 255]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [255, 57, 251,255],
         toColor: [26,35,253,255]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 26, 35, 253, 255],
         toColor: [ 0, 181, 255, 255 ]
       }),
       new AlgorithmicColorRamp({
        algorithm: "hsv",
        fromColor: [ 0, 181, 255, 255 ],
        toColor: [ 0, 253, 255, 255 ]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 0, 253, 255, 255 ],
         toColor: [ 0, 251, 50, 255 ]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 0, 251, 50, 255 ],
         toColor: [ 255, 254, 52, 255 ]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 255, 254, 52, 255 ],
         toColor: [ 255, 181, 61, 255 ]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 255, 181, 61, 255 ],
         toColor: [ 255, 45, 8, 255 ]
       }),
       new AlgorithmicColorRamp({
         algorithm: "hsv",
         fromColor: [ 255, 45, 8, 255 ],
         toColor: [ 190, 190, 190, 255 ]
       })
     ]
    }
   }),
   url: "data/cog/raster.tif",
});

 

TumasGuogis
New Contributor II

ClassBreaksRenderer worked! I must've been doing something wrong when I was trying it before.. 

Thank you again for your time. 

    const renderer = new ClassBreaksRenderer({
      field: "Value"
    })
    
    renderer.addClassBreakInfo({
      minValue: -250,
      maxValue: 0,
      symbol:{
        type:"simple-fill",
        color:"#00FFFF"
      }
    })

    const layer = new ImageryTileLayer({
      url: "http://localhost:6061/raster.tif",
      interpolation: "nearest",
      renderer: renderer
    })

 

TumasGuogis_0-1669927692134.png

 

0 Kudos