Skip to main content

ksmesopy

Python package for downloading and processing data from the Kansas Mesonet, an environmental monitoring network operated by Kansas State University.

Installation

pip install ksmesopy
pip install "ksmesopy[app]"  # Use this to also install a GUI

Dependencies: numpy, pandas, matplotlib. The desktop app additionally requires guile>=1.0.0,<2.

Quick start

import ksmesopy as ms

# Download daily temperature and precipitation for one station
df = ms.request_data(
    station="Manhattan",
    start="2024-01-01",
    end="2024-12-31",
    interval="day",
    variables=["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX", "PRECIP"],
    verbose=True,   # print progress while downloading (default False)
)

# Optional: rename columns to snake_case
df = ms.rename_columns(df)
# TIMESTAMP → timestamp, TEMP2MAVG → tair_2m_avg, PRECIP → precip, …

# Snapshot: every station at a single time step
snap = ms.request_snapshot(
    timestamp="2025-01-01",   # for 5min/hour, include a time e.g. "2025-01-01 14:30"
    interval="day",
    variables=["TEMP2MAVG", "PRECIP"],
)
# TIMESTAMP, STATION, TEMP2MAVG, PRECIP — one row per station

Desktop app

Run this in your terminal

ksmesopy-app

Graphical User Interface

A GUI for selecting stations, date ranges, variables, and intervals. Use the left navigation rail to switch between Inputs, Table, and Chart. Exports data to CSV and charts as PNG. The app ships with the Python package and runs directly without compilation; you can also launch it with python -m ksmesopy.app.


API reference

Stations

Function Returns Description
get_stations() DataFrame Full station metadata table
get_stations(names_only=True) list[str] Sorted list of station names only
get_stations_active() DataFrame Availability table: STATION, OBS_INTERVAL (s), START, END

Data retrieval

Function Returns Description
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. Pass verbose=True to print progress (see Progress reporting).
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. verbose=True adds a [n/total] station header before each station.
request_snapshot(timestamp, interval, variables, *, verbose) DataFrame One timestamp across all stations at once (the Mesonet stn=all endpoint). interval is "day", "hour", or "5min". Returns one row per station with a STATION column. For "day", the time component is ignored and the timestamp is corrected from the next-day convention, so results line up with request_data() for the same date.
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.
rename_columns(df, preset="snake") DataFrame Rename API column names to snake_case (e.g. TEMP2MAVG → tair_2m_avg). Pass a dict for a custom mapping.

Soil processing

Function Returns Description
calibrate_vwc(df, vwc_cols=None) DataFrame Replace firmware VWC values with the KSU site-specific calibration. Requires SOILKA*CM and SOILEC*CM columns. Works on any subset of depths.
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.

Derived variables

Function Returns Description
growing_degree_days(tmin, tmax, base=10.0, ceiling=30.0) ndarray Daily GDD. Both tmin/tmax clipped to [base, ceiling] before averaging.
heat_index(temp, rh) ndarray NOAA/NWS apparent temperature (°C).
wind_chill(temp, wspd) ndarray NWS wind chill (°C); valid for temp ≤ 10 °C, wind ≥ 1.3 m s⁻¹.
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.

Reference evapotranspiration

Function Returns Description
reference_et_penman_monteith(doy, lat, elev, tmin, tmax, srad, wspd, rhmin=None, rhmax=None, *, vpd=None, wind_height=2.0) ndarray FAO-56 Penman-Monteith. Supply humidity as either rhmin=+rhmax= or vpd= (at least one is required); when only vpd= is given, ea for net longwave is derived as es − vpd. srad in W m⁻², converted internally. wind_height (m) adjusts wind to 2 m via the FAO-56 log profile — pass 10.0 for the 10 m sensor.
reference_et_hargreaves(doy, lat, tmin, tmax, *, tmean) ndarray Hargreaves–Samani. Temperature only — no humidity, radiation, or wind needed.

Both return ETo (mm day⁻¹) as an ndarray. Use extraterrestrial_radiation(doy, lat) if you also need Ra.

Atmospheric helpers

Function Output
saturation_vapor_pressure(temp) es (kPa)
actual_vapor_pressure(temp, rh) ea (kPa)
vapor_pressure_deficit(temp, rh) VPD (kPa, ≥ 0)
slope_saturation_vapor_pressure(temp) Δ (kPa °C⁻¹)
atmospheric_pressure(elev) P (kPa)
psychrometric_constant(elev) γ (kPa °C⁻¹)
extraterrestrial_radiation(doy, lat) Ra (MJ m⁻² day⁻¹)
net_radiation(srad_mj, tmin, tmax, ea, elev, doy, lat) Rn (MJ m⁻² day⁻¹)
srad_to_mj(srad, period) energy (MJ m⁻²)

