MODIS fire
[This article was first published on r.iresmi.net, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Day 15 of 30DayMapChallenge: « Fire » (previously).
An animation of global fires in 2024 using MODIS data.
library(dggridR) library(dplyr) library(readr) library(ggplot2) library(purrr) library(sf) library(rnaturalearth) library(glue) library(classInt)
Data
See the docs. You can use a client like Filezilla to download the data.
- SFTP:
fuoco.geog.umd.edu - Login / Password (as of time of writing):
fire/burnt
Get all year 2024 files available in /data/MODIS/C61/MCD14ML.
We’ll use binning on a 250 km discrete global grid.
# countries background
world <- ne_countries(scale = 10) |>
st_make_valid() |>
st_wrap_dateline()
# build the grid
dggs <- dgconstruct(spacing = 250)
hex <- dggs |>
dgshptogrid(world, cellsize = 0.5) |>
st_make_valid() |>
st_wrap_dateline() |>
st_filter(world) |>
select(seqnum)
# read all MODIS files and find their grid cell ID
modis <- dir("~/data/modis/", full.names = TRUE) |>
read_fwf(
skip = 1,
col_types = cols("YYYYMMDD" = col_date(format = "%Y%m%d")),
fwf_positions(
c(1, 10, 15, 17, 26, 36, 42, 48, 53, 61, 65, 68),
c(9, 14, 16, 25, 35, 41, 47, 52, 60, 64, 67, 69),
c("YYYYMMDD", "HHMM", "sat", "lat", "lon", "T21", "T31", "sample", "FRP",
"conf", "type", "dn")),
num_threads = 10) |>
mutate(seqnum = dgGEO_to_SEQNUM(dggs, lon, lat)$seqnum)
Map
We generate one PNG file per day and create the video with a call to a system-installed ffmpeg.
# compute the number of fires for each cell and each day
modis_cells <- modis |>
count(seqnum, YYYYMMDD) |>
left_join(hex,
join_by(seqnum))
# prepare the breaks
breaks <- classIntervals(modis_cells$n, n = 4, style = "kmeans")
# create a PNG map for one day
create_map <- function(d) {
p <- modis_cells |>
filter(YYYYMMDD == d) |>
left_join(hex,
join_by(seqnum)) |>
st_sf() |>
ggplot() +
geom_sf(data = world, fill = "#1a3853", color = "#002240") +
geom_sf(aes(fill = n, color = n)) +
scale_fill_viridis_c(aesthetics = c("colour", "fill"),
breaks = round(breaks$brks),
transform = "log",
name = "Fires\nper cell\n(log\nscale)",
option = "B",
limits = c(1, max(modis_cells$seqnum))) +
coord_sf(crs = "EPSG:8857") +
labs(title = "MODIS fire detection",
subtitle = d,
caption = glue("MODIS - Global Monthly Fire Location \\
Product (MCD14ML)
https://r.iresmi.net/ - {Sys.Date()}")) +
theme_void() +
theme(text = element_text(family = "Ubuntu",
color = "white"),
plot.margin = margin(2, 2, 2, 5, unit = "mm"),
plot.caption = element_text(size = 7,
color = "#777"))
ggsave(glue("img/fire_{d}.png"), p, bg = "#002240", width = 9, height = 5)
}
# Iterate
modis |>
distinct(YYYYMMDD) |>
pull(YYYYMMDD) |>
walk(create_map, .progress = TRUE)
# generate the video
system(glue('ffmpeg -framerate 24 -pattern_type glob -i "img/fire*.png" \\
-c:v libx264 -pix_fmt yuv420p modis.mp4'))
To leave a comment for the author, please follow the link and comment on their blog: r.iresmi.net.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
