Skip to content

Comparison & validation

Compare gridded sources

Available as climate_toolkit.compare_climate_sources.

climate_toolkit.compare_datasets.compare_datasets.compare_sources

compare_sources(
    sources,
    lat=None,
    lon=None,
    start=None,
    end=None,
    input_file=None,
    output_dir="./outputs",
    nex_model=None,
    nex_scenario="ssp245",
    nex_models=None,
    precip_source=None,
    temp_source=None,
    workers=1,
)

Fetch one or more climate datasets for a location and prepare them for comparison.

For each requested source, this function fetches cleaned, analysis-ready daily data for a single point (latitude/longitude) over a date range via the toolkit's preprocessing pipeline, exports each dataset to <output_dir>/<source>.csv, and returns the datasets keyed by source name. The returned dictionary is the input expected by print_report, which produces the comparison tables (annual time series, annual statistics, monthly climatologies, pairwise correlations) and PNG plots.

Climate sources retrieve daily precipitation, maximum temperature, and minimum temperature. The soil_grid source instead retrieves static soil properties (pH, texture fractions, bulk density, organic carbon, CEC), broadcast as a constant daily series across the date range so it can sit alongside the climate sources. Sources that fail to fetch are skipped with a printed warning rather than aborting the run.

Most sources are read from Google Earth Engine and require prior Earth Engine authentication plus a Google Cloud project id in the GCP_PROJECT_ID environment variable (GOOGLE_CLOUD_PROJECT or EE_PROJECT_ID also work). nasa_power uses NASA's public web service and needs no authentication.

Parameters:

Name Type Description Default
sources list of str

