DEV Community

Cover image for Visualize 🔥 active fires 🔥 around the world 🌍 with Javascript
Anthony Lagrede
Anthony Lagrede

Posted on • Updated on

Visualize 🔥 active fires 🔥 around the world 🌍 with Javascript

Originally posted on my blog

What we will learn?

In this article, we will see how to use open data with Plotlyjs and Streams through Znote in Javascript to explore active fire data around the world.

Active fire data

Thanks to the NASA which make available fires locations and Thermal anomalies with the MODIS system (Moderate-Resolution Imaging Spectroradiometer) onboarded in their two satellites (Aqua and Terra) it is possible to visualize how fires are distributed across the planet.

Where get data?

Last active fire data is available here.

If you want explore the history, it is also possible to ask archive here.

Dataset description

We start previewing the dataset to discover the available columns via a simple print with Danfojs

const df = await dfd.readCSV("https://firms.modaps.eosdis.nasa.gov/data/active_fire/modis-c6.1/csv/MODIS_C6_1_Global_7d.csv");
print(df); // or df.ctypes to list all columns
Enter fullscreen mode Exit fullscreen mode

Table of active fires

Full dataset description is here

World map of active fires

Each point is a new fire declared per day. It is shocking to see the number of new fires starting every day 😨

The map below scrolls through the months of July and August 2022
Summer 2022 world

How build this map?

const summer2022 = "/Users/alagrede/Desktop/modis-active-fires-7d.csv";

const content = _fs.readFileSync(summer2022, 'utf8'); // read data file

function show(date) {
    // get lat/long fields for date given
    const latLong = content.split('\n')
        .filter(r=>String(r.split(",")[5]).startsWith(date))
        .map(r => [r.split(",")[0], r.split(",")[1]]) // lat/long
    latLong.shift(); // remove header

    var data = [{
        type: 'scattergeo',
        lon: latLong.map(r=>r[1]),
        lat: latLong.map(r=>r[0]),
        marker: {size: 2, color:'red'}, // draw fires
    }];

    var layout = {
        geo: {
            scope: 'world',
            resolution: 50,
            showland: true,
            showocean: true,
        },
        title: date,
    };
    Plotly.newPlot(el, data, layout);
}

// list days between 2 dates (functions used are described at the end of the article)
var daylist = await getDaysArray(new Date("2022-08-18"), new Date("2022-08-24"));

// loop over days
for(const day of daylist) {
    show(day);
    await sleep(500);
}
Enter fullscreen mode Exit fullscreen mode

Refresh data (last 7d) ℹ️

We can now create a function to refresh the data and store it in a file. The last 7d file is directly available online.

const r = await fetch('https://firms.modaps.eosdis.nasa.gov/data/active_fire/modis-c6.1/csv/MODIS_C6_1_Global_7d.csv')
const content = await r.text();
_fs.writeFileSync('/Users/alagrede/Desktop/modis-active-fires-7d.csv', content);
Enter fullscreen mode Exit fullscreen mode

Focus on a country

You can now focus on a specific country of your choice by selecting a center point and changing the map scope.

To find a specific geographical position, open Google map, select a point then copy/paste the latitude/longitude.

You could find the Plotlyjs API description here

var layout = {
    geo: {
        center: {lat: -46.449031, lon: 2.521705}, // France
        projection: {scale: 1.5}, // zoom
        scope: 'europe', // "africa" | "asia" | "europe" | "north america" | "south america" | "usa" | "world"
        resolution: 50,
        showland: true,
        showocean: true,
    },
    title: date,
};
Plotly.newPlot(el, data, layout);
Enter fullscreen mode Exit fullscreen mode

France

Summer 2022 France

As suggested above, you can add a slider to navigate manually in time

Plotly.newPlot(el+"-myGraph", data, layout);

// add a slider control (min - max - onChange callback)
const slider = await createSlider(0, daylist.length - 1, async function() {
   show(daylist[slider.value]);
   await sleep(200);
});

htmlEl.innerHTML=""; // reset result div
htmlEl.appendChild(slider); // add html slider
var graph = createElement("div"); // add the map into a div
graph.id = el+"-myGraph"; // plotly html id
htmlEl.appendChild(graph); // append map
show(daylist[0]);
Enter fullscreen mode Exit fullscreen mode

Evolution of fires in France since 2000

Now that we know where the fires are, it might be interesting to see how the number of fires has changed since 2000.
This table reveals exceptional fire activity in 2003 reported in the media due to a massive heat wave in Europe.

2019 a new record
Forest fires: in France, in the middle of summer, the area burned is greater than in all of 2019

2022 also a new record...
France's unprecedented summer of wildfires, in maps and graphs

Summer 2022 fires count

