Bagikan melalui


Membuat item Katalog Aset SpatioTemporal (STAC)

Pelajari cara membuat item SpatioTemporal Asset Catalog (STAC) untuk aset data geospasial raster. Setiap aset data geospasial yang diunggah ke Microsoft Planetary Computer Pro GeoCatalog harus memiliki Item terkait yang mematuhi STAC.

Dalam panduan ini, Anda:

  • Instal pustaka Python yang diperlukan menggunakan PIP.
  • Tampilkan dan periksa data GOES-18 menggunakan kode Python yang disediakan.
  • Ekstrak metadata dari nama file menggunakan ekspresi reguler.
  • Buat Item STAC dari Cloud-Optimized file GeoTIFF menggunakan rio-stac.
  • Tingkatkan Item STAC dengan metadata yang diekstrak dari nama file.
  • Tambahkan Item STAC ke Koleksi STAC induk.
  • Validasi dan simpan katalog, koleksi, dan item STAC.
  • Tambahkan Item STAC ke Microsoft Planetary Computer Pro.

Tutorial ini menunjukkan dan menjelaskan kemampuan melalui cuplikan kode, untuk pengalaman gaya notebook interaktif, unduh tutorial ini sebagai notebook Jupyter.

Prasyarat

Untuk menyelesaikan panduan singkat ini, Anda memerlukan:

Fitur Utama STAC

Katalog Aset SpatioTemporal (STAC) adalah standar terbuka untuk menyusun dan berbagi data geospasial. Ini menyediakan bahasa dan format umum untuk menjelaskan aset geospasial, sehingga lebih mudah untuk menemukan, mengakses, dan menggunakan sumber daya ini di berbagai platform dan aplikasi. Berikut ini adalah fitur utama dari standar STAC:

  • Interoperabilitas: Skema berbasis JSON standar memastikan integrasi dan pemahaman yang mudah di seluruh alat dan sistem.
  • Ekstensibilitas: Bidang inti fleksibel dengan ekstensi kustom untuk kebutuhan tertentu.
  • Kemudahan ditemukan: Struktur yang konsisten meningkatkan pencarian dan penemuan aset geospasial.
  • Aksesibilitas: Tautan langsung ke aset data memfasilitasi pengambilan dan integrasi yang mulus.
  • Otomatisasi: Memungkinkan pemrosesan dan analisis otomatis dengan metadata standar.

Manfaat STAC untuk Standardisasi Metadata

  • Konsistensi Di Seluruh Jenis Data: Kerangka kerja terpadu untuk berbagai jenis data geospasial.
  • Kolaborasi yang Ditingkatkan: Menyederhanakan berbagi dan kolaborasi dengan format metadata umum.
  • Integrasi Data yang Ditingkatkan: Memfasilitasi integrasi himpunan data dari beberapa sumber.
  • Manajemen Data Yang Disederhanakan: Alat otomatis mengurangi upaya manual dalam mempertahankan metadata.
  • Memastikan Masa Depan: Sifat yang fleksibel memungkinkan adaptasi terhadap jenis data dan teknologi baru.

Microsoft Planetary Computer Pro (MC Pro) menggunakan STAC sebagai standar pengindeksan intinya untuk memberikan interoperabilitas antar himpunan data. Tutorial ini menunjukkan kepada pengguna cara membuat Item STAC dari awal menggunakan pustaka sumber terbuka umum.

Spesifikasi Item STAC merinci bagaimana Item STAC dibangun dan metadata minimum yang diperlukan yang harus diisi. STAC adalah standar yang fleksibel, memungkinkan pengguna untuk memutuskan data mana yang ingin mereka sertakan sebagai bagian dari metadata. Metadata yang dapat digunakan untuk mengisi Item STAC mungkin disertakan dalam aset data, dalam file sidecar (.XML, . JSON, .TXT dll.), atau bahkan di lokasi seperti nama file. Pengguna harus mempertimbangkan jenis metadata yang mungkin ingin dicari dan diurutkan di masa mendatang saat memutuskan metadata mana yang akan disertakan.

Tutorial ini menggunakan sampel data citra Cloud Optimized GeoTIFF (COG) dari himpunan data National Oceanic and Atmospheric Agency (NOAA) Geostationary Operational Environmental Satellite R (GOES-R) satelit Land Surface Temperature (LST). Data ini disertakan dalam Komputer Planetary terbuka sebagai file COG, tetapi tidak memiliki metadata STAC. Satelit GOES menghasilkan banyak produk data. Detail selengkapnya dapat ditemukan di Panduan Definisi Produk dan Pengguna SeriGOES-R.