Dataset keys to fetch and compare. Valid keys: 'agera_5', 'chirps', 'chirps_v2', 'chirps_v3_daily_rnl', 'chirts', 'cmip_6', 'era_5', 'imerg', 'nasa_power', 'nex_gddp', 'soil_grid', 'tamsat', 'terraclimate', 'auto' (the toolkit's default historical precipitation + temperature pairing), and 'paired' (a custom pairing; requires precip_source and temp_source). 'nex_gddp' (future CMIP6 projections) must be run on its own, not mixed with historical sources. Ignored when input_file is given.

required
lat float

Latitude of the point of interest in decimal degrees (default None). Required unless input_file is given.

None
lon float

Longitude of the point of interest in decimal degrees (default None). Required unless input_file is given.

None
start str

Start date as 'YYYY-MM-DD' (default None, meaning the source's earliest available date).

None
end str

End date as 'YYYY-MM-DD' (default None, meaning the source's latest available date).

None
input_file str

Path to a CSV of already-fetched daily data containing a date column plus one column per variable (default None). When given, no sources are fetched; the file is loaded, re-exported to output_dir, and returned under the key 'input_file'.

None
output_dir str

Directory where per-source CSV files are written; created if it does not exist (default './outputs'). print_report also writes its PNG plots here.

'./outputs'
nex_model str

Single NEX-GDDP-CMIP6 model name, e.g. 'MRI-ESM2-0' (default None). Only used when 'nex_gddp' is in sources. If neither nex_model nor nex_models is given, a default multi-model ensemble for the location is averaged into one series.

None
nex_scenario str

NEX-GDDP-CMIP6 emissions scenario (default 'ssp245'). Common options include 'ssp126', 'ssp245', 'ssp370' and 'ssp585'; only used when 'nex_gddp' is in sources.

'ssp245'
nex_models list of str

Two or more NEX-GDDP-CMIP6 model names to average into a single ensemble-mean series (default None). Overrides nex_model.

None
precip_source str

Precipitation partner for the 'paired' source, e.g. 'chirps_v3_daily_rnl', 'chirps_v2', 'imerg' (default None).

None
temp_source str

Temperature partner for the 'paired' source, e.g. 'agera_5', 'era_5', 'chirts' (default None).

None
workers int

Number of parallel workers for chunked Google Earth Engine fetches (default 1).

1

Returns:

Type Description
dict of str to pandas.DataFrame

Mapping from result key to a daily DataFrame with a date column (datetime64) plus one numeric column per variable (e.g. precipitation, max_temperature, min_temperature). Keys are usually the source name as passed in; NEX-GDDP results use 'nex_gddp_<model>_<scenario>' or 'nex_gddp_ensemble_<scenario>', custom pairings use 'paired_<precip>_plus_<temp>', and input_file runs use 'input_file'. Pass this dictionary to print_report to generate the comparison report and plots.

Raises:

Type Description
ValueError

If a source key is unknown, 'nex_gddp' is combined with other sources, the NEX-GDDP scenario or model names are invalid, or the paired-source configuration is incomplete or inconsistent.

RuntimeError

If none of the requested sources returned usable data.

Examples:

Compare AgERA5 and NASA POWER for Nairobi over 2020, then print the comparison report:

>>> import climate_toolkit as ct
>>> results = ct.compare_climate_sources(
...     sources=["agera_5", "nasa_power"],
...     lat=-1.286,
...     lon=36.817,
...     start="2020-01-01",
...     end="2020-12-31",
...     output_dir="./outputs",
... )
>>> sorted(results)
['agera_5', 'nasa_power']
>>> from climate_toolkit.compare_datasets.compare_datasets import print_report
>>> stats = print_report(results, output_dir="./outputs")

Download station data

Available as climate_toolkit.download_station_data.

climate_toolkit.weather_station.download.download_station_data

download_station_data(
    *,
    station_source,
    station_coord,
    date_from,
    date_to,
    variables=None,
    station_id=None,
    stage="preprocessed",
    verbose=True,
    cache_dir=None,
    refresh_cache=False,
    selection_mode="auto",
    max_distance_km=DEFAULT_MAX_DISTANCE_KM,
    target_elevation_m=None,
    max_elevation_diff_m=DEFAULT_MAX_ELEVATION_DIFF_M,
    min_completeness_ratio=DEFAULT_MIN_COMPLETENESS_RATIO,
    candidate_limit=DEFAULT_CANDIDATE_LIMIT,
    score_limit=DEFAULT_SCORE_LIMIT,
    auto_select="auto-1",
    auto_anchor_elevation=True,
    disable_completeness_guard=False,
    max_auto_stations=DEFAULT_MAX_AUTO_STATIONS,
    custom_station_file=None,
    custom_station_name=None,
    custom_temp_unit="c",
    custom_precip_unit="mm",
)

Download daily weather-station observations near a point of interest.

Finds weather stations close to station_coord, ranks them by distance, elevation similarity, and data completeness, then downloads daily observations for the requested date range and variables. All arguments are keyword-only. The result is a pandas DataFrame (the Python analogue of an R data.frame), with one row per station-day, or -- when selection_mode="list" -- one row per candidate station.

Station backends (GHCN-Daily and GSOD) are public NOAA archives and need no Google Earth Engine authentication. The only optional Earth Engine touchpoint is the DEM elevation lookup used when auto_anchor_elevation=True; if Earth Engine is not configured the lookup fails gracefully, a warning is printed, and station selection proceeds without the elevation guard.

Parameters:

Name Type Description Default
station_source str

Station backend to search. Valid values:

  • "ghcn_daily" : NOAA GHCN-Daily archive (default backend in the CLI; supports all selection modes).
  • "gsod" : NOAA Global Summary of the Day. Currently supports selection_mode="specified" only and requires station_id (a 5-digit WMO-like ID or 11-digit GSOD ID).
  • "auto" : rank candidates across both NOAA backends (GHCN-Daily + GSOD) together.
  • "custom_csv" : load a user-supplied station file; requires custom_station_file.
required
station_coord tuple of float

(latitude, longitude) of the point of interest in decimal degrees (the anchor for the station search, not necessarily a station location).

required
date_from date

First day of the requested period (inclusive).

required
date_to date

Last day of the requested period (inclusive).

required
variables list of ClimateVariable or list of str

Variables to request, e.g. ["precipitation", "max_temperature", "min_temperature"] or the corresponding ClimateVariable enum members. None (default) requests the backend's full supported set.

None
station_id str

Explicit station identifier. Required when selection_mode="specified" and for station_source="gsod". Default None.

None
stage str

Processing stage of the returned data: "raw", "transformed", or "preprocessed" (default). Use the default for analysis-ready, unit-harmonised values.

'preprocessed'
verbose bool

If True (default), print progress and selection warnings.

True
cache_dir str

Directory for cached downloads. None (default) uses the toolkit's default cache location.

None
refresh_cache bool

If True, ignore cached files and re-download. Default False.

False
selection_mode str

How stations are chosen. Valid values:

  • "auto" (default) : rank nearby candidates and download data from the top station(s) per auto_select.
  • "specified" : download exactly the station given by station_id.
  • "list" : do not download observations; return a ranked candidate table for review.
'auto'
max_distance_km float

Search radius around station_coord; candidates farther than this are excluded. Default 50.0.

DEFAULT_MAX_DISTANCE_KM
target_elevation_m float

Reference elevation (m) for the elevation guard. None (default) resolves it from a DEM when auto_anchor_elevation=True.

None
max_elevation_diff_m float

Maximum allowed absolute elevation difference (m) between a candidate station and the target elevation. Default 500.0.

DEFAULT_MAX_ELEVATION_DIFF_M
min_completeness_ratio float

Minimum fraction (0-1) of days with data required per requested variable for a candidate to pass the completeness guard. Default 0.7.

DEFAULT_MIN_COMPLETENESS_RATIO
candidate_limit int

Maximum number of candidates retained after ranking. Default 10.

DEFAULT_CANDIDATE_LIMIT
score_limit int

Maximum number of nearby stations scored for completeness (the expensive step). Default 25.

DEFAULT_SCORE_LIMIT
auto_select str

How many top-ranked stations to download in selection_mode="auto": "auto-1" (default, best station only), "auto-<n>" (top n, e.g. "auto-3"), or "auto-all". Always capped at max_auto_stations.

'auto-1'
auto_anchor_elevation bool

If True (default) and target_elevation_m is None, look up the anchor elevation from a DEM (via Earth Engine, with graceful fallback).

True
disable_completeness_guard bool

If True, skip the completeness threshold and return the nearest-ranked stations regardless of data coverage. Default False.

False
max_auto_stations int

Hard cap on stations downloaded via auto_select. Default 10.

DEFAULT_MAX_AUTO_STATIONS
custom_station_file str

Path to a custom station CSV/JSON file. Required when station_source="custom_csv". Default None.

None
custom_station_name str

Label for the custom station. Default None.

None
custom_temp_unit str

Temperature unit in the custom file: "c" (default), "f", or "k".

'c'
custom_precip_unit str

Precipitation unit in the custom file: "mm" (default), "inch", or "tenth_mm".

'mm'

Returns:

Type Description
DataFrame

Structure depends on selection_mode:

  • "auto" or "specified" : daily observations, one row per station-day, with a date column, station metadata columns (station_id, station_name, station_lat, station_lon, station_elevation_m, ...), one column per requested variable (e.g. precipitation, max_temperature, min_temperature), and selection metadata (selection_rank, selection_status, distance_km, fields_passing_threshold, ...). With auto_select > 1 station, rows for all stations are stacked and distinguished by selection_rank. Empty DataFrame if no station returned data.
  • "list" : one row per candidate station with ranking diagnostics (distance_km, elevation_diff_m, completeness ratios, threshold_status, fields_passing_threshold, fields_failing_threshold, ...) and no daily observations. Selection warnings, if any, are attached in frame.attrs["selection_warnings"].

Raises:

Type Description
ValueError

If station_source is unsupported, if required arguments for the chosen mode are missing (e.g. station_id with selection_mode="specified"), or if auto_select is malformed.

Examples:

Download 2020 daily records from the single best GHCN-Daily station within 50 km of Nairobi:

>>> from datetime import date
>>> import climate_toolkit as ct
>>> obs = ct.download_station_data(
...     station_source="ghcn_daily",
...     station_coord=(-1.286, 36.817),
...     date_from=date(2020, 1, 1),
...     date_to=date(2020, 12, 31),
...     variables=["precipitation", "max_temperature", "min_temperature"],
...     selection_mode="auto",
...     auto_select="auto-1",
... )
>>> obs[["date", "station_id", "precipitation", "max_temperature"]].head()

Validate grids against stations

Available as climate_toolkit.compare_station_to_grids.

climate_toolkit.weather_station.compare.compare_station_to_grids

compare_station_to_grids(
    *,
    station_source,
    station_coord,
    date_from,
    date_to,
    grid_sources,
    variables=None,
    station_id=None,
    selection_mode="auto",
    selection_strategy=DEFAULT_SELECTION_STRATEGY,
    auto_select="auto-1",
    max_distance_km=50.0,
    target_elevation_m=None,
    max_elevation_diff_m=500.0,
    min_completeness_ratio=0.7,
    candidate_limit=10,
    score_limit=25,
    auto_anchor_elevation=True,
    disable_completeness_guard=False,
    max_auto_stations=10,
    cache_dir=None,
    refresh_cache=False,
    precip_source=None,
    temp_source=None,
    wet_day_threshold_mm=DEFAULT_WET_DAY_THRESHOLD_MM,
    min_overlap_days=DEFAULT_MIN_OVERLAP_DAYS,
    verbose=True,
    custom_station_file=None,
    custom_station_name=None,
    custom_temp_unit="c",
    custom_precip_unit="mm",
    candidate_report_prefix=None,
    workers=1,
)

Validate gridded climate products against nearby station observations.

Downloads daily station records near station_coord (via :func:download_station_data), fetches each requested gridded product at the station location for the same period, matches the two on date, and computes agreement statistics (bias, MAE, RMSE, correlation) per station, grid source, and variable at daily, monthly, seasonal, and annual timescales. For precipitation it adds wet-day occurrence skill (hit rate, false-alarm ratio, critical success index, frequency bias), totals, upper-tail quantiles, and heavy-rain indices (rx1day, rx5day, R10mm, R20mm). All arguments are keyword-only. The result is a plain Python dict (the analogue of an R named list), ready for json.dumps or conversion of its list entries to DataFrames.

Authentication note: the station side (GHCN-Daily / GSOD) downloads from public NOAA archives and needs no Google Earth Engine credentials, but most grid sources (agera_5, era_5, chirps, chirts, imerg, terraclimate, ...) are fetched through Google Earth Engine and require the GCP_PROJECT_ID environment variable (or GOOGLE_CLOUD_PROJECT / EE_PROJECT_ID) plus an authenticated Earth Engine account. nasa_power uses the NASA POWER web API and does not need Earth Engine. Failed grid fetches do not abort the run; they are recorded under "grid_failures" in the result.

Parameters:

Name Type Description Default
station_source str

Station backend: "ghcn_daily", "gsod", "auto" (rank across both NOAA backends), or "custom_csv" (requires custom_station_file). See :func:download_station_data.

required
station_coord tuple of float

(latitude, longitude) of the point of interest in decimal degrees; anchors both the station search and the grid extraction.

required
date_from date

First day of the comparison period (inclusive).

required
date_to date

Last day of the comparison period (inclusive).

required
grid_sources list of str

Historical gridded products to evaluate. Valid values: "agera_5", "era_5", "chirps", "chirps_v2", "chirts", "chirps_v2+chirts", "chirps_v3_daily_rnl", "imerg", "nasa_power", "terraclimate", "auto" (toolkit's composite selector), and "paired" (combine precip_source + temp_source). Non-historical or station sources ("ghcn_daily", "gsod", "nex_gddp", "soil_grid", "tamsat") are rejected with ValueError.

required
variables list of ClimateVariable or list of str

Variables to compare. None (default) compares precipitation, max_temperature, and min_temperature.

None
station_id str

Explicit station identifier; used with selection_mode="specified". Default None.

None
selection_mode str

Station-selection behaviour: "auto" (default; rank nearby candidates automatically), "specified" (use station_id), or "list" (return the ranked candidate table only -- no comparison metrics are computed).

'auto'
selection_strategy str

How stations map to variables:

  • "all_vars_single_station" (default) : one station download covering all variables together.
  • "best_per_variable" : select the best station separately for each variable (stations may differ between, say, precipitation and temperature).
DEFAULT_SELECTION_STRATEGY
auto_select str

Number of top-ranked stations used when selection_mode="auto": "auto-1" (default), "auto-<n>", or "auto-all" (capped at max_auto_stations).

'auto-1'
max_distance_km float

Station search radius in km. Default 50.0.

50.0
target_elevation_m float

Reference elevation (m) for the elevation guard; None (default) resolves it from a DEM when auto_anchor_elevation=True.

None
max_elevation_diff_m float

Maximum station-vs-anchor elevation difference (m). Default 500.0.

500.0
min_completeness_ratio float

Minimum per-variable data completeness (0-1) for candidate stations. Default 0.7.

0.7
candidate_limit int

Maximum candidates retained after ranking. Default 10.

10
score_limit int

Maximum nearby stations scored for completeness. Default 25.

25
auto_anchor_elevation bool

If True (default), resolve the anchor elevation from a DEM (Earth Engine; falls back gracefully with a warning).

True
disable_completeness_guard bool

If True, skip the completeness threshold when selecting stations. Default False.

False
max_auto_stations int

Hard cap on stations used via auto_select. Default 10.

10
cache_dir str

Directory for cached downloads. Default None (toolkit default).

None
refresh_cache bool

If True, re-download instead of using cached files. Default False.

False
precip_source str

Precipitation and temperature products combined when "paired" is among grid_sources. Default None.

None
temp_source str

Precipitation and temperature products combined when "paired" is among grid_sources. Default None.

None
wet_day_threshold_mm float

Daily precipitation (mm) at or above which a day counts as wet in the occurrence-skill statistics. Default 1.0.

DEFAULT_WET_DAY_THRESHOLD_MM
min_overlap_days int

Minimum station-grid overlap (days) below which a low-confidence warning is attached to a metric row. Default 30.

DEFAULT_MIN_OVERLAP_DAYS
verbose bool

If True (default), print progress messages.

True
custom_station_file str

Path to a custom station CSV/JSON (with station_source="custom_csv"). Default None.

None
custom_station_name str

Label for the custom station. Default None.

None
custom_temp_unit str

Temperature unit in the custom file: "c" (default), "f", or "k".

'c'
custom_precip_unit str

Precipitation unit in the custom file: "mm" (default), "inch", or "tenth_mm".

'mm'
candidate_report_prefix str

If given, write a candidate-review report to <prefix>.csv, <prefix>.json, and <prefix>.html (an interactive map plus ranking table); the paths are returned under "candidate_review_artifacts". Default None (no report).

None
workers int

Parallel workers for grid-data fetching. Default 1.

1

Returns:

Type Description
dict

A report dictionary. Main keys:

  • "metrics" : list of dict, one per station x grid source x variable, with overlap_days, confidence_class, bias, mae, rmse, correlation, and (for precipitation) wet-day skill and heavy-rain diagnostics.
  • "monthly_metrics", "seasonal_metrics", "annual_metrics" : the same comparisons on aggregated series; annual rows add coverage_ratio and window_status.
  • "pooled_daily_metrics", "pooled_monthly_metrics", "pooled_seasonal_metrics", "pooled_annual_metrics" : metrics against a per-date mean across selected stations (station_id="POOLED_REF"); "overall_metrics" pools raw overlap rows across stations (station_id="ALL").
  • "use_case_rankings" : grid sources ranked (0-1 scores) for use cases such as daily_monitoring, seasonal_totals, drought_screening, heavy_rain_screening, and temperature_climatology.
  • "station_summary", "selected_stations_by_variable", "grid_fetch_summary", "grid_failures", "grid_source_metadata" (including whether each product is station-informed, i.e. not fully independent validation), "warnings", "confidence_summary", "window_status_summary", "xclim_precip_indices", and echo of the inputs ("anchor_location", "date_from", "grid_sources", ...).

With selection_mode="list" the dict instead carries "candidate_stations" (list of candidate records) and all metric lists are empty.

Raises:

Type Description
ValueError

If grid_sources is empty, contains unknown or unsupported sources, or if selection_strategy is invalid.

RuntimeError

If no station observations are available for comparison.

Examples:

Compare the best GHCN-Daily station near Nairobi against AgERA5 for 2020 (requires GCP_PROJECT_ID to be set for the grid fetch):

>>> from datetime import date
>>> import climate_toolkit as ct
>>> report = ct.compare_station_to_grids(
...     station_source="ghcn_daily",
...     station_coord=(-1.286, 36.817),
...     date_from=date(2020, 1, 1),
...     date_to=date(2020, 12, 31),
...     grid_sources=["agera_5"],
...     variables=["precipitation", "max_temperature", "min_temperature"],
... )
>>> import pandas as pd
>>> pd.DataFrame(report["metrics"])[
...     ["grid_source", "variable", "overlap_days", "bias", "correlation"]
... ]