Utwórz element SpatioTemporal Asset Catalog (STAC)

Dowiedz się, jak utworzyć element wykazu zasobów spatioTemporal (STAC) dla zasobu danych geoprzestrzennych rastrowych. Każdy zasób danych geoprzestrzennych przekazany do komputera Microsoft Planetary Computer Pro GeoCatalog musi mieć skojarzony element zgodny ze standardem STAC.

W tym przewodniku:

  • Zainstaluj wymagane biblioteki języka Python przy użyciu narzędzia PIP.
  • Wyświetlaj i sprawdzaj dane goes-18 przy użyciu podanego kodu języka Python.
  • Wyodrębnij metadane z nazwy pliku przy użyciu wyrażeń regularnych.
  • Utwórz elementy STAC z Cloud-Optimized plików GeoTIFF przy użyciu rio-stac.
  • Ulepsz element STAC za pomocą metadanych wyodrębnionych z nazwy pliku.
  • Dodaj element STAC do nadrzędnej kolekcji STAC.
  • Sprawdź poprawność i zapisz katalog STAC, kolekcję i pozycje.
  • Dodaj elementy STAC do Microsoft Planetary Computer Pro.

W tym samouczku pokazano i wyjaśniono możliwości za pomocą fragmentów kodu, aby uzyskać interaktywne doświadczenie w stylu notesu, pobierz ten samouczek jako notebook Jupyter.

Wymagania wstępne

Aby ukończyć tę instrukcję szybkiego startu, potrzebujesz:

Kluczowe funkcje stac

SpatioTemporal Asset Catalog (STAC) to otwarty standard do tworzenia struktury i udostępniania danych geoprzestrzennych. Udostępnia wspólny język i format opisujący zasoby geoprzestrzenne, co ułatwia odnajdywanie i uzyskiwanie dostępu do tych zasobów na różnych platformach i aplikacjach oraz korzystanie z nich. Poniżej przedstawiono kluczowe funkcje standardu STAC:

  • Współdziałanie: ustandaryzowany schemat oparty na formacie JSON zapewnia łatwą integrację i zrozumienie w różnych narzędziach i systemach.
  • Rozszerzalność: elastyczne pola podstawowe z rozszerzeniami niestandardowymi dla określonych potrzeb.
  • Odnajdywanie: Spójna struktura zwiększa wyszukiwanie i odnajdywanie zasobów geoprzestrzennych.
  • Ułatwienia dostępu: bezpośrednie linki do zasobów danych ułatwiają bezproblemowe pobieranie i integrację.
  • Automatyzacja: umożliwia automatyczne przetwarzanie i analizę za pomocą ustandaryzowanych metadanych.

Zalety standardyzacji metadanych STAC

  • Spójność między typami danych: ujednolicona struktura dla różnych typów danych geoprzestrzennych.
  • Rozszerzona współpraca: upraszcza udostępnianie i współpracę z typowym formatem metadanych.
  • Ulepszona integracja danych: ułatwia integrację zestawów danych z wielu źródeł.
  • Uproszczone zarządzanie danymi: zautomatyzowane narzędzia zmniejszają nakład pracy ręcznej w zakresie obsługi metadanych.
  • Odporność na przyszłość: rozszerzalny charakter dostosowuje się do nowych typów danych i technologii.

Microsoft Planetary Computer Pro (MC Pro) używa STAC jako podstawowego standardu indeksowania w celu zapewnienia współdziałania między zestawami danych. W tym samouczku pokazano użytkownikom, jak utworzyć elementy STAC od podstaw przy użyciu typowych bibliotek typu open source.

Specyfikacja elementu STAC zawiera szczegółowe informacje na temat konstruowania elementów STAC oraz wymaganych minimalnych metadanych, które muszą zostać wypełnione. STAC to elastyczny standard, który umożliwia użytkownikom podjęcie decyzji o tym, które dane mają zostać uwzględnione w ramach metadanych. Metadane, które mogą być użyte do wypełnienia elementu STAC, mogą być zawarte w zasobie danych, w pliku towarzyszącym (.XML, .JSON, .TXT itp.), a nawet w miejscach, takich jak nazwa pliku. Użytkownicy powinni rozważyć typy metadanych, które użytkownicy mogą chcieć wyszukiwać i sortować w przyszłości podczas podejmowania decyzji o tym, które metadane mają zostać uwzględnione.