Proses yang digunakan dalam tutorial ini dapat digeneralisasi untuk semua jenis data di mana bidang metadata kunci dijumlahkan menggunakan beberapa pustaka sumber terbuka.

Menginstal pustaka Python

Untuk memulai, kami menginstal pustaka Python yang diperlukan menggunakan PIP:

  • rasterio: Paket ini digunakan untuk membaca dan menulis data geospasial raster. Ini menyediakan alat untuk bekerja dengan format data raster seperti GeoTIFF.

  • pystac: Paket ini digunakan untuk bekerja dengan standar STAC. Ini menyediakan alat untuk membuat, membaca, dan memanipulasi metadata STAC.

  • rio-stac: Paket ini terintegrasi rasterio dengan pystac untuk membuat Item STAC dari data raster. Ini menyederhanakan proses pembuatan metadata STAC untuk himpunan data raster.

  • matplotlib: Pustaka ini digunakan untuk membuat visualisasi dan plot. Dalam konteks data geospasial, ini membantu merender dan menampilkan gambar raster, memungkinkan pengguna untuk memeriksa data secara visual sebelum membuat metadata STAC.

  • azure-storage-blob: Pustaka klien Azure Storage ini menyediakan akses ke layanan Azure Blob Storage. Ini memungkinkan interaksi langsung dengan data geospasial yang disimpan cloud, memungkinkan pengguna untuk membaca dan bekerja dengan file yang disimpan dalam kontainer Azure Blob tanpa mengunduhnya terlebih dahulu.

!pip install rasterio pystac rio_stac matplotlib azure-storage-blob 

Bagian kode berikutnya menampilkan beberapa data GOES-18 dari Komputer Planetary yang terbuka. Kami memilih set data GOES-R Advanced Baseline Imager Level 2 Land Surface Temperature - CONUS, dan file sembarang dari hari ke-208 tahun 2023.

# Import Necessary Libraries 
import requests
from azure.storage.blob import ContainerClient
import matplotlib.pyplot as plt
from rasterio.io import MemoryFile
import os
from urllib.parse import urlparse

# Function to get the SAS token
def get_sas_token(endpoint):
    response = requests.get(endpoint)
    if response.status_code == 200:
        data = response.json()
        return data.get("token")
    else:
        raise Exception(f"Failed to get SAS token: {response.status_code} - {response.text}")

# Define Azure Blob Storage parameters
storage_account_name = "goeseuwest"
container_name = "noaa-goes-cogs"
blob_domain = f"https://{storage_account_name}.blob.core.windows.net"
sas_endpoint = f"https://planetarycomputer.microsoft.com/api/sas/v1/token/{storage_account_name}/{container_name}/"


# Get the SAS token
sas_token = get_sas_token(sas_endpoint)

# Construct the container URL with the SAS token
container_url = f"{blob_domain}/{container_name}?{sas_token}"

# Create a ContainerClient
container_client = ContainerClient.from_container_url(container_url)

# Define data you want, this can be changed for other datasets that are in storage in the open Planetary Computer
satellite = "goes-18"      # The specific GOES satellite (GOES-18, also known as GOES-West)
product = "ABI-L2-LSTC"    # The data product type (Advanced Baseline Imager Level 2 Land Surface Temperature - CONUS)
year = "2023"              # The year the data was collected
day_of_year = "208"        # The day of year (DOY) - day 208 corresponds to July 27, 2023

# Construct the directory path
directory_path = f"{satellite}/{product}/{year}/{day_of_year}/"

# Get just the first blob by using next() and limiting the iterator

first_blob = next(container_client.list_blobs(name_starts_with=directory_path))

# Function to read and display a .tif file from a URL
def display_tif_from_url(url, title):
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        with MemoryFile(response.content) as memfile:
            with memfile.open() as dataset:
                plt.figure(figsize=(10, 10))
                plt.imshow(dataset.read(1), cmap='gray')
                plt.title(title)
                plt.colorbar()
                plt.show()
    else:
        raise Exception(f"Failed to read .tif file: {response.status_code} - {response.text}")

# Create the URL for the blob using the container_url components
file_url = f"{blob_domain}/{container_name}/{first_blob.name}?{sas_token}"

# Extract the filename safely from the URL without the SAS token
parsed_url = urlparse(file_url)
path = parsed_url.path  # Gets just the path portion of the URL
filename = os.path.basename(path)  # Get just the filename part

# Remove .tif extension if present
file_name = filename.replace('.tif', '')

print(f"Extracted File Name: {file_name}")

display_tif_from_url(file_url, file_name)

Visualisasi skala abu-abu dari data raster geospasial dari satelit GOES-18, memperlihatkan pola suhu permukaan tanah di seluruh wilayah.

