Metadata-Version: 2.5
Name: varunayan
Version: 0.4.0
Summary: Download ERA5, IMD, HadEX3 and CRU TS climate data for a bounding box, polygon or point, and compute heat stress indices
Project-URL: Homepage, https://github.com/saketlab/varunayan
Project-URL: Documentation, https://varunayan.saketlab.org/python/
Project-URL: Repository, https://github.com/saketlab/varunayan
Project-URL: Issues, https://github.com/saketlab/varunayan/issues
Author-email: Atharva Jagtap <atharvajagtap1108@gmail.com>, Saket Choudhary <saketc@iitb.ac.in>
Maintainer-email: Atharva Jagtap <atharvajagtap1108@gmail.com>, Saket Choudhary <saketc@iitb.ac.in>
License-Expression: MIT
License-File: LICENSE
Keywords: climate,cru-ts,era5,geospatial,hadex3,heat-stress,imd,netcdf
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.10
Requires-Dist: cdsapi>=0.5.1
Requires-Dist: geopandas>=0.10.0
Requires-Dist: matplotlib>=3.3.0
Requires-Dist: netcdf4>=1.5.0
Requires-Dist: numpy>=1.20.0
Requires-Dist: pandas>=1.3.0
Requires-Dist: python-dateutil>=2.8.0
Requires-Dist: requests>=2.25.0
Requires-Dist: shapely>=1.8.0
Requires-Dist: tqdm>=4.60.0
Requires-Dist: xarray>=0.20.0
Provides-Extra: all
Requires-Dist: bandit>=1.7.0; extra == 'all'
Requires-Dist: black>=22.0; extra == 'all'
Requires-Dist: build>=0.7.0; extra == 'all'
Requires-Dist: check-manifest>=0.48; extra == 'all'
Requires-Dist: coverage[toml]>=6.0; extra == 'all'
Requires-Dist: docutils>=0.17; extra == 'all'
Requires-Dist: flake8>=4.0; extra == 'all'
Requires-Dist: furo>=2023.3.27; extra == 'all'
Requires-Dist: ipykernel>=6.0; extra == 'all'
Requires-Dist: ipython>=7.0; extra == 'all'
Requires-Dist: isort>=5.10; extra == 'all'
Requires-Dist: jupyter-client>=7.0; extra == 'all'
Requires-Dist: jupyter>=1.0; extra == 'all'
Requires-Dist: linkify-it-py>=2.0; extra == 'all'
Requires-Dist: livereload>=2.6.3; extra == 'all'
Requires-Dist: markdown-it-py>=2.0; extra == 'all'
Requires-Dist: mdit-py-plugins>=0.3.0; extra == 'all'
Requires-Dist: mypy>=0.910; extra == 'all'
Requires-Dist: myst-nb>=0.13.0; extra == 'all'
Requires-Dist: myst-parser>=0.15; extra == 'all'
Requires-Dist: nbclient>=0.8; extra == 'all'
Requires-Dist: nbconvert>=6.0; extra == 'all'
Requires-Dist: nbconvert>=7.0; extra == 'all'
Requires-Dist: pandas-stubs; extra == 'all'
Requires-Dist: pre-commit>=2.15; extra == 'all'
Requires-Dist: pylint>=2.12.0; extra == 'all'
Requires-Dist: pytest-cov>=2.10; extra == 'all'
Requires-Dist: pytest-mock>=3.6.1; extra == 'all'
Requires-Dist: pytest-timeout>=2.1.0; extra == 'all'
Requires-Dist: pytest-xdist>=2.5.0; extra == 'all'
Requires-Dist: pytest>=6.0; extra == 'all'
Requires-Dist: safety>=2.0.0; extra == 'all'
Requires-Dist: setuptools>=60.0.0; extra == 'all'
Requires-Dist: sphinx-autoapi>=2.0; extra == 'all'
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == 'all'
Requires-Dist: sphinx-copybutton>=0.5.0; extra == 'all'
Requires-Dist: sphinx-design>=0.3.0; extra == 'all'
Requires-Dist: sphinx-multiversion>=0.2.4; extra == 'all'
Requires-Dist: sphinx-sitemap>=2.5.0; extra == 'all'
Requires-Dist: sphinx-tabs>=3.0.0; extra == 'all'
Requires-Dist: sphinx-togglebutton>=0.3.0; extra == 'all'
Requires-Dist: sphinx>=4.0; extra == 'all'
Requires-Dist: sphinxext-opengraph>=0.9.0; extra == 'all'
Requires-Dist: statsmodels>=0.13; extra == 'all'
Requires-Dist: tox>=3.24.0; extra == 'all'
Requires-Dist: twine>=4.0.0; extra == 'all'
Requires-Dist: types-requests; extra == 'all'
Requires-Dist: watchdog>=2.1.0; extra == 'all'
Requires-Dist: wheel>=0.37.0; extra == 'all'
Provides-Extra: build
Requires-Dist: build>=0.7.0; extra == 'build'
Requires-Dist: check-manifest>=0.48; extra == 'build'
Requires-Dist: setuptools>=60.0.0; extra == 'build'
Requires-Dist: twine>=4.0.0; extra == 'build'
Requires-Dist: wheel>=0.37.0; extra == 'build'
Provides-Extra: dev
Requires-Dist: black>=22.0; extra == 'dev'
Requires-Dist: flake8>=4.0; extra == 'dev'
Requires-Dist: isort>=5.10; extra == 'dev'
Requires-Dist: mypy>=0.910; extra == 'dev'
Requires-Dist: pandas-stubs; extra == 'dev'
Requires-Dist: pre-commit>=2.15; extra == 'dev'
Requires-Dist: pytest-cov>=2.10; extra == 'dev'
Requires-Dist: pytest>=6.0; extra == 'dev'
Requires-Dist: statsmodels>=0.13; extra == 'dev'
Requires-Dist: types-requests; extra == 'dev'
Provides-Extra: docs
Requires-Dist: docutils>=0.17; extra == 'docs'
Requires-Dist: furo>=2023.3.27; extra == 'docs'
Requires-Dist: ipython>=7.0; extra == 'docs'
Requires-Dist: jupyter>=1.0; extra == 'docs'
Requires-Dist: linkify-it-py>=2.0; extra == 'docs'
Requires-Dist: markdown-it-py>=2.0; extra == 'docs'
Requires-Dist: mdit-py-plugins>=0.3.0; extra == 'docs'
Requires-Dist: myst-nb>=0.13.0; extra == 'docs'
Requires-Dist: myst-parser>=0.15; extra == 'docs'
Requires-Dist: nbconvert>=6.0; extra == 'docs'
Requires-Dist: sphinx-autoapi>=2.0; extra == 'docs'
Requires-Dist: sphinx-copybutton>=0.5.0; extra == 'docs'
Requires-Dist: sphinx-design>=0.3.0; extra == 'docs'
Requires-Dist: sphinx-multiversion>=0.2.4; extra == 'docs'
Requires-Dist: sphinx-sitemap>=2.5.0; extra == 'docs'
Requires-Dist: sphinx-tabs>=3.0.0; extra == 'docs'
Requires-Dist: sphinx-togglebutton>=0.3.0; extra == 'docs'
Requires-Dist: sphinx>=4.0; extra == 'docs'
Requires-Dist: sphinxext-opengraph>=0.9.0; extra == 'docs'
Provides-Extra: docs-build
Requires-Dist: docutils>=0.17; extra == 'docs-build'
Requires-Dist: furo>=2023.3.27; extra == 'docs-build'
Requires-Dist: jupyter>=1.0; extra == 'docs-build'
Requires-Dist: linkify-it-py>=2.0; extra == 'docs-build'
Requires-Dist: markdown-it-py>=2.0; extra == 'docs-build'
Requires-Dist: mdit-py-plugins>=0.3.0; extra == 'docs-build'
Requires-Dist: myst-nb>=0.13.0; extra == 'docs-build'
Requires-Dist: myst-parser>=0.15; extra == 'docs-build'
Requires-Dist: nbconvert>=6.0; extra == 'docs-build'
Requires-Dist: sphinx-autoapi>=2.0; extra == 'docs-build'
Requires-Dist: sphinx-book-theme>=1.0.0; extra == 'docs-build'
Requires-Dist: sphinx-copybutton>=0.5.0; extra == 'docs-build'
Requires-Dist: sphinx-design>=0.3.0; extra == 'docs-build'
Requires-Dist: sphinx-multiversion>=0.2.4; extra == 'docs-build'
Requires-Dist: sphinx-sitemap>=2.5.0; extra == 'docs-build'
Requires-Dist: sphinx-tabs>=3.0.0; extra == 'docs-build'
Requires-Dist: sphinx-togglebutton>=0.3.0; extra == 'docs-build'
Requires-Dist: sphinx>=4.0; extra == 'docs-build'
Requires-Dist: sphinxext-opengraph>=0.9.0; extra == 'docs-build'
Provides-Extra: docs-serve
Requires-Dist: livereload>=2.6.3; extra == 'docs-serve'
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == 'docs-serve'
Requires-Dist: watchdog>=2.1.0; extra == 'docs-serve'
Provides-Extra: notebooks
Requires-Dist: ipykernel>=6.0; extra == 'notebooks'
Requires-Dist: jupyter-client>=7.0; extra == 'notebooks'
Requires-Dist: nbclient>=0.8; extra == 'notebooks'
Requires-Dist: nbconvert>=7.0; extra == 'notebooks'
Requires-Dist: statsmodels>=0.13; extra == 'notebooks'
Provides-Extra: quality
Requires-Dist: bandit>=1.7.0; extra == 'quality'
Requires-Dist: black>=22.0; extra == 'quality'
Requires-Dist: flake8>=4.0; extra == 'quality'
Requires-Dist: isort>=5.10; extra == 'quality'
Requires-Dist: mypy>=0.910; extra == 'quality'
Requires-Dist: pandas-stubs; extra == 'quality'
Requires-Dist: pre-commit>=2.15; extra == 'quality'
Requires-Dist: pylint>=2.12.0; extra == 'quality'
Requires-Dist: safety>=2.0.0; extra == 'quality'
Requires-Dist: types-requests; extra == 'quality'
Provides-Extra: test
Requires-Dist: coverage[toml]>=6.0; extra == 'test'
Requires-Dist: pytest-cov>=2.10; extra == 'test'
Requires-Dist: pytest-mock>=3.6.1; extra == 'test'
Requires-Dist: pytest-timeout>=2.1.0; extra == 'test'
Requires-Dist: pytest-xdist>=2.5.0; extra == 'test'
Requires-Dist: pytest>=6.0; extra == 'test'
Requires-Dist: tox>=3.24.0; extra == 'test'
Description-Content-Type: text/markdown

