Brazil’s National Institute of Meteorology (INMET) runs a network of
more than 600 automatic weather stations that record hourly
observations. Historical data are published as one ZIP archive per year,
holding one CSV file per station, with formats that changed several
times over the years. rmet downloads and caches those
archives, reads them into consistent data frames, and summarises the
hourly data into daily values.
inmet_stations() returns the official catalogue of
automatic stations. It is downloaded from INMET once and cached; when
INMET cannot be reached, a snapshot bundled with the package is used
instead.
rs <- inmet_stations(state = "RS", status = "Operante", source = "bundled")
head(rs[, c("station_code", "station_name", "latitude", "longitude", "start_date")])
#> station_code station_name latitude longitude start_date
#> 1 B843 AJURICABA -28.22083 -53.67361 2025-12-02
#> 2 B847 ALEGRETE (MARONNA) -29.82139 -55.88722 2026-02-04
#> 3 A827 BAGE -31.34778 -54.01333 2007-01-04
#> 4 B827 BAGE - CENTRO -31.30556 -54.01333 2025-08-01
#> 5 A840 BENTO GONCALVES -29.16444 -51.53417 2006-12-01
#> 6 B857 BOM JESUS - SANTO INACIO -28.51389 -50.16778 2026-03-03(source = "bundled" keeps this vignette reproducible
offline. In your own code, leave source at its default to
get the current catalogue.)
To find the stations closest to a place, use
inmet_nearest():
inmet_nearest(latitude = -30.03, longitude = -51.23, n = 3, source = "bundled")[
, c("station_code", "station_name", "distance_km", "start_date")
]
#> station_code station_name distance_km start_date
#> 1 A801 PORTO ALEGRE - JARDIM BOTANICO 5.933358 2000-09-22
#> 2 B808 CACHOEIRINHA 13.427377 2025-02-18
#> 3 B825 PORTO ALEGRE - BELEM NOVO 18.056243 2025-05-01Station A801 (Porto Alegre - Jardim Botanico) has
been operating since September 2000. The catalogue also gives each
station’s local time_zone.
With the sf package installed,
inmet_as_sf() turns the catalogue (or any result with
coordinates) into spatial points:
Operating automatic stations in Rio Grande do Sul, by elevation.
inmet_get() downloads any missing archives and reads the
stations you ask for:
poa <- inmet_get(
years = 2023,
stations = "A801",
variables = c("temp_dry_c", "temp_max_prev_c", "temp_min_prev_c", "precip_mm")
)The first call downloads the archive for each year, around 100 MB for
recent years; later calls read from the cache. For the current and the
previous year, rmet also checks whether INMET has published
a newer version of the archive (INMET keeps adding data to them) and
downloads it if so.
The package ships the result of
inmet_get(2023, stations = "A801") as
rmet_example, which the rest of this vignette uses:
dim(rmet_example)
#> [1] 8663 25
head(rmet_example[, c("datetime", "temp_dry_c", "temp_max_prev_c", "precip_mm")])
#> datetime temp_dry_c temp_max_prev_c precip_mm
#> 1 2023-01-01 00:00:00 26.5 27.7 0
#> 2 2023-01-01 01:00:00 26.8 26.9 0
#> 3 2023-01-01 02:00:00 26.3 26.9 0
#> 4 2023-01-01 03:00:00 25.2 26.6 0
#> 5 2023-01-01 04:00:00 24.1 25.2 0
#> 6 2023-01-01 05:00:00 23.1 24.1 0Timestamps are in UTC, as in the source files, and
each row describes the hour ending at datetime.
Pass tz = "America/Sao_Paulo" (or any other Olson name) to
inmet_get() or inmet_read() to display them in
local time.
INMET publishes these observations as raw data.
inmet_qc() flags values that are physically impossible,
internally inconsistent, isolated spikes, or stuck at the same value,
and inmet_completeness() shows how many valid hours each
month has:
checked <- inmet_qc(rmet_example)
#> Flagged 0 value(s) in 0 variable(s). See attr(x, "qc_summary").
head(inmet_completeness(checked, variables = c("temp_dry_c", "precip_mm")), 3)
#> station_code period hours_expected hours_present temp_dry_c precip_mm
#> 1 A801 2023-01 744 734 98.7 98.7
#> 2 A801 2023-02 672 666 99.1 99.1
#> 3 A801 2023-03 744 734 98.7 98.7Most analyses need daily values. inmet_daily() assigns
each hour to the station’s local day, ignores values flagged by
inmet_qc(), and requires a minimum number of valid hours
per day (20 by default):
daily <- inmet_daily(checked)
head(daily[, c("date", "n_hours", "temp_max_c", "temp_min_c", "precip_mm")])
#> date n_hours temp_max_c temp_min_c precip_mm
#> 1 2022-12-31 4 NA NA NA
#> 2 2023-01-01 24 37.0 20.8 0.0
#> 3 2023-01-02 24 33.6 23.6 10.2
#> 4 2023-01-03 24 30.0 20.8 0.0
#> 5 2023-01-04 24 32.9 20.0 0.0
#> 6 2023-01-05 24 33.0 19.3 0.0The first row is 31 December 2022: the records stamped 00:00 to 03:00
UTC on 1 January 2023 describe the last hours of 31 December in Porto
Alegre. With only four hours of data that day’s values are
NA. See
vignette("daily-data", package = "rmet") for the details
and why as.Date(datetime) gives the wrong days.
daily <- daily[format(daily$date, "%Y") == "2023", ]
oldpar <- par(mar = c(4, 4.5, 2, 1))
plot(daily$date, daily$temp_max_c, type = "l", col = "#C0392B",
ylim = range(daily$temp_min_c, daily$temp_max_c, na.rm = TRUE),
xlab = "", ylab = "Temperature (°C)")
lines(daily$date, daily$temp_min_c, col = "#2471A3")
legend("topright", c("Maximum", "Minimum"), col = c("#C0392B", "#2471A3"),
lwd = 1, bty = "n")Daily maximum and minimum temperature at Porto Alegre (A801), 2023.
monthly <- tapply(daily$precip_mm, format(daily$date, "%m"), sum, na.rm = TRUE)
oldpar <- par(mar = c(4, 4.5, 2, 1))
barplot(monthly, names.arg = month.abb, col = "#5DADE2", border = NA,
ylab = "Precipitation (mm)")Monthly precipitation at Porto Alegre (A801), 2023.
Days with missing precipitation hours are NA in
daily$precip_mm, so these monthly totals are lower bounds
when data are missing; check n_hours.
inmet_get() combines three steps that can also be run
separately:
inmet_download(2020:2023) # download (or update) archives
inmet_cache_status() # what is cached, and how large
weather <- inmet_read(
years = 2020:2023,
stations = c("A801", "A832"),
start_date = "2020-06-01",
end_date = "2023-08-31",
variables = c("temp_dry_c", "precip_mm")
)Reading only the stations and variables you need keeps memory use
low: one year of every station is about four million rows.
inmet_extract() copies the original CSV files out of the
archives if you need them for other software, and
inmet_cache_clear() frees disk space.
INMET publishes automatic-station data as raw measurements without
consistency checks. inmet_qc() catches gross errors, but it
cannot judge every value. Apply further checks appropriate to your
analysis, such as comparison with neighbouring stations, before drawing
conclusions.
The variables returned and their units are listed in
?inmet_read; daily variables are described in
?inmet_daily.