Dari melihat data dan nama file, kita sudah dapat melihat potongan-potongan kunci metadata yang diperlukan untuk membangun Item STAC. Nama file berisi informasi tentang satelit mana yang mengambil data dan kapan diambil.

Untuk sampel, nama file OR_ABI-L2-LSTC-M6_G18_s20232080101177_e20232080103550_c20232080104570_DQF, berdasarkan panduan produk, ini berarti:

Komponen Terperinci

Bidang Deskripsi Tujuan
ATAU Lingkungan sistem operasional Menentukan lingkungan sistem tempat data dikumpulkan
ABI Instrumen Baseline Imager Tingkat Lanjut Mengidentifikasi instrumen yang digunakan untuk menangkap data
L2 Produk tingkat 2 (produk turunan) Menunjukkan bahwa data adalah produk turunan, diproses dari pengamatan mentah
LSTC Produk Suhu Permukaan Tanah (Langit Cerah) Mewakili jenis produk tertentu, berfokus pada suhu permukaan darat di bawah kondisi langit yang cerah
M6 Pemindaian Mode 6 (Pemindaian Disk Penuh) Menjelaskan mode pemindaian, mencakup disk lengkap Bumi
G18 Satelit GOES-18 (juga dikenal sebagai GOES-West) Mengidentifikasi satelit tempat data dikumpulkan

Detail Waktu Pengamatan

Mulai Pengamatan (s20232080201177)-

Bidang Deskripsi Tujuan
Tahun 2023 Menentukan tahun pengamatan
Hari Dalam Setahun 208 Menunjukkan hari dalam setahun ketika pengamatan dimulai
Waktu 02:01:17 UTC Menyediakan waktu tepat ketika pengamatan dimulai dalam UTC
Persepuluh Detik 7 Menambahkan presisi ke waktu mulai pengamatan

Akhir Pengamatan (e20232080203550)-

Bidang Deskripsi Tujuan
Tahun 2023 Menentukan tahun pengamatan
Hari Dalam Setahun 208 Menunjukkan hari dalam setahun ketika pengamatan berakhir
Waktu 02:03:55 UTC Menyediakan waktu yang tepat pengamatan berakhir di UTC
Persepuluh Detik 0 Menambahkan presisi ke waktu akhir pengamatan

Waktu Pembuatan File (c20232080204563)-

Bidang Deskripsi Tujuan
Tahun 2023 Menentukan tahun file dibuat
Hari Dalam Setahun 208 Menunjukkan hari dalam setahun ketika file dibuat
Waktu 02:04:56 UTC Menyediakan waktu yang tepat file dibuat di UTC
Persepuluh Detik 3 Menambahkan presisi ke waktu pembuatan file

Informasi Tambahan:

Bidang Deskripsi Tujuan
DQF Bendera Kualitas Data, menunjukkan informasi kualitas untuk data yang sesuai Menyediakan informasi tentang kualitas data
.tif Ekstensi berkas Menunjukkan format file dari data

Kode berikut mengekstrak metadata ini dari nama file menggunakan ekspresi reguler (regex).

import re
from datetime import datetime, timedelta

def extract_goes_metadata(filename):
    """
    Extracts key metadata from a NOAA GOES satellite filename using regular expressions.

    Args:
        filename (str): The filename to parse.

    Returns:
        dict: A dictionary containing the extracted metadata.
    """

    # Regular expression pattern to match the filename format
    pattern = re.compile(
        r"^(OR)_"  # System (OR)
        r"(ABI)-(L\d)-(LSTC)-(M\d)_"  # Instrument, Level, Product, Mode
        r"(G\d{2})_"  # Satellite (G18)
        r"s(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # Start time
        r"e(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # End time
        r"c(\d{4})(\d{3})(\d{2})(\d{2})(\d{2})(\d)_"  # Creation time
        r"([A-Z0-9]+)$"  # Data quality flag
    )

    match = pattern.match(filename)

    if not match:
        return None  # Or raise an exception if you prefer

    # Extract all fields from the regular expression match groups
    (
        system,          # Operational system environment
        instrument,      # Advanced Baseline Imager
        level,           # Product level (L2)
        product_type,    # Product type (LSTC - Land Surface Temperature)
        mode,            # Scanning mode (M6)
        satellite,       # Satellite identifier (G18)
        s_year, s_doy, s_hour, s_minute, s_second, s_tenth,  # Start time components
        e_year, e_doy, e_hour, e_minute, e_second, e_tenth,  # End time components
        c_year, c_doy, c_hour, c_minute, c_second, c_tenth,  # Creation time components
        data_quality_flag  # Quality flag indicator
    ) = match.groups()

    def parse_goes_time(year, doy, hour, minute, second, tenth):
        """Parses GOES time components into an ISO format string."""
        try:
            dt = datetime(int(year), 1, 1) + timedelta(
                days=int(doy) - 1,
                hours=int(hour),
                minutes=int(minute),
                seconds=int(second),
                microseconds=int(tenth) * 100000,
            )
            return dt
        except ValueError:
            return None

    # Parse the time components into datetime objects
    start_time = parse_goes_time(s_year, s_doy, s_hour, s_minute, s_second, s_tenth)
    end_time = parse_goes_time(e_year, e_doy, e_hour, e_minute, e_second, e_tenth)
    creation_time = parse_goes_time(c_year, c_doy, c_hour, c_minute, c_second, c_tenth)

    # Create a dictionary to organize all extracted metadata
    metadata = {
        "system": system,               # Operational system environment (e.g., "OR" for operational)
        "instrument": instrument,       # Instrument used to capture data (e.g., "ABI" for Advanced Baseline Imager)
        "level": level,                 # Processing level of the data (e.g., "L2" for Level 2)
        "product_type": product_type,   # Type of product (e.g., "LSTC" for Land Surface Temperature Clear Sky)
        "mode": mode,                   # Scanning mode (e.g., "M6" for Mode 6, full disk scan)
        "satellite": satellite,         # Satellite identifier (e.g., "G18" for GOES-18)
        "start_time": start_time,       # Observation start time as datetime object
        "end_time": end_time,           # Observation end time as datetime object
        "creation_time": creation_time, # File creation time as datetime object
        "data_quality_flag": data_quality_flag,  # Quality flag for the data (e.g., "DQF")
    }

    return metadata


