|
| 1 | +import json |
| 2 | +from datetime import datetime |
| 3 | +from typing import Any |
| 4 | + |
| 5 | +from pystac import Collection, Item, Link |
| 6 | +from shapely.geometry import Point, mapping |
| 7 | + |
| 8 | +from pystac_monty.collections.glide_events import glide_event_collection |
| 9 | +from pystac_monty.extension import MontyExtension |
| 10 | +from pystac_monty.sources.common import MontyDataSource |
| 11 | + |
| 12 | + |
| 13 | +class GlideDataSource(MontyDataSource): |
| 14 | + def __init__(self, source_url: str, data: Any): |
| 15 | + super().__init__(source_url, data) |
| 16 | + self.data = json.loads(data) |
| 17 | + |
| 18 | + |
| 19 | +class GlideTransformer: |
| 20 | + """ |
| 21 | + Transforms Glide event data into STAC Items |
| 22 | + """ |
| 23 | + |
| 24 | + def __init__(self, data: list[GlideDataSource]) -> None: |
| 25 | + self.data = data |
| 26 | + |
| 27 | + def make_items(self) -> list[Item]: |
| 28 | + items = [] |
| 29 | + |
| 30 | + # validate data for glide transformation |
| 31 | + glide_events = self.validate_glide_data() |
| 32 | + |
| 33 | + for obj in glide_events: |
| 34 | + glide_data = obj.data.get("glideset") |
| 35 | + if not glide_data == []: |
| 36 | + for data in glide_data: |
| 37 | + glide_id = data.get("event") + "-" + data.get("number") + "-" + data.get("geocode") |
| 38 | + latitude = float(data.get("latitude")) |
| 39 | + longitude = float(data.get("longitude")) |
| 40 | + event_date = {"year": data.get("year"), "month": data.get("month"), "day": data.get("day")} |
| 41 | + |
| 42 | + point = Point(longitude, latitude) |
| 43 | + geometry = mapping(point) |
| 44 | + bbox = [longitude, latitude, longitude, latitude] |
| 45 | + |
| 46 | + item = Item( |
| 47 | + id=glide_id, |
| 48 | + geometry=geometry, |
| 49 | + bbox=bbox, |
| 50 | + datetime=self.make_date(event_date), |
| 51 | + properties={ |
| 52 | + "title": data.get("title", ""), |
| 53 | + "description": data.get("comments", ""), |
| 54 | + "magnitude": data.get("magnitude", ""), |
| 55 | + "location": data.get("location", ""), |
| 56 | + "source": data.get("source", ""), |
| 57 | + "docid": data.get("docid", ""), |
| 58 | + "status": data.get("status", ""), |
| 59 | + }, |
| 60 | + ) |
| 61 | + |
| 62 | + item.set_collection(self.get_collection()) |
| 63 | + |
| 64 | + MontyExtension.add_to(item) |
| 65 | + monty = MontyExtension.ext(item) |
| 66 | + monty.hazard_codes = data.get("event") |
| 67 | + monty.country_codes = data.get("geocode") |
| 68 | + |
| 69 | + item.add_link(Link("via", obj.get_source_url(), "application/json", "Glide Event Data")) |
| 70 | + |
| 71 | + items.append(item) |
| 72 | + |
| 73 | + return items |
| 74 | + |
| 75 | + def make_date(self, data: dict): |
| 76 | + year = data["year"] |
| 77 | + month = data["month"] |
| 78 | + day = data["day"] |
| 79 | + |
| 80 | + dt = datetime(year, month, day) |
| 81 | + formatted_date = dt.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z" |
| 82 | + |
| 83 | + date = datetime.fromisoformat(formatted_date.replace("Z", "+00:00")) |
| 84 | + return date |
| 85 | + |
| 86 | + def get_collection(self) -> Collection: |
| 87 | + data = glide_event_collection |
| 88 | + return Collection.from_dict(data) |
| 89 | + |
| 90 | + def validate_glide_data(self) -> list[GlideDataSource]: |
| 91 | + glide_data_list = [] |
| 92 | + for index, obj in enumerate(self.data): |
| 93 | + glideset = obj.get_data()["glideset"] |
| 94 | + if glideset == []: |
| 95 | + raise ValueError(f"No Glide data found in object at index {index}") |
| 96 | + for obj in glideset: |
| 97 | + required_fields = ["latitude", "longitude", "event", "number", "geocode"] |
| 98 | + missing_fields = [field for field in required_fields if field not in obj] |
| 99 | + |
| 100 | + if missing_fields: |
| 101 | + raise ValueError(f"Missing required fields {missing_fields} in object at index {index}") |
| 102 | + return glide_data_list |
0 commit comments