# Varunayan

<p align="center">
  <img src="https://raw.githubusercontent.com/saketlab/varunayan/main/python/docs/_static/varunayan_logo.png" alt="Varunayan Logo" width="200"/>
</p>

Python package for downloading and processing climate data from ERA5, IMD, HadEX3, and CRU TS. Includes heat stress index calculations (UTCI, WBGT, Heat Index, Humidex) and country-level temperature aggregation.

Also available in R: [varunayan for R](https://varunayan.saketlab.org/R/)

## Data sources

| Source | Variables | Resolution | Coverage |
|--------|-----------|------------|----------|
| [ERA5](https://cds.climate.copernicus.eu/) | 100+ (temperature, precipitation, wind, radiation, etc.) | 0.25 deg, hourly to monthly | 1940-present, global |
| [IMD](https://www.imdpune.gov.in/) | Rainfall, Tmax, Tmin | 0.25/1.0 deg, daily | 1901-present, India |
| [HadEX3](https://www.metoffice.gov.uk/hadobs/hadex3/) | 29 ETCCDI climate extremes | 1.25x1.875 deg, annual/monthly | 1901-2018, global |
| [CRU TS v4.07](https://crudata.uea.ac.uk/cru/data/hrg/) | tmp, tmx, tmn, pre, vap, cld, wet, frs, dtr, pet | 0.5 deg, monthly | 1901-2022, land |

## Installation

```bash
pip install varunayan
```

For development:

```bash
pip install -e ".[dev]"
```

## Quick start

### ERA5 (requires CDS account)

```python
import varunayan

# Bounding box: one row for each grid cell, time step and variable
df = varunayan.era5ify_bbox(
    request_id="mumbai",
    variables=["2m_temperature", "total_precipitation"],
    start_date="2024-01-01",
    end_date="2024-01-31",
    north=19.2,
    south=18.9,
    east=72.9,
    west=72.8,
    frequency="daily",
)
# Columns: datetime, latitude, longitude, variable, value
# Units: temperature in °C, precipitation in mm (convert_units=True)

# Regional mean for each day, weighted by cos(latitude)
daily = varunayan.spatial_mean(df, "value", by=["variable", "datetime"])

# Single point: the nearest grid cell
df = varunayan.era5ify_point(
    "shimla",
    ["2m_temperature"],
    "2024-01-01",
    "2024-01-07",
    lat=31.1,
    lon=77.2,
)
```

### IMD gridded data (no credentials needed)

```python
# Rainfall for a bounding box
rain = varunayan.imd_rainfall_bbox(
    "maharashtra",
    start_year=2020,
    end_year=2023,
    north=22,
    south=16,
    east=80,
    west=73,
    resolution=0.25,
    frequency="monthly",
)

# Temperature with GeoJSON filter
tmax = varunayan.imd_temperature_geojson(
    "karnataka",
    start_year=2022,
    end_year=2023,
    geojson_file="karnataka.geojson",
    var_type="tmax",
)

# IMD station lookup
stations = varunayan.get_imd_stations()
```

### HadEX3 climate extremes

```python
# Hottest-day trend over India
txx = varunayan.hadex3_bbox(
    "TXx", start_year=1951, end_year=2018, north=38, south=6, east=98, west=68
)

# All 29 ETCCDI indices
varunayan.list_hadex3_indices()
```

### CRU TS monthly climate grids

```python
# Mean temperature for a bounding box
tmp = varunayan.cru_ts_bbox(
    "tmp", start_year=2000, end_year=2020, north=38, south=6, east=98, west=68
)

# All 10 variables with ERA5/HadEX3 equivalents
varunayan.list_cru_ts_variables()
```

### Country-level temperature

```python
# Cosine-latitude weighted national average
df = varunayan.get_era5_country_temperature(
    "India", "2000-01-01", "2023-12-31", variables=["mean", "max", "min"]
)
```

### Heat stress indices

```python
# Individual indices
utci = varunayan.utci(temp_c=35, wind_speed=2, dewpoint_c=25, tmrt=50)
hi = varunayan.heat_index(temp_c=35, rh=60)
wbgt = varunayan.wbgt_simple(temp_c=35, dewpoint_c=25)

# RH, wet bulb, Heat Index, WBGT and Humidex as one DataFrame
indices = varunayan.calc_heat_indices(temp_c=35, dewpoint_c=25)

# UTCI sparse Legendre polynomial (Roman et al. 2025, wider wind range)
utci_s = varunayan.utci_sparse(temp_c=35, tmrt=50, wind_speed=2, rh=60)

# Risk categories
varunayan.heat_index_risk_category(hi)
varunayan.utci_category(utci)
```

### Analysis and plots

```python
rain = varunayan.era5ify_bbox(
    "kerala_rain",
    ["total_precipitation"],
    "1991-01-01",
    "2020-12-31",
    north=12.8,
    south=8.2,
    east=77.4,
    west=74.9,
    frequency="monthly",
)
monthly = varunayan.spatial_mean(rain, "value", by=["year", "month"])
monthly["anomaly"] = varunayan.anomaly(monthly, "value", baseline=(1991, 2020))
varunayan.plot_series(monthly, x="date", y="anomaly")
```

See the [API reference](https://varunayan.saketlab.org/python/api_reference/index.html) for `compare`, `cross_correlation`, `seasonal_cycle`, `peak_month`, `regrid`, `plot_map` and the other functions.

## CLI

```bash
varunayan bbox --request-id "test" --variables "temperature,relative_humidity" \
  --start "2024-01-01" --end "2024-01-15" \
  --north 30 --south 20 --east 80 --west 70 \
  --dataset-type pressure --pressure-levels "1000,900" \
  --freq daily --res 0.25
```

Use `varunayan geojson --geojson FILE [--level union|feature]` for a GeoJSON region and `varunayan point --lat LAT --lon LON` for a point. Output goes to `{request_id}_output/`.

## Documentation

[varunayan.saketlab.org/python](https://varunayan.saketlab.org/python/)

## Contributing

Contributions welcome via pull request.

## License

MIT License. See [LICENSE](LICENSE).