# Example usage:
print(file_name)
metadata_from_filename = extract_goes_metadata(file_name)
print(metadata_from_filename)
OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF
{'system': 'OR', 'instrument': 'ABI', 'level': 'L2', 'product_type': 'LSTC', 'mode': 'M6', 'satellite': 'G18', 'start_time': datetime.datetime(2023, 7, 27, 0, 1, 17, 700000), 'end_time': datetime.datetime(2023, 7, 27, 0, 3, 55), 'creation_time': datetime.datetime(2023, 7, 27, 0, 4, 56, 800000), 'data_quality_flag': 'DQF'}

Membuat Item STAC dari Cloud-Optimized File GeoTIFF

Blok kode berikut menggunakan rio-stac pustaka untuk mengotomatiskan pembuatan item STAC dari Cloud-Optimized GeoTIFFs (COGs).

Ketika diarahkan ke file COG, rio-stac secara otomatis mengekstrak dan mengatur metadata penting seperti batas spasial, informasi proyeksi, dan properti raster ke dalam format STAC standar. Pustaka menangani tugas kompleks membaca metadata teknis yang disematkan dari GeoTIFF dan mengonversinya menjadi bidang yang mematuhi STAC, termasuk:

  • Geometri
  • Kotak Pembatas (bbox)
  • Detail Proyeksi
  • Karakteristik Raster
  • Ekstensi STAC

Otomatisasi ini secara signifikan mengurangi pekerjaan manual yang diperlukan untuk membuat Item STAC yang valid dan memastikan konsistensi dalam metadata

Nota

GeoCatalog memiliki batasan pada karakter yang dapat digunakan dalam ID Item STAC dan Kunci aset. Pastikan ID Anda tidak berisi karakter berikut: -, , _, +(, ), dan .. Anda mungkin perlu mengubah item_id logika pembuatan untuk mengganti atau menghapus karakter ini dari nama file Anda.

from rio_stac import create_stac_item
from rasterio.io import MemoryFile
import json
from urllib.parse import urlparse, unquote

def create_stac_item_from_cog(url):
    """
    Create a basic STAC Item for GOES data using rio-stac with proper spatial handling
    
    Args:
        url (str): URL to the COG file
        
    Returns:
        pystac.Item: STAC Item with basic metadata and correct spatial information
    """
    
    # Extract the filename safely from the URL
    parsed_url = urlparse(url)
    path = parsed_url.path  # Gets just the path portion of the URL
    filename = os.path.basename(path)  # Get just the filename part
    
    # Remove .tif extension if present
    item_id = filename.replace('.tif', '')
    
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        with MemoryFile(response.content) as memfile:
            with memfile.open() as dataset:
                # Create base STAC item from rasterio dataset calling create_stac_item from rio_stac
                stac_item = create_stac_item(
                    source=dataset,  # The rasterio dataset object representing the COG file
                    id=item_id,  # Generate a unique ID by extracting the filename without the .tif extension
                    asset_name='data',  # Name of the asset, indicating it contains the primary data
                    asset_href=url,  # URL to the COG file, used as the asset's location
                    with_proj=True,  # Include projection metadata (e.g., CRS, bounding box, etc.)
                    with_raster=True,  # Include raster-specific metadata (e.g., bands, resolution, etc.)
                    properties={
                        'datetime': None,  # Set datetime to None since explicit start/end times may be added later
                        # Add rasterio-specific metadata for the raster bands
                        'raster:bands': [
                            {
                                'nodata': dataset.nodata,  # Value representing no data in the raster
                                'data_type': dataset.dtypes[0],  # Data type of the raster (e.g., uint16)
                                'spatial_resolution': dataset.res[0]  # Spatial resolution of the raster in meters
                            }
                        ],
                        'file:size': len(response.content)  # Size of the file in bytes
                    },
                    extensions=[
                        'https://stac-extensions.github.io/file/v2.1.0/schema.json'  # Add the file extension schema for additional metadata
                    ]
                )
                
                return stac_item
    else:
        raise Exception(f"Failed to read .tif file: {response.status_code} - {response.text}")