// All France fires count (make a ticket to ask history of fires)
const allfires = "/Users/alagrede/Desktop/fire_archive_M-C61_290304.csv";
const content = _fs.readFileSync(allfires, 'utf8');
const activeFires = content.split('\n');
activeFires.shift();
const count = activeFires
    // map to month
    .map(r=>String(r.split(",")[5]).slice(0,7)) // date field like 2008-08
    // map to year
    //.map(r=>String(r.split(",")[5]).slice(0,4)) // date field like 2008
    // group by
    .reduce((total, value) => {
        total[value] = (total[value] || 0) + 1;
        return total;
    }, {});

const data = [{
  y: Object.values(count),
  x: Object.keys(count),
  type: 'scatter'
}];

const layout = {
  title: "Evolution of active fires",
  height: 400,
  width: 500
}

Plotly.newPlot(el, data, layout);
Enter fullscreen mode Exit fullscreen mode

Temperature anomalies

On the temperature side, there is a clear upward trend in temperatures since the 2000s.

This partly explains the increase in fires and why records are frequently broken.

EU temp ano

const r = await fetch('https://www.ncei.noaa.gov/access/monitoring/climate-at-a-glance/global/time-series/globe/land_ocean/ytd/12/1880-2016.json')
const json = await r.json();
//printJSON(json);
const result = Object.entries(json.data).map(year => [year[0], year[1]]);

const data = [{
  y: result.map(r=>r[1]),
  x: result.map(r=>r[0]),
  type: 'scatter'
}];

const layout = {
  title: "World temperature anomalies",
  height: 400,
  width: 500
}

Plotly.newPlot(el, data, layout);
Enter fullscreen mode Exit fullscreen mode

World

Unsurprisingly, the world is following the same upward trend.

World temp ano

Others continents

Compared to Europe, the number of new fires declared on the African and South American continents is literally frightening... 😅

South america august 2022 map

Africa august 2022 map

functions used in scripts

async function getDaysArray(start, end) {
    for(var arr=[],dt=new Date(start); dt<=new Date(end); dt.setDate(dt.getDate()+1)){
        arr.push(new Date(dt).toISOString().slice(0,10));
    }
    return arr;
}
async function sleep(time) {
  await new Promise(r => setTimeout(r, time));
}
async function createSlider(min, max, callback) {
  var slider = createElement('input');
  slider.type = 'range';
  slider.min = min;
  slider.max = max;
  slider.value = 0;
  slider.step = 1;
  slider.style.marginLeft = "0px"
  slider.style.width = "100%"
  slider.addEventListener('input', callback, false);
  return slider;
}
Enter fullscreen mode Exit fullscreen mode

Go further

For those who want to take this example further, the entire Javascript notebook is available in my Github repo.

To facilitate the use of this data, this example was made with the interactive Znote app.

znote screenshot

Top comments (16)

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Are we just going to ignore the suspicious cluster of data points around the area of Ukraine?

Collapse
 
alagrede profile image
Anthony Lagrede

Ahah 🤣 it would be cool to be able to detect the conflict from this data. I just tried to do the visualization since 01-2020 above the Ukraine but it's hard to deduce something from it...

Ukraine since 2020

Ukraine fires count

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I mean, this exact data has been used to deduce information about the war, so I instantly went looking for that 😅

But yea, at the point when the invasion started you can clearly see a lot of clustering around the occupied areas, specially towards the later stages of the war when the shift to heavy usage of artillery and slow advance happened.

Thread Thread
 
alagrede profile image
Anthony Lagrede

So cool! Thanks for sharing this information 😊.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇

Nice work here! Thank you for sharing 😁

Collapse
 
alagrede profile image
Anthony Lagrede

Thanks ❤️

Collapse
 
scchip profile image
Chip James

Fascinating project on several fronts. Thx for sharing!

Collapse
 
alagrede profile image
Anthony Lagrede

Thanks James 😊

Collapse
 
bobbyiliev profile image
Bobby Iliev

This is a very interesting project! Thanks for sharing it!

Collapse
 
alagrede profile image
Anthony Lagrede

Thanks 😊

Collapse
 
thesanjeevsharma profile image
Sanjeev Sharma

This is awesome! Thanks for sharing.

Collapse
 
alagrede profile image
Anthony Lagrede

🙏❤️

Collapse
 
kjaymiller profile image
Jay Miller • Edited

Awesome! I've been working on a similar post that comes out today! Glad to see we have people working on it in multiple languages and ways.

I wound up using ArcGIS and Python and I was thinking about switching to FIRMS instead. It seems pretty straightforward to use. 🤔

Collapse
 
qasimaligondal2 profile image
Qasim Ali Gondal

This might help too click

Collapse
 
qasimaligondal2 profile image
Qasim Ali Gondal

This might help too

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more