W tym samouczku wykorzystano przykładowe obrazy GeoTIFF zoptymalizowane pod kątem chmury (COG) pochodzące z zestawu danych dotyczących temperatury powierzchni ziemi (LST) z satelitów geostacjonarnych operacyjnych NOAA (National Oceanic and Atmospheric Agency) R (GOES-R). Te dane są uwzględniane w otwartym komputerze planetarnym jako pliki COG, ale brakuje metadanych STAC. Satelity GOES produkują wiele produktów danych. Więcej szczegółów można znaleźć w przewodniku po definicjach produktów i użytkownikach seriiGOES-R.

Proces używany w tym samouczku można uogólnić dla dowolnego typu danych, w których pola metadanych klucza są wyliczane przy użyciu kilku bibliotek typu open source.

Instalowanie bibliotek języka Python

Aby rozpocząć, zainstalujemy wymagane biblioteki języka Python przy użyciu narzędzia:

  • rasterio: Ten pakiet służy do odczytywania i zapisywania danych rasterów geoprzestrzennych. Udostępnia narzędzia do pracy z formatami danych rasterowych, takimi jak GeoTIFF.

  • pystac: ten pakiet jest używany do pracy ze standardem STAC. Udostępnia narzędzia do tworzenia, odczytywania i manipulowania metadanymi STAC.

  • rio-stac: ten pakiet integruje rasterio się z pystac programem w celu utworzenia elementów STAC na podstawie danych rasterowych. Upraszcza to proces generowania metadanych STAC dla zestawów danych rasterowych.

  • matplotlib: Ta biblioteka służy do tworzenia wizualizacji i kreśleń. W kontekście danych geoprzestrzennych ułatwia renderowanie i wyświetlanie obrazów rastrowych, dzięki czemu użytkownicy mogą wizualnie sprawdzać dane przed utworzeniem metadanych STAC.

  • azure-storage-blob: Ta biblioteka klienta usługi Azure Storage zapewnia dostęp do usług Azure Blob Storage. Umożliwia ona bezpośrednią interakcję z danymi geoprzestrzennymi przechowywanymi w chmurze, umożliwiając użytkownikom odczytywanie i pracę z plikami przechowywanymi w kontenerach obiektów blob platformy Azure bez uprzedniego pobierania ich.

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

W następnej sekcji kodu są wyświetlane niektóre dane goes-18 z otwartego komputera planetarnego. Wybieramy zestaw danych GOES-R Advanced Baseline Imager Level 2 Land Surface Temperature — CONUS oraz dowolny plik z dnia 208 roku 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)

Wizualizacja skali szarości danych rasterów geoprzestrzennych z satelity GOES-18 przedstawiająca wzorce temperatury powierzchni lądowej w całym regionie.

Patrząc na dane i nazwę pliku, możemy już zobaczyć kluczowe elementy metadanych potrzebne do skompilowania elementu STAC. Nazwa pliku zawiera informacje o tym, które satelity przechwyciły dane i kiedy zostały przechwycone.

W przykładzie nazwa pliku to OR_ABI-L2-LSTC-M6_G18_s20232080101177_e20232080103550_c20232080104570_DQF, na podstawie przewodnika po produkcie, oznacza to:

Szczegółowe składniki

(No changes needed) Opis Przeznaczenie
LUB Środowisko systemu operacyjnego Określa środowisko systemowe, w którym zebrano dane
ABI Zaawansowany instrument obrazujący typu Baseline Identyfikuje instrument używany do przechwytywania danych
L2 Produkt poziomu 2 (produkt pochodny) Wskazuje, że dane są produktem pochodnym przetworzonym z pierwotnych obserwacji
LSTC Produkt temperatury powierzchni ziemi (Bezchmurne niebo) Przedstawia określony typ produktu, koncentrując się na temperaturze powierzchni lądowej w warunkach jasnego nieba
M6 Skanowanie w trybie 6 (skanowanie na pełnym dysku) Opisuje tryb skanowania obejmujący pełny dysk Ziemi
G18 Satelita GOES-18 (znany również jako GOES-West) Identyfikuje satelitę, z którego zebrano dane