# Example usage
sas_token = get_sas_token(sas_endpoint) # refresh the SAS token prior to creating STAC item
# Create file URL using the first_blob variable that's already defined
file_url = f"{blob_domain}/{container_name}/{first_blob.name}?{sas_token}"
# Create STAC item for the first blob
stac_item = create_stac_item_from_cog(file_url)

# Print the STAC item as JSON
print(json.dumps(stac_item.to_dict(), indent=2))
    {
      "type": "Feature",
      "stac_version": "1.0.0",
      "stac_extensions": [
        "https://stac-extensions.github.io/file/v2.1.0/schema.json",
        "https://stac-extensions.github.io/projection/v1.1.0/schema.json",
        "https://stac-extensions.github.io/raster/v1.1.0/schema.json"
      ],
      "id": "OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -161.57885623466754,
              14.795666555826678
            ],
            [
              -112.42114380921453,
              14.79566655500485
            ],
            [
              -89.5501123912648,
              53.52729778421186
            ],
            [
              175.5501122574517,
              53.52729779865781
            ],
            [
              -161.57885623466754,
              14.795666555826678
            ]
          ]
        ]
      },
      "bbox": [
        -161.57885623466754,
        14.79566655500485,
        175.5501122574517,
        53.52729779865781
      ],
      "properties": {
        "datetime": "2025-03-26T14:46:05.484602Z",
        "raster:bands": [
          {
            "nodata": 65535.0,
            "data_type": "uint16",
            "spatial_resolution": 2004.017315487541
          }
        ],
        "file:size": 118674,
        "proj:epsg": null,
        "proj:geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -2505021.6463773525,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                1583173.791653181
              ]
            ]
          ]
        },
        "proj:bbox": [
          -2505021.6463773525,
          1583173.791653181,
          2505021.6423414997,
          4589199.764884492
        ],
        "proj:shape": [
          1500,
          2500
        ],
        "proj:transform": [
          2004.017315487541,
          0.0,
          -2505021.6463773525,
          0.0,
          -2004.017315487541,
          4589199.764884492,
          0.0,
          0.0,
          1.0
        ],
        "proj:wkt2": "PROJCS[\"unnamed\",GEOGCS[\"unknown\",DATUM[\"unnamed\",SPHEROID[\"Spheroid\",6378137,298.2572221]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]],PROJECTION[\"Geostationary_Satellite\"],PARAMETER[\"central_meridian\",-137],PARAMETER[\"satellite_height\",35786023],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],EXTENSION[\"PROJ4\",\"+proj=geos +lon_0=-137 +h=35786023 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs +sweep=x\"]]"
      },
      "links": [],
      "assets": {
        "data": {
          "href": "https://goeseuwest.blob.core.windows.net/noaa-goes-cogs/goes-18/ABI-L2-LSTC/2023/208/00/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.tif?st=2025-03-25T14%3A46%3A03Z&se=2025-03-26T15%3A31%3A03Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-03-26T12%3A41%3A49Z&ske=2025-04-02T12%3A41%3A49Z&sks=b&skv=2024-05-04&sig=BuMxN2NUTdrhzY7Dvpd/X4yfX8gnFpHOzANHQLkKE1k%3D",
          "type": "image/tiff; application=geotiff",
          "raster:bands": [
            {
              "data_type": "uint16",
              "scale": 1.0,
              "offset": 0.0,
              "sampling": "area",
              "nodata": 65535.0,
              "unit": "1",
              "statistics": {
                "mean": 2.780959413109756,
                "minimum": 0,
                "maximum": 3,
                "stddev": 0.710762086175375,
                "valid_percent": 100.0
              },
              "histogram": {
                "count": 11,
                "min": 0.0,
                "max": 3.0,
                "buckets": [
                  26655,
                  0,
                  0,
                  25243,
                  0,
                  0,
                  7492,
                  0,
                  0,
                  570370
                ]
              }
            }
          ],
          "roles": []
        }
      }
    }

