QGIS Temporal Controller พร้อมข้อมูลแรสเตอร์

Oct 20 2020

เริ่มตั้งแต่ QGIS 3.14 TimeManager ตายไปแล้ว Temporal Controller ใช้ชีวิตไปนาน ๆ ! มีบทเรียนมากมายเกี่ยวกับวิธีที่ "Temporal Controller" จัดการกับเลเยอร์เวกเตอร์ซึ่งดูดี อย่างไรก็ตามฉันทำงานกับข้อมูลแรสเตอร์เป็นจำนวนมากและฉันไม่พบข้อมูลใด ๆ วิธีการรับพฤติกรรมที่คล้ายกันใน TimeManager

ฉันมี NetCDF เช่นนี้:

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

เมื่อฉันโหลดไฟล์นี้ใน QGIS ขั้นตอนเวลาจะถูกโหลดเป็นแบนด์ (ใน Symbology-Tab จะแสดงเป็นBand 1: time=52244 (days since 1858-11-17 00:00:00)และอื่น ๆ ... ) อย่างไรก็ตาม Temporal-Tab มีเฉพาะช่วงเวลาที่แน่นอนตามที่แสดงในภาพหน้าจอ:

ฉันคาดว่า Temporal Controller จะรับรู้โดยอัตโนมัติว่าเลเยอร์ต่างๆเป็นขั้นตอนของเวลา แต่ปุ่ม "อัตโนมัติ" ไม่ทำงาน มีใครเคยสัมผัสแรสเตอร์เลเยอร์ใน "Temporal Controller" บ้าง? ฉันจะแก้ไขข้อมูลให้ตีความถูกต้องได้อย่างไร? หรือฟังก์ชั่นนี้ไม่ได้ใช้งาน (เนื่องจาก Temporal Controller ค่อนข้างใหม่)?

คำตอบ

1 Joonala Nov 13 2020 at 13:27

ฉันเขียนสคริปต์ PyQGIS เพื่อจัดการวิธีแก้ปัญหาสำหรับไฟล์ NetCDF ซึ่งใช้updateTemporalRangeสัญญาณของคอนโทรลเลอร์ชั่วคราว เพียงคัดลอกสคริปต์ต่อไปนี้ไปยังหน้าต่างตัวแก้ไข QGIS Python แก้ไขวันที่ของคุณเรียกใช้สคริปต์และใช้ Temporal Controller ตามปกติ

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

นี่คือภาพเคลื่อนไหว gif ง่ายๆที่แสดงการใช้งาน: