--- title: "Introduction to vayuayan" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introduction to vayuayan} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN", "false")), "true") # network chunks need NOT_CRAN and a reachable CPCB feed CPCB_OK <- NOT_CRAN && tryCatch( { httr::status_code(httr::HEAD( "https://airquality.cpcb.gov.in/caaqms/iit_rss_feed_with_coordinates", httr::timeout(5) )) < 400 }, error = function(e) FALSE ) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5, eval = CPCB_OK ) ``` # Introduction **vayuayan** (वायुअयन) is an R package that downloads and analyzes air quality data. The data comes from WUSTL ACAG satellite PM2.5 (global) and the CPCB and OAQ monitoring networks (India). The name contains two Sanskrit words: - Vayu (वायु) means wind or air. - Ayan (अयन) means path, journey or movement. Together, "Vayuayan" means "the path of wind." ## Installation ```{r install, eval=FALSE} devtools::install_github("saketlab/vayuayan", subdir = "R") ``` ## Data sources The package gives access to three data sources: 1. The WUSTL ACAG satellite PM2.5 data from Washington University - Global coverage at 0.01 degree (approximately 1 km) resolution - Monthly and annual data (1998 to 2024, product V6.GL.03) 2. The CPCB (Central Pollution Control Board) monitoring network in India - Historical and real-time AQI data - Station-level and city-level data 3. The OAQ (Open Air Quality) low-cost sensor networks in India - Many providers, for example Airnet - Daily, monthly, and annual data ## Quick start ```{r quickstart, eval = TRUE} library(vayuayan) library(dplyr) vayuayan_welcome() ``` # Historical AQI data The `cpcb_` functions give access to historical air quality data from the Central Pollution Control Board. ## Available data The lists of states, cities and stations come from a CPCB station directory in the package. Thus, you can use these calls offline. ```{r historical_explore, eval = TRUE} states <- cpcb_get_state_list() head(states) cities <- cpcb_get_city_list("Maharashtra") head(cities) stations <- cpcb_get_station_list("Mumbai") head(stations) ``` ### Station coordinates ```{r add_coords, eval = TRUE} delhi_stations <- cpcb_add_coords(cpcb_get_station_list("Delhi")) head(delhi_stations) ``` ## Daily data in long format `cpcb_city_daily()` downloads the CPCB daily file for each city. The function returns one row for each day. The package caches the files. Thus, subsequent calls read the files from disk. ```{r city_daily} daily <- cpcb_city_daily(c("Delhi", "Mumbai"), 2024, cache_dir = tempdir()) daily %>% group_by(city, month) %>% summarise(pm25 = mean(value), .groups = "drop") ``` `cpcb_station_daily()` does the same for stations: ```{r station_daily} station_daily <- cpcb_station_daily( head(delhi_stations$value, 3), 2025, cache_dir = tempdir() ) count(station_daily, station_id) ``` `cpcb_download_city_data()` and `cpcb_download_station_data()` save the raw CPCB sheet. Use these functions to get the file. # Live AQI data The live readings come from the public station feed. The feed contains only the data of the last hour. ```{r live_aqi} nearest <- cpcb_get_nearest_station(coords = c(19.0760, 72.8777)) nearest aqi_data <- cpcb_get_live_aqi_data(station_id = nearest$station_id) aqi_data$metrics ``` Without arguments, `cpcb_get_live_aqi_data()` finds the station nearest to your IP location. ## Station summaries `stations_to_dataframe()` changes the live feed into one row for each station. Each row also has an AQI category. ```{r live_table} live <- stations_to_dataframe(cpcb_get_all_india()) live %>% group_by(state_id) %>% summarise( stations = n(), live = sum(live), avg_aqi = mean(avg_aqi, na.rm = TRUE), .groups = "drop" ) %>% arrange(desc(stations)) %>% head(10) count(live, aqi_category, sort = TRUE) ``` ```{r live_map} library(ggplot2) library(sf) aqi_colors <- c( "Good" = "green", "Satisfactory" = "lightgreen", "Moderate" = "yellow", "Poor" = "orange", "Very Poor" = "red", "Severe" = "darkred", "No Data" = "grey70" ) live %>% filter(live) %>% st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>% ggplot() + geom_sf(aes(color = aqi_category), size = 2, alpha = 0.6) + scale_color_manual(values = aqi_colors) + labs(title = "Live CPCB monitoring stations", color = "AQI category") + theme_minimal() ``` # PM2.5 satellite data The `pm25_` functions process satellite PM2.5 data from WUSTL ACAG (product V6.GL.03 on the AWS Open Data registry). The Asia subset (`region = "AS"`) includes India. The file of this subset is smaller than the global file. The package caches the files in `tools::R_user_dir("vayuayan", "cache")`. The vignette build does not run these chunks. ```{r pm25_setup, eval = FALSE} pm25_nc <- pm25_download_netcdf(2023, 11, region = "AS") delhi <- india_boundary(state = "Delhi") ``` ## Regional statistics ```{r pm25_stats, eval = FALSE} pm25_get_stats( geojson_file = "https://geo.bharatviz.org/geojsons/cities/delhi.geojson", nc_file = pm25_nc ) pm25_get_stats( geojson_file = "https://geo.bharatviz.org/geojsons/districts/India_LGD_districts.geojson", nc_file = pm25_nc, group_by = "state_name" ) ``` ## Maps ```{r pm25_map, eval = FALSE} r <- pm25_load_netcdf_bbox(pm25_nc, delhi, var = "PM25", mask = TRUE) pm25_map(r, delhi, title = "Delhi, November 2023") ``` ## Cache management ```{r pm25_cache, eval = FALSE} pm25_list_cached_files() pm25_clear_cache() ``` # Utility functions ```{r utilities, eval = TRUE} clean_station_name("Dr. Karni Singh Shooting Range, Delhi - DPCC") get_aqi_categories(c(42, 180, 320)) # Mumbai to Delhi, in km haversine_distance(19.0760, 72.8777, 28.7041, 77.1025) ```