[Spectral View] wavelength information from GeetseEarthEngineRasterDataProvider not supported anymore

Issue #1270 resolved
Andreas Rabe created an issue

We used to supported spectral profile plotting for GeetseEarthEngineRasterDataProvider WMS layer.

Wavelength information was provided via GeetseEarthEngineRasterDataProvider.wavelength:

Currently, this information is not used anymore by the Spectral View.

We can still plot against Band Numbers…

…but plotting against wavelength is not supported anymore:

Comments (18)

  1. Andreas Rabe reporter

    @Benjamin Jakimow I guess you changed something in the metadata handling and how wavelength information is requested.

    Anything I should do different or will you just reconnect the Provider.wavelength logic?

  2. Andreas Rabe reporter

    Hi @Benjamin Jakimow , here is a code snippet to reproduce the problem:

    import numpy as np
    
    from enmapbox.qgispluginsupport.qps.qgsrasterlayerproperties import QgsRasterLayerSpectralProperties
    from enmapboxprocessing.driver import Driver
    from qgis._core import QgsRasterLayer
    
    # create layer that reports his wavelength view Provider.wavelength
    Driver('test.tif').createFromArray(np.zeros((3, 1, 1)))
    layer = QgsRasterLayer('test.tif')
    provider = layer.dataProvider()
    provider.wavelength = lambda bandNo: 42 + bandNo
    
    # get the wavelength
    props = QgsRasterLayerSpectralProperties.fromRasterLayer(layer)
    print(props)
    print(props.__dict__)
    

    The result only contains “mBandCount“ info:

    <enmapbox.qgispluginsupport.qps.qgsrasterlayerproperties.QgsRasterLayerSpectralProperties object at 0x000001D445029E50>
    {'mBandCount': 3}
    

  3. Andreas Rabe reporter

    Oh no, it’s more complicated than I thought.

    It looks like you are caching the wavelength information when the layer is added.

    In case of GEE TSE WMS layers, the wavelength information is set AFTER you already cached the information (i.e. no wavelength available) 😅

    Shall we have a spectralPropertiesChanged signal, that I can emit?

  4. Benjamin Jakimow

    I don’t understand what you mean with “caching”?
    The spectral layer properties are read each time the user makes a mouse click. This is implemented in the SpectralProfileBridge.loadProfiles():

    for uri, BLOCKS in SOURCE_BLOCKS.items():
        layer: QgsRasterLayer = URI2LAYER[uri]
        spectralProperties = QgsRasterLayerSpectralProperties.fromRasterLayer(layer)
    

    In you code-snippet you create a layer with a gdal data provider. In that case it is expected the provider delivers metadata using the GDAL metadata model (the future C++ implementation of the QgsRasterLayerSpectralProperties will do that the same way):

    In case of other providers (provider.name() != 'gdal') the current python prototype looks for your GEE “wavelength” implementation like:

            # wavelength() can be available for custom providers like EE
            if hasattr(provider, 'wavelength'):
                wl = np.array([provider.wavelength(bandNo) for bandNo in range(1, provider.bandCount() + 1)])
                wlu = 'Nanometers'
                self.setBandValues(None, 'wl', wl)
                self.setBandValues(None, 'wlu', wlu)
    

  5. Andreas Rabe reporter

    I don’t understand what you mean with “caching”?

    Ah ok, I thought you are caching the spectral properties once and not asking the the Provider.wavelength() every time you need wavelength information.

    Sorry,

    In you code-snippet you create a layer with a gdal data provider. In that case the provider should deliver the metadata as known from GDAL, using the GDAL metadata model.

    Ah ok, I will create a test with a WMS layer.

  6. Andreas Rabe reporter

    Ok, here is a new test snippet:

    import numpy as np
    
    from enmapbox import EnMAPBox
    from enmapbox.testing import start_app
    from enmapboxprocessing.driver import Driver
    from qgis._core import QgsRasterLayer
    
    qgsApp = start_app()
    enmapBox = EnMAPBox(load_other_apps=False)
    
    # create a layer that reports his wavelength via Provider.wavelength
    Driver('test.tif').createFromArray(np.array(list(range(3*2*2))).reshape(((3, 2, 2))))
    layer = QgsRasterLayer('test.tif', 'test')
    provider = layer.dataProvider()
    provider.wavelength = lambda bandNo: 42 + bandNo
    provider.name = lambda: 'dummy'  # GDAL provider is not allowed to report his wavelength, so we overwrite the name
    
    enmapBox.onDataDropped([layer])
    qgsApp.exec_()
    

    It works as expected, when plotting against Band Numbers:

    It’s not working, when plotting against the wavelength:

  7. Andreas Rabe reporter

    Also outputs a warning:

    D:\source\QGISPlugIns\enmap-box\enmapbox\qgispluginsupport\qps\pyqtgraph\pyqtgraph\graphicsItems\ScatterPlotItem.py:974: RuntimeWarning: All-NaN slice encountered
      self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
    D:\source\QGISPlugIns\enmap-box\enmapbox\qgispluginsupport\qps\pyqtgraph\pyqtgraph\graphicsItems\ScatterPlotItem.py:974: RuntimeWarning: All-NaN slice encountered
      self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
    D:\source\QGISPlugIns\enmap-box\enmapbox\qgispluginsupport\qps\pyqtgraph\pyqtgraph\graphicsItems\ScatterPlotItem.py:974: RuntimeWarning: All-NaN slice encountered
      self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
    D:\source\QGISPlugIns\enmap-box\enmapbox\qgispluginsupport\qps\pyqtgraph\pyqtgraph\graphicsItems\ScatterPlotItem.py:974: RuntimeWarning: All-NaN slice encountered
      self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
    

  8. Andreas Rabe reporter

    I also printed every time the wavelength are queried:

    That looks good. Prints as expected:

    call provider.wavelength
    provider.wavelength: [43 44 45]
    

  9. Andreas Rabe reporter

    Ok, I think it’s save to say, that this has nothing to do with GEE TSE or WMS layer in general.

  10. Andreas Rabe reporter
    1. Do you get an error? I don’t.
    2. Can we just skip the test for GDAL providers? That would make it much easier.

  11. Benjamin Jakimow

    @Andreas Janz Long story short. The wavelength information was lost during the JSON serialization (numpy data types are serialized to None). This should now be fixed.
    Furthermore I fixed your test example using a proper data provider (snippets/issues/issue1270.py) which can be cloned.
    Please check if this works with your GEE provider as well.

  12. Log in to comment