Szczegóły czasu obserwacji

Początek obserwacji (s2023208020177)-

(No changes needed) Opis Przeznaczenie
Rok 2023 Określa rok obserwacji
Dzień Roku 208 Wskazuje dzień roku rozpoczęcia obserwacji
Czas 02:01:17 UTC Zawiera dokładny czas rozpoczęcia obserwacji w formacie UTC
Dziesiąte części sekundy 7 Dodaje precyzję do czasu rozpoczęcia obserwacji

Koniec obserwacji (e20232080203550)-

(No changes needed) Opis Przeznaczenie
Rok 2023 Określa rok obserwacji
Dzień Roku 208 Wskazuje dzień roku, w których zakończyła się obserwacja
Czas 02:03:55 UTC Zawiera dokładny czas, w jaki obserwacja zakończyła się w formacie UTC
Dziesiąte części sekundy 0 Dodaje precyzję do czasu zakończenia obserwacji

Czas tworzenia pliku (c20232080204563)-

(No changes needed) Opis Przeznaczenie
Rok 2023 Określa rok utworzenia pliku
Dzień Roku 208 Wskazuje dzień roku utworzenia pliku
Czas 02:04:56 UTC Zawiera dokładny czas utworzenia pliku w formacie UTC
Dziesiąte części sekundy 3 Dodaje precyzję do czasu tworzenia pliku

Dodatkowe informacje:

(No changes needed) Opis Przeznaczenie
DQF Flaga jakości danych wskazująca informacje o jakości odpowiednich danych Zawiera informacje o jakości danych
.tif Rozszerzenie pliku Wskazuje format pliku danych

Poniższy kod wyodrębnia te metadane z nazwy pliku przy użyciu wyrażeń regularnych (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'}

Tworzenie elementów STAC na podstawie plików geoTIFF Cloud-Optimized

Poniższy blok kodu używa rio-stac biblioteki do zautomatyzowania tworzenia elementów STAC z Cloud-Optimized GeoTIFFs (COGs).

Po wskazaniu pliku COG, rio-stac automatycznie wyodrębnia i organizuje podstawowe metadane, takie jak granica przestrzenna, informacje o projekcji i właściwości rastra w ustandaryzowany format STAC. Biblioteka obsługuje złożone zadanie odczytywania osadzonych metadanych technicznych z geoTIFF i konwertuje je na pola zgodne ze standardem STAC, w tym:

  • Geometria
  • Ramka ograniczająca (bbox)
  • Szczegóły projekcji
  • Cechy rasterowe
  • Rozszerzenia STAC

Ta automatyzacja znacznie zmniejsza ręczną pracę wymaganą do utworzenia prawidłowych elementów STAC i zapewnia spójność metadanych

Uwaga / Notatka

GeoCatalog ma ograniczenia dotyczące znaków, których można używać w identyfikatorach elementów STAC i kluczach zasobów. Upewnij się, że identyfikatory nie zawierają następujących znaków: -, _, +, (, ) i .. Może być konieczne zmodyfikowanie logiki generowania w item_id celu zastąpienia lub usunięcia tych znaków z nazw plików.

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": []
        }
      }
    }

Kod JSON elementu STAC z rio-stac

Biblioteka rio-stac odczytuje plik GOES COG i automatycznie wyodrębnia kluczowe metadane.

Ponadto, na podstawie typu uwzględnionych metadanych, rio-stac dodało odpowiednie rozszerzenia STAC. Rozszerzenia STAC rozszerzają podstawową specyfikację przez dodanie ustandaryzowanych metadanych specyficznych dla domeny.

Poniższe tabele zawierają wyjaśnienie wszystkich znalezionych metadanych rio-stac.

Podstawowe pola

