Rename raster bands in ArcGIS 10.x

4231
7
Jump to solution
07-22-2020 01:56 PM
WadeWall
Occasional Contributor

Hi all,

I have imported a multiband raster in .tif format into a geodatabase using ArcGIS 10.7 and want to rename the bands to something more descriptive. However, I can't find out how to do this easily.

Does anyone know how to rename bands in ArcGIS 10.x?

0 Kudos
1 Solution

Accepted Solutions
GuenterDoerffel
Esri Contributor

Hi Wade,

to answer this one first: In a MosaicDataset you can create "custom" band definitions:

which lead to these custom band names being accessible in UI ...

Raster Functions ...

Python code ..


The gp-tool "arcpy.SetMosaicDatasetProperties_management()" will allow you to also SET those definitions, but personally I never used that


G.  

View solution in original post

0 Kudos
7 Replies
GuenterDoerffel
Esri Contributor

Best: Create a MosaicDataset (where in the definition of the Mosaic, you can define Band Names, bandwidth, ...) and then load your dataset into it ... also will allow you to define proper processing templates for suitable band combinations 

G.

0 Kudos
WadeWall
Occasional Contributor

Thanks for the reply. I can create a new Mosaic Dataset, but still not sure how to rename bands. Could you provide an example of how to create a four band raster with the bands being named "This","Does","Not","Work"? I have tried to do it through multiple combinations of values.

As a side not, this seems like a very difficult way to rename bands. It should be as easy as something like raster.bandnames = ['a','b','c']. Just complaining.

GuenterDoerffel
Esri Contributor

Hi Wade,

to answer this one first: In a MosaicDataset you can create "custom" band definitions:

which lead to these custom band names being accessible in UI ...

Raster Functions ...

Python code ..


The gp-tool "arcpy.SetMosaicDatasetProperties_management()" will allow you to also SET those definitions, but personally I never used that


G.  

0 Kudos
Channi
by
New Contributor

This is not a solution and nothing has been solved. Where is the Arcpy equivalent for the GDAL 'RasterBand.SetDescription(BandName)'

If I have 1300 images you are essentially asking me to rewrite all of the raster data into a mosaic format, in my case 1.3TB of data just to alter 5 to 6 charters per image; this is not practical and not a solution. This is very easy to do in ENVI and ERDAS. Is there a solution that is effective for batch processing? 

0 Kudos
WadeWall
Occasional Contributor

One can right-click on each band name in Arc Catalog and rename bands that way. So how can one do this using arcpy? There has to be a way to access the band names using arcpy.

AlessioArena
New Contributor

Following the trail that WadeWall pointed to, I wrote a small Python function that can fix this problem.

I wrote this thinking of a rasterio.DatasetReader object being passed but can be easily adapted to gdal

import os
def writePAMfile(img, descriptions=None):
    pam_path = os.path.abspath('.'.join([img.files[0], 'aux.xml']))
    n_bands = img.count
    if isinstance(descriptions, list):
        if not len(descriptions) == n_bands:
            raise ValueError("You must pass one description string for every band")
    elif descriptions is None:
        descriptions = img.descriptions
    else:
        raise TypeError("The argument 'descriptions' must be a list of strings or None")
    with open(pam_path, 'w') as pam:
        pam.write("<PAMDataset>\n")
        for i in range(n_bands):
            if descriptions[i] is None:
                pam.write('\t<PAMRasterBand band="{0}">\n\t\t<Metadata>\n\t\t\t<MDI key="BandName">None</MDI>\n\t\t</Metadata>\n\t</PAMRasterBand>\n'.format(str(i+1)))
            else:
                pam.write('\t<PAMRasterBand band="{0}">\n\t\t<Description>{1}</Description>\n\t\t<Metadata>\n\t\t\t<MDI key="BandName">None</MDI>\n\t\t</Metadata>\n\t</PAMRasterBand>\n'.format(str(i+1), descriptions[i]))
        pam.write("</PAMDataset>\n")

 

In this function you can pass the list of band_names to use, but if those are already set using the appropriate gdal or rasterio method you can leave it blank and will read this information from your raster

Once that file is written, loading the raster in ArcMap or ArcCatalog will show the appropriate names

0 Kudos
AlessioArena
New Contributor

Or if you would like a bit more refined functionality, like preserving already existing tags, removing descriptions and so on

import os
import xml.etree.ElementTree as ET

def find_xml_element(parent_element, tag, attribs=None):
    options = parent_element.findall(tag)
    if len(options) == 0:
        return None
    else:
        if attribs is None:
            return options[0]
        for o in options:
            if o.attrib == attribs:
                return o
        else:
            return None
    
def writePAMfile(img, descriptions=None):
    n_bands = img.count
    if isinstance(descriptions, list):
        if not len(descriptions) == n_bands:
            raise ValueError("You must pass one description string for every band")
    elif descriptions is None:
        descriptions = img.descriptions
    else:
        raise TypeError("The argument 'descriptions' must be a list of strings or None")

    pam_path = os.path.abspath('.'.join([img.files[0], 'aux.xml']))
    if os.path.isfile(pam_path):
        tree = ET.parse(pam_path)
        root = tree.getroot()
        if root.tag != 'PAMDataset':
            raise RuntimeError("a XML file {0} exists but is not recognized as a valid PAM dataset".format(pam_path))
        else:
            for n, d in enumerate(descriptions):
                band = find_xml_element(root, "PAMRasterBand", {'band':str(n + 1)})
                if band is None:
                    band = ET.SubElement(root, "PAMRasterBand", band=str(n+1))
                meta = band.find("Metadata")
                if meta is None:
                    meta = ET.SubElement(band, 'Metadata')
                mdi = find_xml_element(meta, "MDI", {'key':'BandName'})
                if mdi is None:
                    ET.SubElement(meta, "MDI", key="BandName").text = str(d)
                else:
                    mdi.text = str(d)
                desc = band.find("Description")
                if d is not None:
                    if desc is None:
                        ET.SubElement(band, "Description").text = d
                    else:
                        desc.text = d
                else:
                    if desc is not None:
                        band.remove(desc)
    else:
        root = ET.Element("PAMDataset")
        for n, d in enumerate(descriptions):
            band = ET.SubElement(root, "PAMRasterBand", band=str(n+1))
            meta = ET.SubElement(band, 'Metadata')
            if isinstance(d, str):
                ET.SubElement(meta, "MDI", key="BandName").text = d
                ET.SubElement(band, "Description").text = d
            elif d is None:
                ET.SubElement(meta, "MDI", key="BandName").text = "None"
            else:
                raise ValueError("Descriptions must be a str or None")
        tree = ET.ElementTree(root)
    tree.write(pam_path)
0 Kudos