All functions accept scalars or NumPy arrays.

Charts

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 (tair_2m_avg) interchangeably, and return the axes they drew on so they can be further customised.

import matplotlib.pyplot as plt
import ksmesopy as ms

fig, axes = plt.subplots(5, 1, sharex=True, figsize=(12, 14))

ms.plot_temperature(axes[0], df, ["TEMP2MAVG", "TEMP2MMIN", "TEMP2MMAX"])
ms.plot_precip(axes[1], df, "PRECIP")
ms.plot_humidity(axes[2], df, "RELHUM2MAVG")
ms.plot_solar_radiation(axes[3], df, ["SRAVG", "Ra"])  # Ra drawn dashed
ms.plot_vwc(axes[4], df)                               # auto-detects VWC columns

plt.tight_layout()
plt.savefig("meteogram.png", dpi=150)

All functions accept API column names (TEMP2MAVG) or snake_case names (tair_2m_avg) interchangeably, and return the axes they drew on so they can be further customised.

Function Key behaviour
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.
plot_precip(ax, df, variable, *, ylabel, color) Bar chart, bar width inferred from timestamp spacing.
plot_humidity(ax, df, variables, *, ylabel, legend) Lines, y-axis fixed 0–100 %.
plot_vpd(ax, df, variables, *, ylabel, legend) Filled area + line, y-axis starts at 0.
plot_solar_radiation(ax, df, variables, *, ylabel, legend) Filled area for observed; dashed line for Ra columns (detected by name).
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.
plot_vwc(ax, df, variables, *, ylabel, legend) Sequential colormap shallow→deep; auto-detects VWC columns if variables=None.
plot_et(ax, df, variables, *, bar, ylabel, legend) Line by default; bar=True for daily totals.

Variable catalogue

Intervals: D = daily only · H = hourly and daily · A = 5-min, hourly, and daily

Atmospheric

API name snake_case Description Unit Intervals
TEMP2MAVG tair_2m_avg Air temperature 2 m avg °C A
TEMP2MMIN tair_2m_min Air temperature 2 m min °C D
TEMP2MMAX tair_2m_max Air temperature 2 m max °C D
TEMP10MAVG tair_10m_avg Air temperature 10 m avg °C A
TEMP10MMIN tair_10m_min Air temperature 10 m min °C D
TEMP10MMAX tair_10m_max Air temperature 10 m max °C D
RELHUM2MAVG rh_2m_avg Relative humidity 2 m avg % A
RELHUM2MMIN rh_2m_min Relative humidity 2 m min % D
RELHUM2MMAX rh_2m_max Relative humidity 2 m max % D
VPDEFAVG vpd_avg Vapor pressure deficit avg kPa A
PRESSUREAVG pressure_avg Atmospheric pressure avg kPa A
PRECIP precip Precipitation gauge 1 mm A
PRECIP2 precip2 Precipitation gauge 2 mm A
SRAVG srad Solar radiation avg W m⁻² A
WSPD2MAVG wspd_2m_avg Wind speed 2 m avg m s⁻¹ A
WSPD2MMAX wspd_2m_max Wind speed 2 m max m s⁻¹ H¹
WDIR2M wdir_2m Wind direction 2 m ° A
WDIR2MSTD wdir_2m_std Wind direction 2 m std dev ° A
WSPD10MAVG wspd_10m_avg Wind speed 10 m avg m s⁻¹ A
WSPD10MMAX wspd_10m_max Wind speed 10 m max m s⁻¹ H¹
WDIR10M wdir_10m Wind direction 10 m ° A
WDIR10MSTD wdir_10m_std Wind direction 10 m std dev ° A

¹ Available at 5-min and daily only (not hourly).

Soil temperature — dedicated probes

API name snake_case Description Unit Intervals
SOILTMP5AVG tsoil_5cm Soil temperature 5 cm avg °C A
SOILTMP5MIN tsoil_5cm_min Soil temperature 5 cm min °C D
SOILTMP5MAX tsoil_5cm_max Soil temperature 5 cm max °C D
SOILTMP10AVG tsoil_10cm Soil temperature 10 cm avg °C A
SOILTMP10MIN tsoil_10cm_min Soil temperature 10 cm min °C D
SOILTMP10MAX tsoil_10cm_max Soil temperature 10 cm max °C D