item STAC JSON dari rio-stac

Pustaka rio-stac membaca file GOES COG dan secara otomatis mengekstrak metadata kunci.

Selain itu, berdasarkan jenis metadata yang disertakan, rio-stac menambahkan Ekstensi STAC yang relevan. Ekstensi STAC meningkatkan spesifikasi inti dengan menambahkan metadata khusus domain standar.

  • Ekstensi File menyediakan metadata file penting seperti ukuran dan checksum.
  • Ekstensi Proyeksi menangkap informasi referensi spasial termasuk sistem koordinat dan kotak pembatas.
  • Ekstensi Raster menstandarkan properti khusus untuk data raster, seperti informasi band dan resolusi spasial.

Tabel berikut memberikan penjelasan tentang semua metadata rio-stac yang ditemukan.

Bidang Inti

Bidang Deskripsi Tujuan
jenis Selalu "Fitur" Mengidentifikasi jenis sebagai Fitur GeoJSON
stac_version 1.0.0 Menentukan versi standar STAC
Id Pengidentifikasi unik Berisi informasi satelit, produk, dan waktu
stac_extensions Daftar URL skema Menentukan bidang metadata tambahan

Informasi Spasial

Bidang Deskripsi Tujuan
geometri Poligon GeoJSON Menentukan jejak data dalam koordinat WGS84
bbox Koordinat kotak pembatas Menyediakan tingkat spasial sederhana untuk pemfilteran cepat
proj:geometri Poligon khusus proyeksi Tapak dalam koordinat proyeksi asli
proj:bbox Batas proyeksi bawaan Tingkat spasial dalam sistem koordinat satelit
proj:bentuk [1500, 2500] Dimensi gambar dalam piksel
proj:transform Transformasi affine Memetakan piksel untuk mengoordinasikan ruang
proj:wkt2 Well-Known Text Menyelesaikan definisi proyeksi
proj:epsg nol Tidak ada kode EPSG standar untuk proyeksi peta ini

Informasi Temporal

Bidang Deskripsi Tujuan
tanggalwaktu Tanda waktu pembuatan Ketika item STAC ini dibuat

Informasi Raster

Bidang Deskripsi Tujuan
raster:bands Array objek pita Menjelaskan properti data raster
→ data_type uint16 Jenis data piksel
→ spatial_resolution 2004,02m Jarak sampel tanah
→ skala/offset Faktor konversi Mengubah nilai piksel menjadi unit fisik (Kelvin)
nodata 65535.0 Nilai yang tidak mewakili data
statistik → Ringkasan statistik Menyediakan informasi distribusi data
→ histogram Distribusi nilai Memvisualisasikan distribusi data

Informasi Aset

Bidang Deskripsi Tujuan
aset.data Aset data utama Menunjuk ke file data aktual
→ href URL Lokasi GeoTIFF Cloud-Optimized
jenis → Tipe media Mengidentifikasi format file

File Metadata

Bidang Deskripsi Tujuan
file:size 943.250 byte Ukuran file data

Menambahkan metadata dari Nama File

Selanjutnya, kami menambahkan data yang kami temukan dalam nama file untuk menyelesaikan pengisian metadata untuk Item STAC ini.

Satu hal yang perlu diperhatikan adalah semua tanggalwaktu untuk Item STAC harus sesuai dengan ISO 8601. Pustaka PySTAC memiliki fungsi datetime_to_str yang memastikan data diformat dengan benar.

import pystac

def enhance_stac_item_with_metadata(stac_item, metadata_from_filename):
    """
    Enhances a STAC Item with additional metadata from GOES filename.
    
    Args:
        stac_item (pystac.Item): Existing STAC Item created by rio-stac
        metadata_from_filename (dict): Metadata extracted from filename
        
    Returns:
        pystac.Item: Enhanced STAC Item
    """
    # Add satellite/sensor properties to the STAC item
    stac_item.properties.update({
        'platform': f"GOES-{metadata_from_filename['satellite'][1:]}",
        'instruments': [metadata_from_filename['instrument']],
        'constellation': 'GOES'
    })
    
    # Add temporal properties to the STAC item, use pystac to ensure time conforms to ISO 8601
    stac_item.datetime = None  # Clear the default datetime
    stac_item.properties.update({
        'start_datetime': pystac.utils.datetime_to_str(metadata_from_filename['start_time']),
        'end_datetime': pystac.utils.datetime_to_str(metadata_from_filename['end_time']),
        'created': pystac.utils.datetime_to_str(metadata_from_filename['creation_time'])
    })
    
    # Add GOES-specific properties to the STAC item
    stac_item.properties.update({
        'goes:system': metadata_from_filename['system'],
        'goes:level': metadata_from_filename['level'],
        'goes:product_type': metadata_from_filename['product_type'],
        'goes:mode': metadata_from_filename['mode'],
        'goes:processing_level': metadata_from_filename['level'],
        'goes:data_quality_flag': metadata_from_filename['data_quality_flag']
    })
    
    return stac_item


