QGIS Temporal Controller dengan data raster

Oct 20 2020

Mulai dari QGIS 3.14 TimeManager sudah mati, hiduplah Pengontrol Waktu! Ada banyak tutorial di luar sana bagaimana "Pengontrol Temporal" menangani lapisan vektor, yang terlihat bagus. Namun, saya banyak bekerja dengan data raster dan saya tidak dapat menemukan informasi apa pun, cara mendapatkan perilaku yang serupa seperti di TimeManager.

Saya memiliki NetCDF seperti ini:

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" ;
}

Ketika saya memuat file ini di QGIS, langkah waktu dimuat sebagai band (di Tab Simbologi, mereka ditampilkan sebagai Band 1: time=52244 (days since 1858-11-17 00:00:00)dan seterusnya ...). Namun, Temporal-Tab hanya menawarkan rentang waktu tetap seperti yang ditunjukkan pada tangkapan layar:

Saya berharap bahwa Pengontrol Temporal secara otomatis mengenali bahwa lapisan adalah langkah waktu tetapi tombol "Otomatis" tidak aktif. Adakah yang punya pengalaman dengan lapisan raster di "Temporal Controller"? Bagaimana saya dapat mengubah data saya agar diinterpretasikan dengan benar? Atau apakah fungsi ini tidak diterapkan (karena Pengontrol Temporal cukup baru)?

Jawaban

1 Joonala Nov 13 2020 at 13:27

Saya menulis skrip PyQGIS untuk menangani solusi untuk file NetCDF yang menggunakan updateTemporalRangesinyal pengontrol temporal . Cukup salin skrip berikut ke jendela editor QGIS Python, edit tanggal Anda, jalankan skrip dan gunakan Pengontrol Temporal seperti biasa.

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))) 

Berikut adalah animasi gif sederhana yang menunjukkan penggunaannya: