MODIS fire

R-bloggers 2025-11-16

[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.

A photo of a forest fire

Eagle Creek Fire – CC-BY-NC-SA by Curtis Gregory Perry

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 backgroundworld <- ne_countries(scale = 10) |>   st_make_valid() |>   st_wrap_dateline()# build the griddggs <- 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 IDmodis <- 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 daymodis_cells <- modis |>   count(seqnum, YYYYMMDD) |>   left_join(hex,            join_by(seqnum)) # prepare the breaksbreaks <- classIntervals(modis_cells$n, n = 4, style = "kmeans")# create a PNG map for one daycreate_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)}# Iteratemodis |>   distinct(YYYYMMDD) |>   pull(YYYYMMDD) |>   walk(create_map, .progress = TRUE)# generate the videosystem(glue('ffmpeg -framerate 24 -pattern_type glob -i "img/fire*.png" \\            -c:v libx264 -pix_fmt yuv420p modis.mp4'))
Figure 1: Animation of global fires in 2024 using MODIS data
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.
Continue reading: MODIS fire