I am trying to read a GeoTIFF, perform calculations (radiometric correction) on all bands, and then output back to GeoTIFF. Most of the code I have works fine, up until trying to output.

import os
import rioxarray as rxr
import numpy as np
import pandas as pd

wv3tif = rxr.open_rasterio(os.path.join(os.getcwd(), "WV3 MUL GDA2020UTM55.tif"))

sensorvals = pd.read_excel(os.path.join("WV3_band_details.xlsx"))

L_bands = []
for band in range(len(sensorvals['Band no.'])):
    L = np.add(np.multiply(wv3tif[band], (sensorvals['GAIN'][band] * sensorvals['abscalfactor'][band] / sensorvals['effectivebandwidth'][band])), sensorvals['OFFSET'][band])
L_bands.rio.to_raster("WV3 MUL GDA2020UTM55 TOA radiance.tif")

The last line throws an error 'numpy.ndarray' object has no attribute 'rio' because the data is no longer an xarray.core.dataarray.DataArray object. I have tried to vstack but since that's a numpy routine it only returns an ndarray without the necessary output methods.

How do I stack the list of bands for output with rioxarray, including outputting with original CRS and coords?

  • Would you like to use another library like gdal or rasterio? I have a code for that
    – Helios
    Dec 5, 2022 at 15:05
  • I'm happy to use anything that works. I've been going through the rioxarray documentation and I just can't see a way to stack a list to an xarray DataArray for output.
    – GlenS
    Dec 5, 2022 at 20:37
  • Oh. It can be done by L_output = xa.DataArray(L_bands) after import xarray as xa. Not sure if there are corresponding methods in rioxarray but this produces a xarray.core.dataarray.DataArray with the right shape. Now just have to work out how to copy the CRS and spatial dimensions etc.
    – GlenS
    Dec 5, 2022 at 20:55

1 Answer 1


As per this post the correct method seems to be

y = wv3tif['y'].values
x = wv3tif['x'].values
band_vals = wv3tif['band'].values

L_bands = []
for band in range(len(sensorvals['Band no.'])):
    L_bands.append(np.add(np.multiply(wv3tif[band].data, (sensorvals['GAIN'][band] * sensorvals['abscalfactor'][band] / sensorvals['effectivebandwidth'][band])), sensorvals['OFFSET'][band]))

L_output = xa.DataArray(L_bands, coords={'y':y, 'x':x, 'band':band_vals}, dims=['band', 'y', 'x'])

L_output.rio.to_raster("WV3 MUL GDA2020UTM55 TOA radiance.tif")

This now correctly writes the GeoTIFF with the modified pixel values

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.