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:
Together, “Vayuayan” means “the path of wind.”
The package gives access to three data sources:
library(vayuayan)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
vayuayan_welcome()
#>
#> ── Vayuayan - Air quality data analysis ────────────────────────────────────────
#> Version 0.3.0
#>
#> ── Available functions: ──
#>
#> • cpcb_get_state_list(), cpcb_get_city_list() - Historical AQI data from CPCB
#> • cpcb_get_live_aqi_data(), cpcb_get_nearest_station() - Real-time AQI
#> monitoring
#> • pm25_get_stats(), pm25_download_netcdf() - Satellite PM2.5 data processing
#> • oaq_session(), oaq_get_stations_latest() - OAQ open air quality platform
#>
#> ── Quick start: ──
#>
#> states <- cpcb_get_state_list()
#> cities <- cpcb_get_city_list('Maharashtra')
#>
#> location <- cpcb_get_system_location()
#> aqi <- cpcb_get_live_aqi_data()
#>
#> stats <- pm25_get_stats('region.geojson', 2023, 11, region = 'AS')The cpcb_ functions give access to historical air
quality data from the Central Pollution Control Board.
The lists of states, cities and stations come from a CPCB station directory in the package. Thus, you can use these calls offline.
states <- cpcb_get_state_list()
head(states)
#> [1] "Andaman And Nicobar" "Andhra Pradesh" "Arunachal Pradesh"
#> [4] "Assam" "Bihar" "Chandigarh"
cities <- cpcb_get_city_list("Maharashtra")
head(cities)
#> [1] "Ahmednagar" "Akola" "Ambernath" "Amravati" "Aurangabad"
#> [6] "Badlapur"
stations <- cpcb_get_station_list("Mumbai")
head(stations)
#> label value
#> 1 Bandra Kurla Complex, Mumbai - IITM site_5392
#> 2 Bandra Kurla Complex, Mumbai - MPCB site_5810
#> 3 Bandra, Mumbai - MPCB site_168
#> 4 Borivali East, Mumbai - IITM site_5400
#> 5 Borivali East, Mumbai - MPCB site_5113
#> 6 Byculla, Mumbai - BMC site_5960delhi_stations <- cpcb_add_coords(cpcb_get_station_list("Delhi"))
#> Done: 59/59 stations have coordinates
head(delhi_stations)
#> label value lat lon
#> 1 Alipur, Delhi - DPCC site_5024 28.81533 77.15301
#> 2 Anand Vihar, Delhi - DPCC site_301 28.64762 77.31581
#> 3 Ashok Vihar, Delhi - DPCC site_1420 28.69538 77.18166
#> 4 Aya Nagar, Delhi - IITM site_108 28.47069 77.10994
#> 5 Badarpur,Delhi-DPCC site_100409 28.51330 77.32634
#> 6 Bawana, Delhi - DPCC site_1560 28.77620 77.05107cpcb_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.
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:
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.
The live readings come from the public station feed. The feed contains only the data of the last hour.
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$metricsWithout arguments, cpcb_get_live_aqi_data() finds the
station nearest to your IP location.
stations_to_dataframe() changes the live feed into one
row for each station. Each row also has an AQI category.
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)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()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.