6

I have a multiband image with nodata value (which is Landsat and been set nodata to 0). And I want to use rasterio show to display the image. However, I found that the show function can't deal with the nodata value of the multiband image. I have made sure that the singleband image is correct. My code is like this:

with rio.open(path) as src:
    arr = src.read([1, 2, 3], masked=True)
    show(arr)

The image is like this:

rgb

This is the landsat image. You can find that the image is surrounded by black color. In this place the data is nodata and I want it to be displayed as transparent.

How do I show nodata multiband img by rasterio?

2
  • 2
    You say that the 'show' function can't handle no data, but your code produces an image. Can you clarify what is wrong with the image or what you were expecting to happen instead?
    – sbphd
    Commented Dec 2, 2019 at 7:24
  • I'm sorry,I had supplement.
    – wsf1990
    Commented Dec 2, 2019 at 7:54

4 Answers 4

1

If you just want the no data areas to be white, then an easy and quick solution is to do:

arr[arr==0] = np.max(arr)
show(arr)

If you want it actually transparent because you are going to plot multiple data sets on the axes which need to overlap correctly, then there isn't an easy way, but I'd explore using 'matplotlib.pyplot.imshow', converting your dataset to float, and converting no data areas to 'np.nan'.

1
  • 2
    I had test matplotlib.pyplot.imshow and set nodata to np.nan,but it still show the black color.
    – wsf1990
    Commented Dec 2, 2019 at 12:32
1

Personally, I've been down many rabbit holes trying to solve this problem, and ultimately found forking gdal_translate to be a much simpler and configurable approach to get something viewable in IPython:

import glob
from IPython.display import Image, display

# Use gdal to convert GeoTIFF to a rescaled PNG
for f in glob.glob("/tmp/clips/*.tiff"):
    !gdal_translate -q -of PNG -scale 0 3000 0 255 -a_nodata 0 -ot Byte {f} {f}.png
    
for f in glob.glob("/tmp/clips/*.png"):
    display(Image(f, width=500))

Result:

Jupyter Output

0

Note that show is a wrapper on imshow and you can pass imshow kwargs to it.

I believe imshow itself would handle a 4th band as an "alpha" (i.e. transparency) layer, but you can also provide it with the alpha parameter of imshow.

So in your case, you could just pass your masked array's mask:

show(img.data, alpha=img.mask)
2
  • This gives me a TypeError: alpha must be a float, two-dimensional array, or None
    – Alex
    Commented Sep 20, 2023 at 7:03
  • 1
    @Alex Assuming you passed the image mask as above, you could try typecasting your mask to a float, e.g. img.mask.astype(np.float32) Commented Sep 21, 2023 at 6:57
0

I got this to work by taking advantage of the fact that imshow handles an array as follows:

"(M, N, 4): an image with RGBA values (0-1 float or 0-255 int), i.e. including transparency."

I added a fourth alpha band as follows:

arr_mask = ~np.isnan(np.sum(arr, axis=0))
composite = np.vstack([arr, arr_mask[np.newaxis]])
show(composite)
1
  • This gives me a fully white image.
    – Alex
    Commented Sep 20, 2023 at 7:04

Your Answer

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

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