Tarama verileri ile QGIS Temporal Controller

Oct 20 2020

QGIS 3.14'ten başlayarak TimeManager öldü, çok yaşa Temporal Controller! "Temporal Controller" ın vektör katmanları ile nasıl ilgilendiği konusunda pek çok öğretici var, bu güzel görünüyor. Bununla birlikte, raster verilerle çok çalışıyorum ve herhangi bir bilgi bulamıyorum, TimeManager'da olduğu gibi benzer bir davranışı nasıl elde edeceğim.

Bunun gibi bir NetCDF'im var:

ncdump -h SLA_ts.nc 
netcdf SLA_ts {
dimensions:
    time = 124 ;
    lat = 5 ;
    lon = 5 ;
variables:
    char crs ;
        crs:grid_mapping_name = "latitude_longitude" ;
        crs:long_name = "CRS definition" ;
        crs:semi_major_axis = 6378136.3 ;
        crs:inverse_flattening = 298.257 ;
    float time(time) ;
        time:long_name = "time" ;
        time:calendar = "standard" ;
        time:units = "days since 1858-11-17 00:00:00.0" ;
        time:actual_range = 52244., 55987.735625 ;
    float lat(lat) ;
        lat:standard_name = "latitude" ;
        lat:long_name = "latitude" ;
        lat:units = "degrees_north" ;
        lat:actual_range = 53.8, 54.2 ;
    float lon(lon) ;
        lon:standard_name = "longitude" ;
        lon:long_name = "longitude" ;
        lon:units = "degrees_east" ;
        lon:actual_range = 7.5, 7.9 ;
    float sla(time, lat, lon) ;
        sla:_FillValue = NaNf ;
        sla:grid_mapping = "crs" ;
        sla:long_name = "sea level anomaly" ;
        sla:unit = "m" ;

// global attributes:
        :Conventions = "CF-1.5" ;
}

Bu dosyayı QGIS'e yüklediğimde, zaman adımları bantlar olarak yüklenir (Semboloji-Sekmesinde, şu şekilde görüntülenir Band 1: time=52244 (days since 1858-11-17 00:00:00)ve böyle devam eder ...). Ancak, Temporal-Tab, ekran görüntüsünde gösterildiği gibi yalnızca sabit bir zaman aralığı sunar:

Temporal Controller'ın katmanların zaman adımları olduğunu otomatik olarak algılamasını beklerdim, ancak "Otomatik" düğmesi devre dışı. "Temporal Controller" da raster katmanlarla herhangi bir deneyimi olan var mı? Verilerimi doğru yorumlanacak şekilde nasıl değiştirebilirim? Yoksa bu işlevsellik basitçe uygulanmadı mı (Geçici Denetleyici oldukça yeni olduğundan)?

Yanıtlar

1 Joonala Nov 13 2020 at 13:27

Geçici denetleyicinin updateTemporalRangesinyalini kullanan NetCDF dosyalarının geçici çözümünü işlemek için bir PyQGIS betiği yazdım . Aşağıdaki komut dosyasını QGIS Python düzenleyici penceresine kopyalayın, tarihlerinizi düzenleyin, komut dosyasını çalıştırın ve her zamanki gibi Temporal Controller'ı kullanın.

import datetime

# These functions are part of https://github.com/GispoCoding/qgis_plugin_tools/blob/master/tools/raster_layers.py

def set_raster_renderer_to_singleband(layer: QgsRasterLayer, band: int = 1) -> None:
    """
    Set raster renderer to singleband
    :param layer: raster layer
    """
    # https://gis.stackexchange.com/a/377631/123927 and https://gis.stackexchange.com/a/157573/123927
    provider: QgsRasterDataProvider = layer.dataProvider()
    renderer: QgsSingleBandGrayRenderer = QgsSingleBandGrayRenderer(layer.dataProvider(), band)

    stats: QgsRasterBandStats = provider.bandStatistics(band, QgsRasterBandStats.All, layer.extent(), 0)
    min_val = max(stats.minimumValue, 0)
    max_val = max(stats.maximumValue, 0)

    enhancement = QgsContrastEnhancement(renderer.dataType(band))
    contrast_enhancement = QgsContrastEnhancement.StretchToMinimumMaximum
    enhancement.setContrastEnhancementAlgorithm(contrast_enhancement, True)
    enhancement.setMinimumValue(min_val)
    enhancement.setMaximumValue(max_val)
    layer.setRenderer(renderer)
    layer.renderer().setContrastEnhancement(enhancement)
    layer.triggerRepaint()
    
def set_band_based_on_range(layer: QgsRasterLayer, t_range: QgsDateTimeRange) -> int:
    """

    :param layer: raster layer
    :param t_range: temporal range
    :return: band number
    """
    band_num = 1
    tprops: QgsRasterLayerTemporalProperties = layer.temporalProperties()
    if tprops.isVisibleInTemporalRange(t_range) and t_range.begin().isValid() and t_range.end().isValid():
        if tprops.mode() == QgsRasterLayerTemporalProperties.ModeFixedTemporalRange:
            layer_t_range: QgsDateTimeRange = tprops.fixedTemporalRange()
            start: datetime.datetime = layer_t_range.begin().toPyDateTime()
            end: datetime.datetime = layer_t_range.end().toPyDateTime()
            delta = (end - start) / layer.bandCount()
            band_num = int((t_range.begin().toPyDateTime() - start) / delta) + 1
            set_raster_renderer_to_singleband(layer, band_num)
    return band_num
    
def set_fixed_temporal_range(layer: QgsRasterLayer, t_range: QgsDateTimeRange) -> None:
    """
    Set fixed temporal range for raster layer
    :param layer: raster layer
    :param t_range: fixed temporal range
    """
    mode = QgsRasterLayerTemporalProperties.ModeFixedTemporalRange
    tprops: QgsRasterLayerTemporalProperties = layer.temporalProperties()
    tprops.setMode(mode)
    if t_range.begin().timeSpec() == 0 or t_range.end().timeSpec() == 0:
        begin = t_range.begin()
        end = t_range.end()
        begin.setTimeSpec(Qt.TimeSpec(1))
        end.setTimeSpec(Qt.TimeSpec(1))
        t_range = QgsDateTimeRange(begin, end)
    tprops.setFixedTemporalRange(t_range)
    tprops.setIsActive(True)
    
def temporal_range_changed(t_range: QgsDateTimeRange):
    layer = iface.activeLayer()
    if isinstance(layer, QgsRasterLayer):
        set_band_based_on_range(layer, t_range)
    
def set_range():
    mode = QgsRasterLayerTemporalProperties.ModeFixedTemporalRange
    
temporal_controller: QgsTemporalController = iface.mapCanvas().temporalController()
temporal_controller.updateTemporalRange.connect(temporal_range_changed)
# Add one second to make the last frame visible
set_fixed_temporal_range(iface.activeLayer(), QgsDateTimeRange(datetime.datetime(2020, 11, 2, 15, 0), datetime.datetime(2020, 11, 3, 11, 0, 1))) 

İşte kullanımı gösteren basit bir gif animasyonu: