🌦️ nus-campus-weather
Python package for the NUS Campus Meteorological Network dataset — hourly observations from 40 automatic weather stations across the National University of Singapore (NUS) main campus, Singapore, for the full calendar year 2025.
Dataset repo: nus-campus-weather-paper
PyPI:pip install nus-campus-weather
📦 Installation
From PyPI:
pip install nus-campus-weather
From source:
git clone https://github.com/City-Syntax/nus-campus-weather.git
cd nus-campus-weather
pip install -e .
Dependencies: pandas, numpy, matplotlib, seaborn
Optional (for map backgrounds): contextily
🚀 Quick Start
import nus_campus_weather as ncw
# Just use it — the dataset auto-downloads from Zenodo on first call
# (~120 MB, one-time), then cached for future use.
df = ncw.load_station("WS01")
fig = ncw.plot_climatology()
Optional — explicit fetch
ncw.fetch_dataset() # download/cache now instead of on first load
Optional — bring your own copy
If you have a local clone of the dataset repo (useful for development or offline work), point the loader at it:
ncw.set_data_dir("/path/to/nus-campus-weather-paper")
# Or via env var:
# export NUS_WEATHER_DATA="/path/to/nus-campus-weather-paper"
The auto-fetch caches to your platform cache dir (~/Library/Caches/nus_campus_weather/
on macOS, ~/.cache/nus_campus_weather/ on Linux, %LOCALAPPDATA%\nus_campus_weather\
on Windows). Override with the NUS_WEATHER_CACHE environment variable.
Dataset version
ncw.DATASET_VERSION # '1.1.0'
ncw.DATASET_DOI # '10.5281/zenodo.23535609'
📂 Loading Data
Single station
# Raw sensor data
df = ncw.load_station("WS01")
# Gap-filled data (includes _flag columns)
df = ncw.load_station("WS01", imputed=True)
Each CSV has columns: Datetime, Latitude, Longitude, Elevation (m), Type, and six meteorological variables (plus Rain Tot (mm) at WS02, WS16, WS35). Imputed files add a _flag column per variable:
| Flag | Meaning |
|---|---|
0 |
Original observation |
1 |
Stage 1 linear interpolation (short gaps) |
2 |
Stage 2 XGBoost spatial regression |
3 |
Not measured / not imputed (left empty) |
Observed values only
# Gap-filled file, but every filled value (flag 1-3) returned as NaN
df = ncw.load_station("WS01", imputed=True, observed_only=True)
wsp = ncw.load_all(variable="WindSpeed Ave (m/s)", imputed=True, observed_only=True)
⚠️ Wind: gap-filled wind speed and direction have little skill at intra-campus scale. Use
observed_only=True(or filterflag == 0) for wind analyses; the package warns if filled wind values are loaded.
All 40 stations
# Wide format — one column per station (8760 rows × 40 cols)
temp = ncw.load_all(variable="AirTemp Ave (C)", imputed=True)
# Long format — all stations stacked
long_df = ncw.load_all(imputed=True)
Station metadata
meta = ncw.station_metadata()
# Returns a DataFrame indexed by station (WS01..WS40) with columns:
# lat, lon, elevation_m, type (Ground / Roof / Roof-3axis)
📊 Plot Functions
All plot functions use the data directory set via set_data_dir() and save figures to a figures/ subfolder within it.
| Function | Output |
|---|---|
ncw.plot_completeness() |
Completeness bubble map and monthly heatmap (cf. paper Fig. 4) |
ncw.plot_climatology() |
Diurnal × seasonal climatology (cf. paper Fig. 6) |
ncw.plot_radials() |
Annual radial climatology, five variables (cf. paper Fig. 9) |
ncw.plot_imputation_examples() |
Representative gap-fill examples (cf. paper Fig. 10) |
ncw.plot_completeness()
ncw.plot_climatology()
ncw.plot_radials()
ncw.plot_imputation_examples()
🗂️ Dataset Variables
| Column | Units | Notes |
|---|---|---|
AirTemp Ave (C) |
°C | Ground stations 2–3 m above ground; 8 rooftop stations |
RelHum Ave (%) |
% | |
AtmPress Ave (hPa) |
hPa | |
GlobalRad Ave (W/m2) |
W m⁻² | Global horizontal irradiance at the sensor, including local shading |
WindSpeed Ave (m/s) |
m s⁻¹ | Hourly vector mean (magnitude of the mean wind vector) |
WindDir Ave (degrees) |
° | Hourly vector mean, 0–360° |
Rain Tot (mm) |
mm | WS02, WS16, WS35 only |
⚠️ Known issues
From dataset v1.1.0, faulty sensor values are removed by rule-based quality control; every removal is listed in data_quality_assessment/qc_log.csv of the dataset repository.
- Global irradiance not available (flag 3, not imputed) at WS38 (no pyranometer, fully shaded site) and WS32, WS39 (pyranometers non-functional).
- Global irradiance removed for some months at WS07, WS19, WS23 and WS26 (corrupted channel; spurious night-time readings).
- WS17 — pressure removed for January–April (faulty sensor) and wind for 20–26 December (sensor malfunction); these gaps are filled like any other.
- Wind speed/direction — spatially decorrelated at intra-campus scale; use only flag = 0 observations for wind analyses (
observed_only=True).
📄 Citation
If you use this package or dataset, please cite:
Lim, J. et al. An hourly meteorological dataset from a high-density 40-station campus weather network in tropical Singapore. Scientific Data (under review).
Dataset: Zenodo, https://doi.org/10.5281/zenodo.20477760 (all versions)
📜 Licence
Code (this package): MIT — see LICENSE.
Dataset: CC BY 4.0 — see the dataset repository.
Metadata
Release files for nus-campus-weather 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nus_campus_weather-1.2.0.tar.gz | 20.0 kB | Without provenance | Details for nus_campus_weather-1.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nus_campus_weather-1.2.0-py3-none-any.whl | Python 3 | none | any | Details for nus_campus_weather-1.2.0-py3-none-any.whl |
Total release size: 39.3 kB
Release files / nus_campus_weather-1.2.0.tar.gz
| Download URL | nus_campus_weather-1.2.0.tar.gz |
|---|---|
| Size | 20.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cf87524bfd00934ef21003333e50d83828703cbb1238769d18695e21dbe2ad93
|
|
BLAKE2b-256 checksum How to use checksums |
076b4b7bded5809ab50d82ad85d04a8c30b8c6744f458f0b4e38a108d04182ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / nus_campus_weather-1.2.0-py3-none-any.whl
| Download URL | nus_campus_weather-1.2.0-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4a5840985c7428d060797c0eb029701aefc8e43798ef0ecd0040699281f90eef
|
|
BLAKE2b-256 checksum How to use checksums |
0ac08a66a38a076945241948f2857af59a4f5567fa4221f593f766b6c68d79b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Security for nus-campus-weather 1.2.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.