# Example usage in new cell
stac_item = enhance_stac_item_with_metadata(stac_item, metadata_from_filename)
print(json.dumps(stac_item.to_dict(), indent=2))

Item STAC:

    {
      "type": "Feature",
      "stac_version": "1.0.0",
      "stac_extensions": [
        "https://stac-extensions.github.io/file/v2.1.0/schema.json",
        "https://stac-extensions.github.io/projection/v1.1.0/schema.json",
        "https://stac-extensions.github.io/raster/v1.1.0/schema.json"
      ],
      "id": "OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -161.57885623466754,
              14.795666555826678
            ],
            [
              -112.42114380921453,
              14.79566655500485
            ],
            [
              -89.5501123912648,
              53.52729778421186
            ],
            [
              175.5501122574517,
              53.52729779865781
            ],
            [
              -161.57885623466754,
              14.795666555826678
            ]
          ]
        ]
      },
      "bbox": [
        -161.57885623466754,
        14.79566655500485,
        175.5501122574517,
        53.52729779865781
      ],
      "properties": {
        "datetime": null,
        "raster:bands": [
          {
            "nodata": 65535.0,
            "data_type": "uint16",
            "spatial_resolution": 2004.017315487541
          }
        ],
        "file:size": 118674,
        "proj:epsg": null,
        "proj:geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                -2505021.6463773525,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                1583173.791653181
              ],
              [
                2505021.6423414997,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                4589199.764884492
              ],
              [
                -2505021.6463773525,
                1583173.791653181
              ]
            ]
          ]
        },
        "proj:bbox": [
          -2505021.6463773525,
          1583173.791653181,
          2505021.6423414997,
          4589199.764884492
        ],
        "proj:shape": [
          1500,
          2500
        ],
        "proj:transform": [
          2004.017315487541,
          0.0,
          -2505021.6463773525,
          0.0,
          -2004.017315487541,
          4589199.764884492,
          0.0,
          0.0,
          1.0
        ],
        "proj:wkt2": "PROJCS[\"unnamed\",GEOGCS[\"unknown\",DATUM[\"unnamed\",SPHEROID[\"Spheroid\",6378137,298.2572221]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]],PROJECTION[\"Geostationary_Satellite\"],PARAMETER[\"central_meridian\",-137],PARAMETER[\"satellite_height\",35786023],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],EXTENSION[\"PROJ4\",\"+proj=geos +lon_0=-137 +h=35786023 +x_0=0 +y_0=0 +ellps=GRS80 +units=m +no_defs +sweep=x\"]]",
        "platform": "GOES-18",
        "instruments": [
          "ABI"
        ],
        "constellation": "GOES",
        "start_datetime": "2023-07-27T00:01:17.700000Z",
        "end_datetime": "2023-07-27T00:03:55Z",
        "created": "2023-07-27T00:04:56.800000Z",
        "goes:system": "OR",
        "goes:level": "L2",
        "goes:product_type": "LSTC",
        "goes:mode": "M6",
        "goes:processing_level": "L2",
        "goes:data_quality_flag": "DQF"
      },
      "links": [],
      "assets": {
        "data": {
          "href": "https://goeseuwest.blob.core.windows.net/noaa-goes-cogs/goes-18/ABI-L2-LSTC/2023/208/00/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.tif?st=2025-03-25T14%3A46%3A03Z&se=2025-03-26T15%3A31%3A03Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-03-26T12%3A41%3A49Z&ske=2025-04-02T12%3A41%3A49Z&sks=b&skv=2024-05-04&sig=BuMxN2NUTdrhzY7Dvpd/X4yfX8gnFpHOzANHQLkKE1k%3D",
          "type": "image/tiff; application=geotiff",
          "raster:bands": [
            {
              "data_type": "uint16",
              "scale": 1.0,
              "offset": 0.0,
              "sampling": "area",
              "nodata": 65535.0,
              "unit": "1",
              "statistics": {
                "mean": 2.780959413109756,
                "minimum": 0,
                "maximum": 3,
                "stddev": 0.710762086175375,
                "valid_percent": 100.0
              },
              "histogram": {
                "count": 11,
                "min": 0.0,
                "max": 3.0,
                "buckets": [
                  26655,
                  0,
                  0,
                  25243,
                  0,
                  0,
                  7492,
                  0,
                  0,
                  570370
                ]
              }
            }
          ],
          "roles": []
        }
      }
    }

