ksmesopy 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ksmesopy-0.1.0/PKG-INFO +242 -0
- ksmesopy-0.1.0/README.md +227 -0
- ksmesopy-0.1.0/ksmesopy/__init__.py +98 -0
- ksmesopy-0.1.0/ksmesopy/charts.py +637 -0
- ksmesopy-0.1.0/ksmesopy/core.py +861 -0
- ksmesopy-0.1.0/ksmesopy/utils.py +200 -0
- ksmesopy-0.1.0/ksmesopy.egg-info/PKG-INFO +242 -0
- ksmesopy-0.1.0/ksmesopy.egg-info/SOURCES.txt +11 -0
- ksmesopy-0.1.0/ksmesopy.egg-info/dependency_links.txt +1 -0
- ksmesopy-0.1.0/ksmesopy.egg-info/requires.txt +6 -0
- ksmesopy-0.1.0/ksmesopy.egg-info/top_level.txt +1 -0
- ksmesopy-0.1.0/pyproject.toml +27 -0
- ksmesopy-0.1.0/setup.cfg +4 -0
ksmesopy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ksmesopy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python API for the Kansas Mesonet
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://mesonet.k-state.edu
|
|
7
|
+
Project-URL: Repository, https://github.com/<your-username>/ksmesopy
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: numpy>=1.24
|
|
11
|
+
Requires-Dist: pandas>=2.0
|
|
12
|
+
Requires-Dist: matplotlib>=3.7
|
|
13
|
+
Provides-Extra: app
|
|
14
|
+
Requires-Dist: guile; extra == "app"
|
|
15
|
+
|
|
16
|
+
# ksmesopy
|
|
17
|
+
|
|
18
|
+
Python package for downloading and processing data from the [Kansas Mesonet](https://mesonet.k-state.edu), an environmental monitoring network operated by Kansas State University.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install git+https://github.com/<your-username>/ksmesopy.git
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Dependencies: `numpy`, `pandas`, `matplotlib`. The desktop app additionally requires `guile`.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import ksmesopy as ms
|
|
32
|
+
|
|
33
|
+
# Download daily temperature and precipitation for one station
|
|
34
|
+
df = ms.request_data(
|
|
35
|
+
station="Manhattan",
|
|
36
|
+
start="2024-01-01",
|
|
37
|
+
end="2024-12-31",
|
|
38
|
+
interval="day",
|
|
39
|
+
variables=["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX", "PRECIP"],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Optional: rename columns to snake_case
|
|
43
|
+
df = ms.rename_columns(df)
|
|
44
|
+
# TIMESTAMP → timestamp, TEMP2MAVG → t2m, PRECIP → precip, …
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Desktop app
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python ksmesoapp.py
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A GUI for selecting stations, date ranges, variables, and intervals, with a tabular view and time-series chart. Exports to CSV and PNG.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## API reference
|
|
58
|
+
|
|
59
|
+
### Stations
|
|
60
|
+
|
|
61
|
+
| Function | Returns | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `get_stations()` | `DataFrame` | Full station metadata table |
|
|
64
|
+
| `get_stations(names_only=True)` | `list[str]` | Sorted list of station names only |
|
|
65
|
+
| `get_stations_active()` | `DataFrame` | Availability table: `STATION`, `OBS_INTERVAL` (s), `START`, `END` |
|
|
66
|
+
|
|
67
|
+
### Data retrieval
|
|
68
|
+
|
|
69
|
+
| Function | Returns | Description |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `request_data(station, start, end, interval, variables, *, verbose, sleep)` | `DataFrame` | Download data for one station. `interval` is `"day"`, `"hour"`, or `"5min"`. Daily timestamps are corrected from the Mesonet's next-day convention. |
|
|
72
|
+
| `request_data_multi(stations, start, end, interval, variables, *, verbose, sleep)` | `dict[str, DataFrame]` | Same as above for a list of stations; returns one DataFrame per station. |
|
|
73
|
+
| `list_variables(interval=None)` | `list[dict]` | Variable catalogue filtered by interval, or all variables if `None`. Each entry has keys `api_name`, `snake_name`, `description`, `intervals`. |
|
|
74
|
+
| `rename_columns(df, preset="snake")` | `DataFrame` | Rename API column names to snake_case (e.g. `TEMP2MAVG` → `t2m`). Pass a `dict` for a custom mapping. |
|
|
75
|
+
|
|
76
|
+
### Soil processing
|
|
77
|
+
|
|
78
|
+
| Function | Returns | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `calibrate_vwc(df, vwc_cols=None)` | `DataFrame` | Replace firmware VWC values with the KSU site-specific calibration. Fetch `SOILKA*CM` and `SOILEC*CM` alongside `VWC*CM` in the same `request_data` call. Works on any subset of depths. |
|
|
81
|
+
| `compute_soil_water_storage(df)` | `DataFrame` | Trapezoidal soil water storage in the top 50 cm (mm). Requires all four VWC depths; adds a `STORAGE_MM` column. Call `calibrate_vwc()` first for calibrated storage. |
|
|
82
|
+
|
|
83
|
+
### Derived variables
|
|
84
|
+
|
|
85
|
+
| Function | Returns | Description |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `growing_degree_days(tmin, tmax, base=10.0, ceiling=30.0)` | `ndarray` | Daily GDD. Both tmin/tmax clipped to `[base, ceiling]` before averaging. |
|
|
88
|
+
| `heat_index(temp, rh)` | `ndarray` | NOAA/NWS apparent temperature (°C). |
|
|
89
|
+
| `wind_chill(temp, wspd)` | `ndarray` | NWS wind chill (°C); valid for temp ≤ 10 °C, wind ≥ 1.3 m s⁻¹. |
|
|
90
|
+
| `temperature_humidity_index(temp, rh)` | `ndarray` | THI for livestock heat stress. Thresholds (dairy): <68 none · 68–72 mild · 72–80 moderate · 80–90 severe · >90 dangerous. |
|
|
91
|
+
|
|
92
|
+
### Reference evapotranspiration
|
|
93
|
+
|
|
94
|
+
| Function | Returns | Description |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `reference_et_penman_monteith(doy, lat, elev, tmin, tmax, srad, wspd, rhmin, rhmax, *, vpd, ea, wind_height)` | `(ETo, Ra)` | FAO-56 Penman-Monteith. Supply vapour pressure via `ea=`, `vpd=`, or `rhmin=`+`rhmax=`. `srad` in W m⁻², converted internally. |
|
|
97
|
+
| `reference_et_hargreaves(doy, lat, tmin, tmax, *, tmean)` | `(ETo, Ra)` | Hargreaves–Samani. Temperature only — no humidity, radiation, or wind needed. |
|
|
98
|
+
|
|
99
|
+
Both return `(ETo [mm day⁻¹], Ra [MJ m⁻² day⁻¹])`.
|
|
100
|
+
|
|
101
|
+
### Atmospheric helpers
|
|
102
|
+
|
|
103
|
+
| Function | Output |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `saturation_vapor_pressure(temp)` | es (kPa) |
|
|
106
|
+
| `actual_vapor_pressure(temp, rh)` | ea (kPa) |
|
|
107
|
+
| `vapor_pressure_deficit(temp, rh)` | VPD (kPa, ≥ 0) |
|
|
108
|
+
| `slope_saturation_vapor_pressure(temp)` | Δ (kPa °C⁻¹) |
|
|
109
|
+
| `atmospheric_pressure(elev)` | P (kPa) |
|
|
110
|
+
| `psychrometric_constant(elev)` | γ (kPa °C⁻¹) |
|
|
111
|
+
| `extraterrestrial_radiation(doy, lat)` | Ra (MJ m⁻² day⁻¹) |
|
|
112
|
+
| `net_radiation(srad_mj, tmin, tmax, ea, elev, doy, lat)` | Rn (MJ m⁻² day⁻¹) |
|
|
113
|
+
| `srad_to_mj(srad, period)` | energy (MJ m⁻²) |
|
|
114
|
+
|
|
115
|
+
All functions accept scalars or NumPy arrays.
|
|
116
|
+
|
|
117
|
+
### Charts
|
|
118
|
+
|
|
119
|
+
Each function draws onto a Matplotlib `Axes` supplied by the caller, so panels compose freely inside any figure layout. All functions accept API column names (`TEMP2MAVG`) or snake_case names (`t2m`) interchangeably, and return the axes they drew on so they can be further customised.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import matplotlib.pyplot as plt
|
|
123
|
+
import ksmesopy as ms
|
|
124
|
+
|
|
125
|
+
fig, axes = plt.subplots(5, 1, sharex=True, figsize=(12, 14))
|
|
126
|
+
|
|
127
|
+
ms.plot_temperature(axes[0], df, ["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX"])
|
|
128
|
+
ms.plot_precip(axes[1], df, "PRECIP")
|
|
129
|
+
ms.plot_humidity(axes[2], df, "RELHUM2MAVG")
|
|
130
|
+
ms.plot_solar_radiation(axes[3], df, ["SRAVG", "Ra"]) # Ra drawn dashed
|
|
131
|
+
ms.plot_vwc(axes[4], df) # auto-detects VWC columns
|
|
132
|
+
|
|
133
|
+
plt.tight_layout()
|
|
134
|
+
plt.savefig("meteogram.png", dpi=150)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
plt.tight_layout()
|
|
138
|
+
plt.savefig("meteogram.png", dpi=150)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
All functions accept API column names (`TEMP2MAVG`) or snake_case names (`t2m`) interchangeably, and return the axes they drew on so they can be further customised.
|
|
142
|
+
|
|
143
|
+
| Function | Key behaviour |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `plot_temperature(ax, df, variables, *, band, ylabel, legend)` | Shaded band when min/avg/max triplet detected (`band=True`); plain lines otherwise. Works for air and soil temperature. |
|
|
146
|
+
| `plot_precip(ax, df, variable, *, ylabel, color)` | Bar chart, bar width inferred from timestamp spacing. |
|
|
147
|
+
| `plot_humidity(ax, df, variables, *, ylabel, legend)` | Lines, y-axis fixed 0–100 %. |
|
|
148
|
+
| `plot_vpd(ax, df, variables, *, ylabel, legend)` | Filled area + line, y-axis starts at 0. |
|
|
149
|
+
| `plot_solar_radiation(ax, df, variables, *, ylabel, legend)` | Filled area for observed; dashed line for Ra columns (detected by name). |
|
|
150
|
+
| `plot_wind(ax, df, speed, direction, *, ylabel, legend)` | Speed as line; direction overlaid as scatter on a twin y-axis with N/E/S/W ticks. |
|
|
151
|
+
| `plot_vwc(ax, df, variables, *, ylabel, legend)` | Sequential colormap shallow→deep; auto-detects VWC columns if `variables=None`. |
|
|
152
|
+
| `plot_et(ax, df, variables, *, bar, ylabel, legend)` | Line by default; `bar=True` for daily totals. |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Variable catalogue
|
|
157
|
+
|
|
158
|
+
Intervals: **D** = daily only · **H** = hourly and daily · **A** = 5-min, hourly, and daily
|
|
159
|
+
|
|
160
|
+
### Atmospheric
|
|
161
|
+
|
|
162
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
163
|
+
|---|---|---|---|---|
|
|
164
|
+
| `TEMP2MAVG` | `t2m` | Air temperature 2 m avg | °C | A |
|
|
165
|
+
| `TEMP2MMIN` | `t2m_min` | Air temperature 2 m min | °C | D |
|
|
166
|
+
| `TEMP2MMAX` | `t2m_max` | Air temperature 2 m max | °C | D |
|
|
167
|
+
| `TEMP10MAVG` | `t10m` | Air temperature 10 m avg | °C | A |
|
|
168
|
+
| `TEMP10MMIN` | `t10m_min` | Air temperature 10 m min | °C | D |
|
|
169
|
+
| `TEMP10MMAX` | `t10m_max` | Air temperature 10 m max | °C | D |
|
|
170
|
+
| `RELHUM2MAVG` | `rh` | Relative humidity 2 m avg | % | A |
|
|
171
|
+
| `RELHUM2MMIN` | `rh_min` | Relative humidity 2 m min | % | D |
|
|
172
|
+
| `RELHUM2MMAX` | `rh_max` | Relative humidity 2 m max | % | D |
|
|
173
|
+
| `VPDEFAVG` | `vpd` | Vapor pressure deficit avg | kPa | A |
|
|
174
|
+
| `PRESSUREAVG` | `pres` | Atmospheric pressure avg | kPa | A |
|
|
175
|
+
| `PRECIP` | `precip` | Precipitation gauge 1 | mm | A |
|
|
176
|
+
| `PRECIP2` | `precip2` | Precipitation gauge 2 | mm | A |
|
|
177
|
+
| `SRAVG` | `srad` | Solar radiation avg | W m⁻² | A |
|
|
178
|
+
| `WSPD2MAVG` | `wspd` | Wind speed 2 m avg | m s⁻¹ | A |
|
|
179
|
+
| `WSPD2MMAX` | `wspd_max` | Wind speed 2 m max | m s⁻¹ | H¹ |
|
|
180
|
+
| `WDIR2M` | `wdir` | Wind direction 2 m | ° | A |
|
|
181
|
+
| `WDIR2MSTD` | `wdir_std` | Wind direction 2 m std dev | ° | A |
|
|
182
|
+
| `WSPD10MAVG` | `wspd10m` | Wind speed 10 m avg | m s⁻¹ | A |
|
|
183
|
+
| `WSPD10MMAX` | `wspd10m_max` | Wind speed 10 m max | m s⁻¹ | H¹ |
|
|
184
|
+
| `WDIR10M` | `wdir10m` | Wind direction 10 m | ° | A |
|
|
185
|
+
| `WDIR10MSTD` | `wdir10m_std` | Wind direction 10 m std dev | ° | A |
|
|
186
|
+
|
|
187
|
+
¹ Available at 5-min and daily only (not hourly).
|
|
188
|
+
|
|
189
|
+
### Soil temperature — dedicated probes
|
|
190
|
+
|
|
191
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
192
|
+
|---|---|---|---|---|
|
|
193
|
+
| `SOILTMP5AVG` | `tsoil_5cm` | Soil temperature 5 cm avg | °C | A |
|
|
194
|
+
| `SOILTMP5MIN` | `tsoil_5cm_min` | Soil temperature 5 cm min | °C | D |
|
|
195
|
+
| `SOILTMP5MAX` | `tsoil_5cm_max` | Soil temperature 5 cm max | °C | D |
|
|
196
|
+
| `SOILTMP10AVG` | `tsoil_10cm` | Soil temperature 10 cm avg | °C | A |
|
|
197
|
+
| `SOILTMP10MIN` | `tsoil_10cm_min` | Soil temperature 10 cm min | °C | D |
|
|
198
|
+
| `SOILTMP10MAX` | `tsoil_10cm_max` | Soil temperature 10 cm max | °C | D |
|
|
199
|
+
|
|
200
|
+
### Soil — CS655 sensors
|
|
201
|
+
|
|
202
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
203
|
+
|---|---|---|---|---|
|
|
204
|
+
| `SOILTMP5AVG655` | `tsoil_5cm_655` | Soil temperature 5 cm | °C | A |
|
|
205
|
+
| `SOILTMP10AVG655` | `tsoil_10cm_655` | Soil temperature 10 cm | °C | A |
|
|
206
|
+
| `SOILTMP20AVG655` | `tsoil_20cm_655` | Soil temperature 20 cm | °C | A |
|
|
207
|
+
| `SOILTMP50AVG655` | `tsoil_50cm_655` | Soil temperature 50 cm | °C | A |
|
|
208
|
+
| `SOILKA5CM` | `ka_5cm` | Dielectric constant 5 cm | — | A |
|
|
209
|
+
| `SOILKA10CM` | `ka_10cm` | Dielectric constant 10 cm | — | A |
|
|
210
|
+
| `SOILKA20CM` | `ka_20cm` | Dielectric constant 20 cm | — | A |
|
|
211
|
+
| `SOILKA50CM` | `ka_50cm` | Dielectric constant 50 cm | — | A |
|
|
212
|
+
| `SOILEC5CM` | `ec_5cm` | Electrical conductivity 5 cm | dS m⁻¹ | A |
|
|
213
|
+
| `SOILEC10CM` | `ec_10cm` | Electrical conductivity 10 cm | dS m⁻¹ | A |
|
|
214
|
+
| `SOILEC20CM` | `ec_20cm` | Electrical conductivity 20 cm | dS m⁻¹ | A |
|
|
215
|
+
| `SOILEC50CM` | `ec_50cm` | Electrical conductivity 50 cm | dS m⁻¹ | A |
|
|
216
|
+
| `VWC5CM` | `vwc_5cm` | Volumetric water content 5 cm | m³ m⁻³ | A |
|
|
217
|
+
| `VWC10CM` | `vwc_10cm` | Volumetric water content 10 cm | m³ m⁻³ | A |
|
|
218
|
+
| `VWC20CM` | `vwc_20cm` | Volumetric water content 20 cm | m³ m⁻³ | A |
|
|
219
|
+
| `VWC50CM` | `vwc_50cm` | Volumetric water content 50 cm | m³ m⁻³ | A |
|
|
220
|
+
|
|
221
|
+
> **VWC note:** the Mesonet API returns VWC computed by the CS655 firmware equation. Requesting any `VWC*CM` column will print a warning reminding you that a site-specific calibration is available. To apply it, fetch the corresponding `SOILKA*CM` and `SOILEC*CM` columns in the same `request_data` call and then pass the DataFrame to `calibrate_vwc()`. Works for any subset of depths independently.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Notes
|
|
226
|
+
|
|
227
|
+
**Precipitation.** The Mesonet operates dual tipping-bucket rain gauges at most stations. `request_data()` returns both (`PRECIP`, `PRECIP2`); the desktop app merges them to the row-wise maximum automatically. For scripted use, merge manually:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
df["PRECIP"] = df[["PRECIP", "PRECIP2"]].max(axis=1)
|
|
231
|
+
df.drop(columns="PRECIP2", inplace=True)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Daily timestamps.** The Mesonet API stores each day's aggregated values at 00:00 of the following calendar day. `request_data()` corrects for this automatically; the returned `TIMESTAMP` always reflects the observation date.
|
|
235
|
+
|
|
236
|
+
**Missing values.** The API encodes missing observations as `"M"`. These are converted to `NaN` on read. Periods before a station or sensor was installed are pre-filled with `NaN` rather than omitted.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT
|
ksmesopy-0.1.0/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# ksmesopy
|
|
2
|
+
|
|
3
|
+
Python package for downloading and processing data from the [Kansas Mesonet](https://mesonet.k-state.edu), an environmental monitoring network operated by Kansas State University.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install git+https://github.com/<your-username>/ksmesopy.git
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Dependencies: `numpy`, `pandas`, `matplotlib`. The desktop app additionally requires `guile`.
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import ksmesopy as ms
|
|
17
|
+
|
|
18
|
+
# Download daily temperature and precipitation for one station
|
|
19
|
+
df = ms.request_data(
|
|
20
|
+
station="Manhattan",
|
|
21
|
+
start="2024-01-01",
|
|
22
|
+
end="2024-12-31",
|
|
23
|
+
interval="day",
|
|
24
|
+
variables=["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX", "PRECIP"],
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Optional: rename columns to snake_case
|
|
28
|
+
df = ms.rename_columns(df)
|
|
29
|
+
# TIMESTAMP → timestamp, TEMP2MAVG → t2m, PRECIP → precip, …
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Desktop app
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python ksmesoapp.py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A GUI for selecting stations, date ranges, variables, and intervals, with a tabular view and time-series chart. Exports to CSV and PNG.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## API reference
|
|
43
|
+
|
|
44
|
+
### Stations
|
|
45
|
+
|
|
46
|
+
| Function | Returns | Description |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `get_stations()` | `DataFrame` | Full station metadata table |
|
|
49
|
+
| `get_stations(names_only=True)` | `list[str]` | Sorted list of station names only |
|
|
50
|
+
| `get_stations_active()` | `DataFrame` | Availability table: `STATION`, `OBS_INTERVAL` (s), `START`, `END` |
|
|
51
|
+
|
|
52
|
+
### Data retrieval
|
|
53
|
+
|
|
54
|
+
| Function | Returns | Description |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `request_data(station, start, end, interval, variables, *, verbose, sleep)` | `DataFrame` | Download data for one station. `interval` is `"day"`, `"hour"`, or `"5min"`. Daily timestamps are corrected from the Mesonet's next-day convention. |
|
|
57
|
+
| `request_data_multi(stations, start, end, interval, variables, *, verbose, sleep)` | `dict[str, DataFrame]` | Same as above for a list of stations; returns one DataFrame per station. |
|
|
58
|
+
| `list_variables(interval=None)` | `list[dict]` | Variable catalogue filtered by interval, or all variables if `None`. Each entry has keys `api_name`, `snake_name`, `description`, `intervals`. |
|
|
59
|
+
| `rename_columns(df, preset="snake")` | `DataFrame` | Rename API column names to snake_case (e.g. `TEMP2MAVG` → `t2m`). Pass a `dict` for a custom mapping. |
|
|
60
|
+
|
|
61
|
+
### Soil processing
|
|
62
|
+
|
|
63
|
+
| Function | Returns | Description |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `calibrate_vwc(df, vwc_cols=None)` | `DataFrame` | Replace firmware VWC values with the KSU site-specific calibration. Fetch `SOILKA*CM` and `SOILEC*CM` alongside `VWC*CM` in the same `request_data` call. Works on any subset of depths. |
|
|
66
|
+
| `compute_soil_water_storage(df)` | `DataFrame` | Trapezoidal soil water storage in the top 50 cm (mm). Requires all four VWC depths; adds a `STORAGE_MM` column. Call `calibrate_vwc()` first for calibrated storage. |
|
|
67
|
+
|
|
68
|
+
### Derived variables
|
|
69
|
+
|
|
70
|
+
| Function | Returns | Description |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `growing_degree_days(tmin, tmax, base=10.0, ceiling=30.0)` | `ndarray` | Daily GDD. Both tmin/tmax clipped to `[base, ceiling]` before averaging. |
|
|
73
|
+
| `heat_index(temp, rh)` | `ndarray` | NOAA/NWS apparent temperature (°C). |
|
|
74
|
+
| `wind_chill(temp, wspd)` | `ndarray` | NWS wind chill (°C); valid for temp ≤ 10 °C, wind ≥ 1.3 m s⁻¹. |
|
|
75
|
+
| `temperature_humidity_index(temp, rh)` | `ndarray` | THI for livestock heat stress. Thresholds (dairy): <68 none · 68–72 mild · 72–80 moderate · 80–90 severe · >90 dangerous. |
|
|
76
|
+
|
|
77
|
+
### Reference evapotranspiration
|
|
78
|
+
|
|
79
|
+
| Function | Returns | Description |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `reference_et_penman_monteith(doy, lat, elev, tmin, tmax, srad, wspd, rhmin, rhmax, *, vpd, ea, wind_height)` | `(ETo, Ra)` | FAO-56 Penman-Monteith. Supply vapour pressure via `ea=`, `vpd=`, or `rhmin=`+`rhmax=`. `srad` in W m⁻², converted internally. |
|
|
82
|
+
| `reference_et_hargreaves(doy, lat, tmin, tmax, *, tmean)` | `(ETo, Ra)` | Hargreaves–Samani. Temperature only — no humidity, radiation, or wind needed. |
|
|
83
|
+
|
|
84
|
+
Both return `(ETo [mm day⁻¹], Ra [MJ m⁻² day⁻¹])`.
|
|
85
|
+
|
|
86
|
+
### Atmospheric helpers
|
|
87
|
+
|
|
88
|
+
| Function | Output |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `saturation_vapor_pressure(temp)` | es (kPa) |
|
|
91
|
+
| `actual_vapor_pressure(temp, rh)` | ea (kPa) |
|
|
92
|
+
| `vapor_pressure_deficit(temp, rh)` | VPD (kPa, ≥ 0) |
|
|
93
|
+
| `slope_saturation_vapor_pressure(temp)` | Δ (kPa °C⁻¹) |
|
|
94
|
+
| `atmospheric_pressure(elev)` | P (kPa) |
|
|
95
|
+
| `psychrometric_constant(elev)` | γ (kPa °C⁻¹) |
|
|
96
|
+
| `extraterrestrial_radiation(doy, lat)` | Ra (MJ m⁻² day⁻¹) |
|
|
97
|
+
| `net_radiation(srad_mj, tmin, tmax, ea, elev, doy, lat)` | Rn (MJ m⁻² day⁻¹) |
|
|
98
|
+
| `srad_to_mj(srad, period)` | energy (MJ m⁻²) |
|
|
99
|
+
|
|
100
|
+
All functions accept scalars or NumPy arrays.
|
|
101
|
+
|
|
102
|
+
### Charts
|
|
103
|
+
|
|
104
|
+
Each function draws onto a Matplotlib `Axes` supplied by the caller, so panels compose freely inside any figure layout. All functions accept API column names (`TEMP2MAVG`) or snake_case names (`t2m`) interchangeably, and return the axes they drew on so they can be further customised.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import matplotlib.pyplot as plt
|
|
108
|
+
import ksmesopy as ms
|
|
109
|
+
|
|
110
|
+
fig, axes = plt.subplots(5, 1, sharex=True, figsize=(12, 14))
|
|
111
|
+
|
|
112
|
+
ms.plot_temperature(axes[0], df, ["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX"])
|
|
113
|
+
ms.plot_precip(axes[1], df, "PRECIP")
|
|
114
|
+
ms.plot_humidity(axes[2], df, "RELHUM2MAVG")
|
|
115
|
+
ms.plot_solar_radiation(axes[3], df, ["SRAVG", "Ra"]) # Ra drawn dashed
|
|
116
|
+
ms.plot_vwc(axes[4], df) # auto-detects VWC columns
|
|
117
|
+
|
|
118
|
+
plt.tight_layout()
|
|
119
|
+
plt.savefig("meteogram.png", dpi=150)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
plt.tight_layout()
|
|
123
|
+
plt.savefig("meteogram.png", dpi=150)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
All functions accept API column names (`TEMP2MAVG`) or snake_case names (`t2m`) interchangeably, and return the axes they drew on so they can be further customised.
|
|
127
|
+
|
|
128
|
+
| Function | Key behaviour |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `plot_temperature(ax, df, variables, *, band, ylabel, legend)` | Shaded band when min/avg/max triplet detected (`band=True`); plain lines otherwise. Works for air and soil temperature. |
|
|
131
|
+
| `plot_precip(ax, df, variable, *, ylabel, color)` | Bar chart, bar width inferred from timestamp spacing. |
|
|
132
|
+
| `plot_humidity(ax, df, variables, *, ylabel, legend)` | Lines, y-axis fixed 0–100 %. |
|
|
133
|
+
| `plot_vpd(ax, df, variables, *, ylabel, legend)` | Filled area + line, y-axis starts at 0. |
|
|
134
|
+
| `plot_solar_radiation(ax, df, variables, *, ylabel, legend)` | Filled area for observed; dashed line for Ra columns (detected by name). |
|
|
135
|
+
| `plot_wind(ax, df, speed, direction, *, ylabel, legend)` | Speed as line; direction overlaid as scatter on a twin y-axis with N/E/S/W ticks. |
|
|
136
|
+
| `plot_vwc(ax, df, variables, *, ylabel, legend)` | Sequential colormap shallow→deep; auto-detects VWC columns if `variables=None`. |
|
|
137
|
+
| `plot_et(ax, df, variables, *, bar, ylabel, legend)` | Line by default; `bar=True` for daily totals. |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Variable catalogue
|
|
142
|
+
|
|
143
|
+
Intervals: **D** = daily only · **H** = hourly and daily · **A** = 5-min, hourly, and daily
|
|
144
|
+
|
|
145
|
+
### Atmospheric
|
|
146
|
+
|
|
147
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
148
|
+
|---|---|---|---|---|
|
|
149
|
+
| `TEMP2MAVG` | `t2m` | Air temperature 2 m avg | °C | A |
|
|
150
|
+
| `TEMP2MMIN` | `t2m_min` | Air temperature 2 m min | °C | D |
|
|
151
|
+
| `TEMP2MMAX` | `t2m_max` | Air temperature 2 m max | °C | D |
|
|
152
|
+
| `TEMP10MAVG` | `t10m` | Air temperature 10 m avg | °C | A |
|
|
153
|
+
| `TEMP10MMIN` | `t10m_min` | Air temperature 10 m min | °C | D |
|
|
154
|
+
| `TEMP10MMAX` | `t10m_max` | Air temperature 10 m max | °C | D |
|
|
155
|
+
| `RELHUM2MAVG` | `rh` | Relative humidity 2 m avg | % | A |
|
|
156
|
+
| `RELHUM2MMIN` | `rh_min` | Relative humidity 2 m min | % | D |
|
|
157
|
+
| `RELHUM2MMAX` | `rh_max` | Relative humidity 2 m max | % | D |
|
|
158
|
+
| `VPDEFAVG` | `vpd` | Vapor pressure deficit avg | kPa | A |
|
|
159
|
+
| `PRESSUREAVG` | `pres` | Atmospheric pressure avg | kPa | A |
|
|
160
|
+
| `PRECIP` | `precip` | Precipitation gauge 1 | mm | A |
|
|
161
|
+
| `PRECIP2` | `precip2` | Precipitation gauge 2 | mm | A |
|
|
162
|
+
| `SRAVG` | `srad` | Solar radiation avg | W m⁻² | A |
|
|
163
|
+
| `WSPD2MAVG` | `wspd` | Wind speed 2 m avg | m s⁻¹ | A |
|
|
164
|
+
| `WSPD2MMAX` | `wspd_max` | Wind speed 2 m max | m s⁻¹ | H¹ |
|
|
165
|
+
| `WDIR2M` | `wdir` | Wind direction 2 m | ° | A |
|
|
166
|
+
| `WDIR2MSTD` | `wdir_std` | Wind direction 2 m std dev | ° | A |
|
|
167
|
+
| `WSPD10MAVG` | `wspd10m` | Wind speed 10 m avg | m s⁻¹ | A |
|
|
168
|
+
| `WSPD10MMAX` | `wspd10m_max` | Wind speed 10 m max | m s⁻¹ | H¹ |
|
|
169
|
+
| `WDIR10M` | `wdir10m` | Wind direction 10 m | ° | A |
|
|
170
|
+
| `WDIR10MSTD` | `wdir10m_std` | Wind direction 10 m std dev | ° | A |
|
|
171
|
+
|
|
172
|
+
¹ Available at 5-min and daily only (not hourly).
|
|
173
|
+
|
|
174
|
+
### Soil temperature — dedicated probes
|
|
175
|
+
|
|
176
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
177
|
+
|---|---|---|---|---|
|
|
178
|
+
| `SOILTMP5AVG` | `tsoil_5cm` | Soil temperature 5 cm avg | °C | A |
|
|
179
|
+
| `SOILTMP5MIN` | `tsoil_5cm_min` | Soil temperature 5 cm min | °C | D |
|
|
180
|
+
| `SOILTMP5MAX` | `tsoil_5cm_max` | Soil temperature 5 cm max | °C | D |
|
|
181
|
+
| `SOILTMP10AVG` | `tsoil_10cm` | Soil temperature 10 cm avg | °C | A |
|
|
182
|
+
| `SOILTMP10MIN` | `tsoil_10cm_min` | Soil temperature 10 cm min | °C | D |
|
|
183
|
+
| `SOILTMP10MAX` | `tsoil_10cm_max` | Soil temperature 10 cm max | °C | D |
|
|
184
|
+
|
|
185
|
+
### Soil — CS655 sensors
|
|
186
|
+
|
|
187
|
+
| API name | snake_case | Description | Unit | Intervals |
|
|
188
|
+
|---|---|---|---|---|
|
|
189
|
+
| `SOILTMP5AVG655` | `tsoil_5cm_655` | Soil temperature 5 cm | °C | A |
|
|
190
|
+
| `SOILTMP10AVG655` | `tsoil_10cm_655` | Soil temperature 10 cm | °C | A |
|
|
191
|
+
| `SOILTMP20AVG655` | `tsoil_20cm_655` | Soil temperature 20 cm | °C | A |
|
|
192
|
+
| `SOILTMP50AVG655` | `tsoil_50cm_655` | Soil temperature 50 cm | °C | A |
|
|
193
|
+
| `SOILKA5CM` | `ka_5cm` | Dielectric constant 5 cm | — | A |
|
|
194
|
+
| `SOILKA10CM` | `ka_10cm` | Dielectric constant 10 cm | — | A |
|
|
195
|
+
| `SOILKA20CM` | `ka_20cm` | Dielectric constant 20 cm | — | A |
|
|
196
|
+
| `SOILKA50CM` | `ka_50cm` | Dielectric constant 50 cm | — | A |
|
|
197
|
+
| `SOILEC5CM` | `ec_5cm` | Electrical conductivity 5 cm | dS m⁻¹ | A |
|
|
198
|
+
| `SOILEC10CM` | `ec_10cm` | Electrical conductivity 10 cm | dS m⁻¹ | A |
|
|
199
|
+
| `SOILEC20CM` | `ec_20cm` | Electrical conductivity 20 cm | dS m⁻¹ | A |
|
|
200
|
+
| `SOILEC50CM` | `ec_50cm` | Electrical conductivity 50 cm | dS m⁻¹ | A |
|
|
201
|
+
| `VWC5CM` | `vwc_5cm` | Volumetric water content 5 cm | m³ m⁻³ | A |
|
|
202
|
+
| `VWC10CM` | `vwc_10cm` | Volumetric water content 10 cm | m³ m⁻³ | A |
|
|
203
|
+
| `VWC20CM` | `vwc_20cm` | Volumetric water content 20 cm | m³ m⁻³ | A |
|
|
204
|
+
| `VWC50CM` | `vwc_50cm` | Volumetric water content 50 cm | m³ m⁻³ | A |
|
|
205
|
+
|
|
206
|
+
> **VWC note:** the Mesonet API returns VWC computed by the CS655 firmware equation. Requesting any `VWC*CM` column will print a warning reminding you that a site-specific calibration is available. To apply it, fetch the corresponding `SOILKA*CM` and `SOILEC*CM` columns in the same `request_data` call and then pass the DataFrame to `calibrate_vwc()`. Works for any subset of depths independently.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Notes
|
|
211
|
+
|
|
212
|
+
**Precipitation.** The Mesonet operates dual tipping-bucket rain gauges at most stations. `request_data()` returns both (`PRECIP`, `PRECIP2`); the desktop app merges them to the row-wise maximum automatically. For scripted use, merge manually:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
df["PRECIP"] = df[["PRECIP", "PRECIP2"]].max(axis=1)
|
|
216
|
+
df.drop(columns="PRECIP2", inplace=True)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Daily timestamps.** The Mesonet API stores each day's aggregated values at 00:00 of the following calendar day. `request_data()` corrects for this automatically; the returned `TIMESTAMP` always reflects the observation date.
|
|
220
|
+
|
|
221
|
+
**Missing values.** The API encodes missing observations as `"M"`. These are converted to `NaN` on read. Periods before a station or sensor was installed are pre-filled with `NaN` rather than omitted.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ksmesopy
|
|
3
|
+
=========
|
|
4
|
+
Python API for the Kansas Mesonet.
|
|
5
|
+
https://mesonet.k-state.edu
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from ksmesopy.core import (
|
|
9
|
+
get_stations,
|
|
10
|
+
get_stations_active,
|
|
11
|
+
list_variables,
|
|
12
|
+
VARIABLES,
|
|
13
|
+
RENAME_PRESET,
|
|
14
|
+
_VWC_DEPS,
|
|
15
|
+
_ALL_VWC,
|
|
16
|
+
_VALID_FOR,
|
|
17
|
+
request_data,
|
|
18
|
+
request_data_multi,
|
|
19
|
+
rename_columns,
|
|
20
|
+
calibrate_vwc,
|
|
21
|
+
compute_soil_water_storage,
|
|
22
|
+
srad_to_mj,
|
|
23
|
+
atmospheric_pressure,
|
|
24
|
+
saturation_vapor_pressure,
|
|
25
|
+
actual_vapor_pressure,
|
|
26
|
+
vapor_pressure_deficit,
|
|
27
|
+
slope_saturation_vapor_pressure,
|
|
28
|
+
psychrometric_constant,
|
|
29
|
+
extraterrestrial_radiation,
|
|
30
|
+
net_radiation,
|
|
31
|
+
reference_et_penman_monteith,
|
|
32
|
+
reference_et_hargreaves,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
from ksmesopy.utils import (
|
|
36
|
+
growing_degree_days,
|
|
37
|
+
heat_index,
|
|
38
|
+
wind_chill,
|
|
39
|
+
temperature_humidity_index,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
from ksmesopy.charts import (
|
|
43
|
+
plot_temperature,
|
|
44
|
+
plot_precip,
|
|
45
|
+
plot_humidity,
|
|
46
|
+
plot_vpd,
|
|
47
|
+
plot_solar_radiation,
|
|
48
|
+
plot_wind,
|
|
49
|
+
plot_vwc,
|
|
50
|
+
plot_et,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# Station metadata
|
|
55
|
+
"get_stations",
|
|
56
|
+
"get_stations_active",
|
|
57
|
+
# Variable catalogue
|
|
58
|
+
"list_variables",
|
|
59
|
+
"VARIABLES",
|
|
60
|
+
"RENAME_PRESET",
|
|
61
|
+
"_VWC_DEPS",
|
|
62
|
+
"_ALL_VWC",
|
|
63
|
+
"_VALID_FOR",
|
|
64
|
+
# Data retrieval
|
|
65
|
+
"request_data",
|
|
66
|
+
"request_data_multi",
|
|
67
|
+
"rename_columns",
|
|
68
|
+
# Soil processing
|
|
69
|
+
"calibrate_vwc",
|
|
70
|
+
"compute_soil_water_storage",
|
|
71
|
+
# Atmospheric helpers
|
|
72
|
+
"srad_to_mj",
|
|
73
|
+
"atmospheric_pressure",
|
|
74
|
+
"saturation_vapor_pressure",
|
|
75
|
+
"actual_vapor_pressure",
|
|
76
|
+
"vapor_pressure_deficit",
|
|
77
|
+
"slope_saturation_vapor_pressure",
|
|
78
|
+
"psychrometric_constant",
|
|
79
|
+
"extraterrestrial_radiation",
|
|
80
|
+
"net_radiation",
|
|
81
|
+
# Reference ET
|
|
82
|
+
"reference_et_penman_monteith",
|
|
83
|
+
"reference_et_hargreaves",
|
|
84
|
+
# Derived variables
|
|
85
|
+
"growing_degree_days",
|
|
86
|
+
"heat_index",
|
|
87
|
+
"wind_chill",
|
|
88
|
+
"temperature_humidity_index",
|
|
89
|
+
# Charts
|
|
90
|
+
"plot_temperature",
|
|
91
|
+
"plot_precip",
|
|
92
|
+
"plot_humidity",
|
|
93
|
+
"plot_vpd",
|
|
94
|
+
"plot_solar_radiation",
|
|
95
|
+
"plot_wind",
|
|
96
|
+
"plot_vwc",
|
|
97
|
+
"plot_et",
|
|
98
|
+
]
|