Soil — CS655 sensors

API name snake_case Description Unit Intervals
SOILTMP5AVG655 tsoil_5cm_655 Soil temperature 5 cm °C A
SOILTMP10AVG655 tsoil_10cm_655 Soil temperature 10 cm °C A
SOILTMP20AVG655 tsoil_20cm_655 Soil temperature 20 cm °C A
SOILTMP50AVG655 tsoil_50cm_655 Soil temperature 50 cm °C A
SOILKA5CM ka_5cm Dielectric constant 5 cm — A
SOILKA10CM ka_10cm Dielectric constant 10 cm — A
SOILKA20CM ka_20cm Dielectric constant 20 cm — A
SOILKA50CM ka_50cm Dielectric constant 50 cm — A
SOILEC5CM ec_5cm Electrical conductivity 5 cm dS m⁻¹ A
SOILEC10CM ec_10cm Electrical conductivity 10 cm dS m⁻¹ A
SOILEC20CM ec_20cm Electrical conductivity 20 cm dS m⁻¹ A
SOILEC50CM ec_50cm Electrical conductivity 50 cm dS m⁻¹ A
VWC5CM vwc_5cm Volumetric water content 5 cm m³ m⁻³ A
VWC10CM vwc_10cm Volumetric water content 10 cm m³ m⁻³ A
VWC20CM vwc_20cm Volumetric water content 20 cm m³ m⁻³ A
VWC50CM vwc_50cm Volumetric water content 50 cm m³ m⁻³ A

VWC note: the Mesonet API returns VWC computed by the CS655 firmware equation. Call calibrate_vwc() to replace those values with the KSU site-specific calibration. Requires SOILKA*CM and SOILEC*CM to be fetched alongside VWC*CM. Works for any subset of depths independently.


Notes

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:

df["PRECIP"] = df[["PRECIP", "PRECIP2"]].max(axis=1)
df.drop(columns="PRECIP2", inplace=True)

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.

Network snapshots. request_snapshot() fetches one time step for every station in a single call — handy for mapping a variable across Kansas on a given day or 5-minute mark. It's restricted to a single instant by design; for a time series at one station use request_data(). Daily snapshots use the same next-day correction as request_data(), so the two agree for any given date.

Progress reporting. Long requests are split into chunks of 3 000 records, so a multi-year download is several round trips to the API. Pass verbose=True to request_data(), request_data_multi(), or request_snapshot() to print one line per request as it is issued:

df = ms.request_data("Manhattan", "2013-01-01", "2024-12-31", "day",
                     ["TEMP2MAVG", "PRECIP"], verbose=True)
Manhattan: 2013-01-01 - 2021-03-20
Manhattan: 2021-03-21 - 2024-12-31
Manhattan: done — 4383 rows × 2 variables

Dates carry a time component for "hour" and "5min" intervals. Failed attempts are reported too, so a slow download that is quietly retrying is visible rather than looking hung. verbose defaults to False, keeping scripted use silent.

Progress messages are also sent to the ksmesopy logger at DEBUG level regardless of verbose, so an application can capture them instead of printing:

import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("ksmesopy").setLevel(logging.DEBUG)

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.


License

MIT

Metadata

Release files for ksmesopy 0.7.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ksmesopy 0.7.3
File Size Uploaded Provenance Actions
ksmesopy-0.7.3.tar.gz 36.1 kB With provenance Details for ksmesopy-0.7.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ksmesopy 0.7.3
File Interpreter ABI Platform Actions
ksmesopy-0.7.3-py3-none-any.whl Python 3 none any Details for ksmesopy-0.7.3-py3-none-any.whl

Total release size: 70.9 kB

Release files / ksmesopy-0.7.3.tar.gz

Download URL ksmesopy-0.7.3.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ed8afe0769d727c9eb0a10f84688b2ec4b3b5e77781cb574cba3e1cd84fa3cfb
BLAKE2b-256 checksum
How to use checksums
2de1376dfdca16ef279c6e9dabe3c276bc34e9bef0efef7e066701eae62e4651
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / ksmesopy-0.7.3-py3-none-any.whl

Download URL ksmesopy-0.7.3-py3-none-any.whl
Size 34.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
513def45317b0935fc3d06958dd3617cce13d9dbf4e83e18e45d92ac43644b14
BLAKE2b-256 checksum
How to use checksums
da44e79de0159da8071e1b36a4990cc8dad1e2716cbca4551a4416eaea1af30b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Security for ksmesopy 0.7.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ksmesopy-0.7.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page