Menambahkan Item STAC ke Koleksi

MC Pro mewajibkan semua Item STAC memiliki referensi ke ID Koleksi STAC induk yang dimasukkan. Untuk tutorial ini, ID Koleksi STAC adalah nama satelit dan produk data.

Dengan PySTAC, mudah untuk menggunakan beberapa metadata yang dikumpulkan dari file sumber untuk mengisi bidang kunci untuk Koleksi STAC dan menggunakan fungsi validasi bawaan.

Kode berikut membuat Koleksi STAC induk untuk menampung data GOES. Kode kemudian menyimpan informasi ini ke file yang digunakan untuk membuat koleksi Microsoft Planetary Computer Pro STAC dan menyerap item STAC ke Planetary Computer Pro.

# Define collection properties
collection_id = f"{satellite}-{product}"
collection_title = f"{satellite.upper()} {product} Collection" 
collection_desc = f"Collection of {satellite} {product} Earth observation data"

# Create spatial extent
bbox = [-180, -60, 10, 60]  # placeholder, replace with actual data at a later date
spatial_extent = pystac.SpatialExtent([bbox])

# Create temporal extent, use current date time or replace with existing datetimes in stac_item
start_datetime = datetime.now()
if hasattr(metadata_from_filename, 'get'): 
    if metadata_from_filename.get('start_time'):
        start_datetime = metadata_from_filename.get('start_time')

temporal_extent = pystac.TemporalExtent([[start_datetime, None]])
extent = pystac.Extent(spatial=spatial_extent, temporal=temporal_extent)

# Create the STAC Collection
collection = pystac.Collection(
    id=collection_id,
    description=collection_desc,
    extent=extent,
    title=collection_title,
    license="public-domain",
)

# Add keywords and provider
collection.keywords = ["GOES", "satellite", "weather", "NOAA", satellite, product]
collection.providers = [
    pystac.Provider(
        name="NOAA",
        roles=["producer", "licensor"],
        url="https://www.noaa.gov/"
    )
]

# Create output directories
output_dir = "stac_catalog"
collection_dir = os.path.join(output_dir, collection_id)
items_dir = os.path.join(collection_dir, "items")
os.makedirs(items_dir, exist_ok=True)

# Important: Save the collection first to generate proper file paths
collection_path = os.path.join(collection_dir, "collection.json")
collection.set_self_href(collection_path)

# Extract filename for the item
original_filename = first_blob.name.split('/')[-1]
base_filename = original_filename.replace('.tif', '')
item_path = os.path.join(items_dir, f"{base_filename}.json")

# Set the item's proper href
stac_item.set_self_href(item_path)

# Now associate the item with the collection (after setting hrefs)
collection.add_item(stac_item)

# Create a catalog to contain the collection
catalog = pystac.Catalog(
    id="goes-data-catalog",
    description="GOES Satellite Data Catalog",
    title="GOES Data"
)
catalog_path = os.path.join(output_dir, "catalog.json")
catalog.set_self_href(catalog_path)
catalog.add_child(collection)

# Validate the collection and contained items
print("Validating collection and items...")
try:
    collection.validate_all()
    print("✅ Collection and items validated successfully")
    
    # Save everything to disk
    catalog.normalize_and_save(catalog_path, pystac.CatalogType.SELF_CONTAINED)
    print(f"✅ STAC catalog saved at: {catalog_path}")
    print(f"✅ STAC collection saved at: {collection_path}")
    print(f"✅ STAC item saved at: {item_path}")
    
except Exception as e:
    print(f"❌ Validation error: {str(e)}")
Validating collection and items...
✅ Collection and items validated successfully
✅ STAC catalog saved at: stac_catalog/catalog.json
✅ STAC collection saved at: stac_catalog/goes-18-ABI-L2-LSTC/collection.json
✅ STAC item saved at: stac_catalog/goes-18-ABI-L2-LSTC/items/OR_ABI-L2-LSTC-M6_G18_s20232080001177_e20232080003550_c20232080004568_DQF.json

Langkah selanjutnya

Sekarang setelah Anda membuat beberapa Item STAC, saatnya untuk menyerap data ke Microsoft Planetary Computer Pro.

Untuk Penyerapan Item Tunggal:

Untuk Penyerapan Massal:

Kami juga menawarkan alat STAC Forge yang menyediakan peningkatan otomatisasi menggunakan templat di sekitar data.