(No changes needed) Opis Przeznaczenie
typ Zawsze "funkcja" Identyfikuje typ jako funkcję GeoJSON
stac_version 1.0.0 Określa wersję standardową STAC
id Unikatowy identyfikator Zawiera informacje dotyczące satelity, produktu i czasu
stac_extensions Lista adresów URL schematu Definiuje dodatkowe pola metadanych

Informacje przestrzenne

(No changes needed) Opis Przeznaczenie
geometria Wielokąt GeoJSON Definiuje ślad danych we współrzędnych WGS84
bbox Współrzędne ramki ograniczającej Zapewnia prosty zakres przestrzenny na potrzeby szybkiego filtrowania
proj:geometry Wielokąt specyficzny dla projekcji Ślad we współrzędnych projekcji natywnej
proj:bbox Granice projekcji natywnej Zakres przestrzenny w układzie współrzędnych satelity
proj:shape [1500, 2500] Wymiary obrazu w pikselach
proj:transform Przekształcenie afiniczne Mapuje piksel na przestrzeń współrzędnych
proj:wkt2 Well-Known Text Kompletna definicja projekcji
proj:epsg null Nie istnieje standardowy kod EPSG dla tej projekcji mapy

Informacje czasowe

(No changes needed) Opis Przeznaczenie
data/godzina Sygnatura czasowa tworzenia Gdy ten element STAC został utworzony

Informacje o rasterze

(No changes needed) Opis Przeznaczenie
raster:bands Tablica obiektów pasmowych Opisuje właściwości danych rastrowych
→ typ_danych uint16 Typ danych pikseli
rozdzielczość przestrzenna 2004,02 m Odległość próbki ziemi
skalowanie/przesunięcie → Przeliczniki Przekształca wartości pikseli w jednostki fizyczne (Kelvin)
→ brak danych 65535.0 Wartość reprezentująca brak danych
→ statystyk Podsumowanie statystyczne Udostępnia informacje o dystrybucji danych
histogram → Rozkład wartości Wizualizowanie dystrybucji danych

Informacje o zasobach

(No changes needed) Opis Przeznaczenie
Dane.zasobów Główny zasób danych Wskazuje rzeczywisty plik danych
→ href adres URL Lokalizacja GeoTIFF Cloud-Optimized
typ → Typ nośnika Identyfikuje format pliku

Metadane pliku

(No changes needed) Opis Przeznaczenie
rozmiar pliku 943 250 bajtów Rozmiar pliku danych

Dodawanie metadanych z nazwy pliku

Następnie dodamy dane znalezione w nazwie pliku, aby zakończyć wypełnianie metadanych dla tego elementu STAC.

Należy pamiętać, że wszystkie daty i czas w elementach STAC muszą być zgodne z normą ISO 8601. Biblioteka PySTAC ma funkcję datetime_to_str, która zapewnia poprawne formatowanie danych.

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

Element 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": []
        }
      }
    }

Dodawanie elementu STAC do kolekcji

Program MC Pro wymaga, aby wszystkie elementy STAC miały odwołanie do ID nadrzędnej kolekcji STAC, do której są włączane. W tym samouczku identyfikator kolekcji STAC oznacza nazwę satelity oraz produktu danych.

Dzięki funkcji PySTAC można łatwo użyć niektórych metadanych zebranych z plików źródłowych w celu wypełnienia pól kluczy dla kolekcji STAC i używania wbudowanych funkcji weryfikacji.

Poniższy kod tworzy nadrzędną kolekcję STAC do gromadzenia danych GOES. Następnie kod zapisuje te informacje w plikach, które są używane do tworzenia kolekcji Microsoft Planetary Computer Pro STAC oraz do pozyskiwania elementów STAC w ramach 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

Dalsze kroki

Teraz, po utworzeniu niektórych obiektów STAC, nadszedł czas na wczytanie danych do Microsoft Planetary Computer Pro.

W przypadku przyjmowania pojedynczego przedmiotu:

Dla zbiorczego wprowadzania:

Oferujemy również narzędzie STAC Forge , które zapewnia zwiększoną automatyzację przy użyciu szablonów dotyczących danych.