Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Make NoData value of downloaded tiff available to python api #555

Open
SlowMo24 opened this issue Jan 24, 2025 · 2 comments
Open

Comments

@SlowMo24
Copy link

What is the problem? Please describe.

In our workflow, we execute an eval_script via a SentinelHubRequest to calculate the NDVI. We then run get_data on that request to retrieve the NDVI data array.

By default the value -999 is used as NoDataValue but this is not clear without trying and we could not find a way to retrieve that value programmatically.

Here's the solution

Return a Numpy Masked Array in the get_data method that can hold that information.

Alternatives

Provide a function to retrieve the NoDataValue.

Additional context

We now set the NoDataValue explicitly in the eval_script and keep a constant in our code that represents that value. If one needed flexibility here, she would probably have to do string-replacement when reading in the JS eval_script because the interaction between python and JS is difficult.

@mlubej
Copy link
Contributor

mlubej commented Jan 27, 2025

Hi @SlowMo24!

Can you show the evalscript you are using where you get these -999 default values?

Cheers!

@SlowMo24
Copy link
Author

SlowMo24 commented Feb 25, 2025

Hy @mlubej , I did some more investigation. It seems like I raised the issue prematurely/on an intermediate state of my code. The default is in fact nan and the get_data method returns just that .... for "FLOAT32"

But this is not the case for "UINT8" where a nan value does not exist. By default, sentinelhub will use 0 as nan and not set the nodataValue of the returned raster. Therefore we have to manually set the nodataValue (in our case 255 because 0 has a meaning). Yet, the python client does not respect the nodataValue exposed by Uint8 rasters (whereas e.g. QGis does for the exact same image).

I'm sorry for the imprecise issue.

Here is some code to reproduce the issue. A masked array may still be an option to investigate but might be an overkill...

import numpy as np
from sentinelhub import SentinelHubRequest, DataCollection, MimeType, SHConfig, BBox, CRS

bbox = BBox((
    9.280732, -0.263633, 9.316524, -0.241747
), crs=CRS("4326"))
config = SHConfig()

evalscript_true_color = """
    //VERSION=3

    function setup() {
        return {
            input: [{
                bands: ["B02"]
            }],
            output: {
                bands: 1
            }
        };
    }

    function evaluatePixel(sample) {
        return [undefined];
    }
"""
input_data = [
    SentinelHubRequest.input_data(
        data_collection=DataCollection.SENTINEL2_L1C,
        time_interval=("2020-06-12", "2020-06-13"),
    ),
]

responses = [SentinelHubRequest.output_response("default", MimeType.TIFF)]

request = SentinelHubRequest(
    evalscript=evalscript_true_color,
    input_data=input_data,
    responses=responses,
    bbox=bbox,
    config=config,
    data_folder='cache'
)

data = request.get_data(save_data=True,)[0]
print(data)
print(type(data))
print(np.unique(data))
print(np.isnan(data).any())

prints

[[0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 ...
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]]
<class 'numpy.ndarray'>
[0]
False

and writes the following file

dbf75d56da4136646a599522d74be1df.zip

Adding nodataValue: 255 to the eval script does not change anything (which may not be the desired output of sentinelhub in general?) but also changing return [undefined]; to return [255]; will at least create a valid geotiff:

5791dc7157b0faf8209310e145e875d7.zip

although sentinelhub-py does not read it correctly:

[[255 255 255 ... 255 255 255]
 [255 255 255 ... 255 255 255]
 [255 255 255 ... 255 255 255]
 ...
 [255 255 255 ... 255 255 255]
 [255 255 255 ... 255 255 255]
 [255 255 255 ... 255 255 255]]
<class 'numpy.ndarray'>
[255]
False

I hope I was able to provide the information required?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants