chore: add weather pipeline example

This commit is contained in:
2026-07-07 14:31:04 +02:00
parent 5311307a6f
commit 83eecd612e
3 changed files with 177 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
predicate in_range(min: float, max: float)(v: float) = min <= v & v <= max
predicate is_percentage = in_range(0.0, 100.0)
type Celsius = float
type Kelvin = float where _ >= 0
type Hectopascal = float
type Temperature = Celsius where in_range(-30.0, 100.0)
type Pressure = Hectopascal where in_range(800.0, 1100.0)(_)
type Humidity = float where is_percentage(_)
type HeatIndex = float
type StationID = str where len(_) == 3 & _.isupper()
type Mean[T <: float] = float
extend Celsius {
def __add__: fn(Celsius, /) -> Celsius
def __sub__: fn(Celsius, /) -> Celsius
}
extend Kelvin {
def __add__: fn(Kelvin, /) -> Kelvin
}
extend Hectopascal {
def __add__: fn(Hectopascal, /) -> Hectopascal
def __sub__: fn(Hectopascal, /) -> Hectopascal
}
alias RawData = Frame[
station_id: str,
timestamp: str,
temperature: float,
pressure: float,
humidity: float,
]
alias Data = Frame[
station_id: StationID,
timestamp: object,
temperature: Temperature,
pressure: Pressure,
humidity: Humidity,
]
alias DataWithHI = Frame[
station_id: StationID,
timestamp: object,
temperature: Temperature,
pressure: Pressure,
humidity: Humidity,
heat_index: HeatIndex,
]
alias DailyAverages = Frame[
timestamp: object,
temperature: Mean[Temperature],
pressure: Mean[Pressure],
humidity: Mean[Humidity],
heat_index: Mean[HeatIndex],
]
predicate limit_amplitude(max_amp: float)(ls: list[float]) = max(ls) - min(ls) <= max_amp
type LowAmplitudeWave = list[float where _ >= 1] where limit_amplitude(10)(_)

View File

@@ -0,0 +1,43 @@
import datetime
import random
import pandas as pd
stations = ["SIO", "AIG", "ZER"]
start_ts = datetime.datetime(2026, 1, 1)
end_ts = datetime.datetime(2027, 1, 1)
delta = end_ts - start_ts
min_temp, max_temp = -30.0, 100.0
min_pres, max_pres = 800.0, 1100.0
min_hum, max_hum = 0.0, 1.0
N = 3000
rows: list[tuple[str, datetime.datetime, float, float, float]] = []
for _ in range(N):
ts = random.random() * delta + start_ts
rows.append(
(
random.choice(stations),
ts,
random.random() * (max_temp - min_temp) + min_temp,
random.random() * (max_pres - min_pres) + min_pres,
random.random() * (max_hum - min_hum) + min_hum,
)
)
df = pd.DataFrame(
rows,
columns=[
"station_id",
"timestamp",
"temperature",
"pressure",
"humidity",
],
)
df = df.sort_values(by=["timestamp", "station_id"])
df.to_csv("data.csv", index=False)

View File

@@ -0,0 +1,69 @@
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
from custom_types import DailyAverages, Data, DataWithHI, HeatIndex, RawData
from midas.typing import Column, cast, unsafe_cast
def load_data(path: Path) -> RawData:
return cast(RawData, pd.read_csv(path))
def convert_data(raw_df: RawData) -> Data:
new_df = raw_df.copy()
new_df["timestamp"] = cast(
Column[object],
pd.to_datetime(new_df["timestamp"]),
)
return cast(Data, new_df)
def compute_heat_index(df: Data):
df["heat_index"] = cast(
Column[HeatIndex],
(
df["temperature"] * 2.0
+ df["humidity"] * 10.0
- df["temperature"] * df["humidity"] * 0.2
),
)
return df
def daily_avg(df: DataWithHI):
return cast(
DailyAverages,
df.groupby(
by=[
df["station_id"],
df["timestamp"].dt.day.rename("day"),
],
)
.mean()
.sort_values(by="timestamp"),
)
def plot(df: DailyAverages):
stations = unsafe_cast(list[str], list(df.index.get_level_values(0).unique()))
for station in stations:
sub_df = unsafe_cast(DailyAverages, df.loc[station])
# plt.plot(sub_df["timestamp"], sub_df["temperature"])
plt.plot(sub_df["timestamp"], sub_df["heat_index"])
plt.show()
def main():
raw_df: RawData = load_data(Path("data.csv"))
df: Data = convert_data(raw_df)
with_hi = compute_heat_index(df)
dailies = daily_avg(with_hi)
print(dailies)
plot(dailies)
if __name__ == "__main__":
main()