Skip to content

Commit

Permalink
feat(sentences): update dashboard sentences for natural forest
Browse files Browse the repository at this point in the history
  • Loading branch information
wri7tno committed Nov 12, 2024
1 parent dc95e82 commit a0c1203
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 112 deletions.
102 changes: 102 additions & 0 deletions services/analysis-cached.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const SQL_QUERIES = {
lossTsc:
'SELECT tsc_tree_cover_loss_drivers__driver, umd_tree_cover_loss__year, SUM(umd_tree_cover_loss__ha) AS umd_tree_cover_loss__ha, SUM("gfw_gross_emissions_co2e_all_gases__Mg") AS "gfw_gross_emissions_co2e_all_gases__Mg" FROM data {WHERE} GROUP BY tsc_tree_cover_loss_drivers__driver, umd_tree_cover_loss__year',
loss: 'SELECT {select_location}, umd_tree_cover_loss__year, SUM(umd_tree_cover_loss__ha) AS umd_tree_cover_loss__ha, SUM("gfw_gross_emissions_co2e_all_gases__Mg") AS "gfw_gross_emissions_co2e_all_gases__Mg" FROM data {WHERE} GROUP BY umd_tree_cover_loss__year, {location} ORDER BY umd_tree_cover_loss__year, {location}',
lossNaturalForest: `SELECT {select_location}, sbtn_natural_forests__class, umd_tree_cover_loss__year, SUM(umd_tree_cover_loss__ha) AS umd_tree_cover_loss__ha, SUM("gfw_gross_emissions_co2e_all_gases__Mg") AS gfw_gross_emissions_co2e_all_gases__Mg FROM data {WHERE} GROUP BY sbtn_natural_forests__class, umd_tree_cover_loss__year, {location}`,
lossFires:
'SELECT {select_location}, umd_tree_cover_loss__year, SUM(umd_tree_cover_loss__ha) AS umd_tree_cover_loss__ha, SUM(umd_tree_cover_loss_from_fires__ha) AS "umd_tree_cover_loss_from_fires__ha" FROM data {WHERE} GROUP BY umd_tree_cover_loss__year, {location} ORDER BY umd_tree_cover_loss__year, {location}',
lossFiresOTF:
Expand All @@ -36,6 +37,7 @@ const SQL_QUERIES = {
carbonFluxOTF: `SELECT SUM("gfw_forest_carbon_net_flux__Mg_CO2e"), SUM("gfw_forest_carbon_gross_removals__Mg_CO2e"), SUM("gfw_forest_carbon_gross_emissions__Mg_CO2e") FROM data WHERE umd_tree_cover_density_2000__threshold >= {threshold} OR is__umd_tree_cover_gain = 'true'&geostore_origin={geostoreOrigin}&geostore_id={geostoreId}`,
extent:
'SELECT {select_location}, SUM(umd_tree_cover_extent_{extentYear}__ha) AS umd_tree_cover_extent_{extentYear}__ha, SUM(area__ha) AS area__ha FROM data {WHERE} GROUP BY {location} ORDER BY {location}',
extentNaturalForest: `SELECT {select_location}, sbtn_natural_forests__class, SUM(area__ha) AS area__ha FROM data {WHERE} GROUP BY iso, sbtn_natural_forests__class, {location} ORDER BY {location}`,
gain: 'SELECT {select_location}, SUM("umd_tree_cover_gain__ha") AS "umd_tree_cover_gain__ha", SUM(umd_tree_cover_extent_2000__ha) AS umd_tree_cover_extent_2000__ha FROM data {WHERE} GROUP BY {location} ORDER BY {location}',
areaIntersection:
'SELECT {select_location}, SUM(area__ha) AS area__ha {intersection} FROM data {WHERE} GROUP BY {location} {intersection} ORDER BY area__ha DESC',
Expand Down Expand Up @@ -378,6 +380,53 @@ export const getTreeCoverLossByDriverType = (params) => {
}));
};

export const getLossNaturalForest = (params) => {
const { forestType, landCategory, ifl, download } = params || {};

const requestUrl = getRequestUrl({
...params,
dataset: 'annual',
datasetType: 'change',
version: 'v20240815',
});

if (!requestUrl) {
return new Promise(() => {});
}

const url = encodeURI(
`${requestUrl}${SQL_QUERIES.lossNaturalForest}`
.replace(
/{select_location}/g,
getLocationSelect({ ...params, cast: false })
)
.replace(/{location}/g, getLocationSelect(params))
.replace('{WHERE}', getWHEREQuery({ ...params, dataset: 'annual' }))
);

if (download) {
const indicator = getIndicator(forestType, landCategory, ifl);
return {
name: `loss_natural_forest${
indicator ? `_in_${snakeCase(indicator.label)}` : ''
}__ha`,
url: getDownloadUrl(url),
};
}

return dataRequest.get(url).then((response) => ({
...response,
data: {
data: response?.data?.map((d) => ({
...d,
year: d.umd_tree_cover_loss__year,
area: d.umd_tree_cover_loss__ha,
emissions: d.gfw_gross_emissions_co2e_all_gases__mg,
})),
},
}));
};

// summed loss for single location
export const getLoss = (params) => {
const { forestType, landCategory, ifl, download } = params || {};
Expand Down Expand Up @@ -1138,6 +1187,59 @@ export const getNetChange = async (params) => {
};
};

export const getExtentNaturalForest = (params) => {
const { forestType, landCategory, ifl, download } = params || {};

const requestUrl = getRequestUrl({
...params,
dataset: 'annual',
datasetType: 'summary',
version: 'v20240815',
});

if (!requestUrl) {
return new Promise(() => {});
}

const url = encodeURI(
`${requestUrl}${SQL_QUERIES.extentNaturalForest}`
.replace(
/{select_location}/g,
getLocationSelect({ ...params, cast: false })
)
.replace(/{location}/g, getLocationSelect({ ...params }))
.replace('{WHERE}', getWHEREQuery({ ...params, dataset: 'annual' }))
);

if (download) {
const indicator = getIndicator(forestType, landCategory, ifl);
return {
name: `natural_forest_${
indicator ? `_in_${snakeCase(indicator.label)}` : ''
}__ha`,
url: getDownloadUrl(url),
};
}

return dataRequest.get(url).then((response) => {
return {
...response,
data: {
data: response?.data?.map((d) => {
return {
...d,
extent:
d.sbtn_natural_forests__class === 'Natural Forest'
? d.area__ha
: 0,
total_area: d.area__ha,
};
}),
},
};
});
};

// summed extent for single location
export const getExtent = (params) => {
const { forestType, landCategory, ifl, download, extentYear } = params || {};
Expand Down
10 changes: 8 additions & 2 deletions services/get-where-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const isNumber = (value) => !!(typeof value === 'number' || !isNaN(value));

// build {where} statement for query
export const getWHEREQuery = (params = {}) => {
const { type, dataset } = params || {};
// umd_tree_cover_loss__year is being added for the dashboard sentences for natural forest
const { type, dataset, umd_tree_cover_loss__year, isNaturalForest } =
params || {};

const allFilterOptions = forestTypes.concat(landCategories);
const allowedParams = ALLOWED_PARAMS[params.dataset || 'annual'];
Expand Down Expand Up @@ -98,7 +100,11 @@ export const getWHEREQuery = (params = {}) => {
}

if (isLastParameter) {
WHERE = `${WHERE} `;
if (isNaturalForest) {
WHERE = `${WHERE} AND umd_tree_cover_loss__year=${umd_tree_cover_loss__year}`;
} else {
WHERE = `${WHERE} `;
}
} else {
WHERE = `${WHERE} AND `;
}
Expand Down
181 changes: 71 additions & 110 deletions services/sentences.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { all, spread } from 'axios';
import { formatNumber } from 'utils/format';

import sortBy from 'lodash/sortBy';
import groupBy from 'lodash/groupBy';
import sumBy from 'lodash/sumBy';
import max from 'lodash/max';
import reverse from 'lodash/reverse';
import isEmpty from 'lodash/isEmpty';

import tropicalIsos from 'data/tropical-isos.json';

import { getExtent, getLoss } from 'services/analysis-cached';
import {
getExtentNaturalForest,
getLossNaturalForest,
} from 'services/analysis-cached';

const ADMINS = {
adm0: null,
Expand All @@ -27,119 +22,85 @@ const GLOBAL_LOCATION = {

export const adminSentences = {
default:
'In 2010, {location} had {extent} of tree cover, extending over {percentage} of its land area.',
'In 2020, {location} had {extent} of natural forest, extending over {percentage} of its land area.',
withLoss:
'In 2010, {location} had {extent} of tree cover, extending over {percentage} of its land area. In {year}, it lost {loss} of tree cover',
'In 2020, {location} had {extent} of natural forest, extending over {percentage} of its land area. In {year}, it lost {loss} of natural forest',
globalInitial:
'In 2010, {location} had {extent} of tree cover, extending over {percentage} of its land area. In {year}, it lost {loss} of tree cover.',
'In 2020, {location} had {extent} of natural forest, extending over {percentage} of its land area. In {year}, it lost {loss} of natural forest',
withPlantationLoss:
'In 2010, {location} had {naturalForest} of natural forest, extending over {percentage} of its land area. In {year}, it lost {naturalLoss} of natural forest',
'In 2020, {location} had {naturalForest} of natural forest, extending over {percentage} of its land area. In {year}, it lost {naturalLoss} of natural forest',
countrySpecific: {
IDN: 'In 2001, {location} had {primaryForest} of primary forest*, extending over {percentagePrimaryForest} of its land area. In {year}, it lost {primaryLoss} of primary forest*, equivalent to {emissionsPrimary} of CO₂ emissions.',
},
co2Emissions: ', equivalent to {emissionsTreeCover} of CO\u2082 emissions.',
end: '.',
};

export const getSentenceData = (params = GLOBAL_LOCATION) =>
all([
getExtent(params),
getExtent({ ...params, forestType: 'plantations' }),
getExtent({
export const getSentenceData = async (params = GLOBAL_LOCATION) => {
try {
const extentNaturalForestResponse = await getExtentNaturalForest(params);
const lossNaturalForestResponse = await getLossNaturalForest({
...params,
forestType: 'primary_forest',
extentYear: 2000,
}),
getLoss(params),
getLoss({ ...params, forestType: 'plantations' }),
getLoss({ ...params, forestType: 'primary_forest' }),
]).then(
spread(
(
totalExtent,
totalPlantationsExtent,
totalPrimaryExtent,
totalLoss,
totalPlantationsLoss,
totalPrimaryLoss
) => {
const extent = totalExtent.data.data;
const loss = totalLoss.data.data;
const plantationsLoss = totalPlantationsLoss.data.data;
const plantationsExtent = totalPlantationsExtent.data.data;
const primaryExtent = totalPrimaryExtent.data.data;

// group over years
const groupedLoss = plantationsLoss && groupBy(loss, 'year');
const groupedPlantationsLoss =
plantationsLoss && groupBy(plantationsLoss, 'year');

const primaryLoss = totalPrimaryLoss.data.data;
const latestYear = max(Object.keys(groupedLoss));

const latestPlantationLoss = groupedPlantationsLoss[latestYear] || null;
const latestLoss = groupedLoss[latestYear] || null;

// sum over different bound1 within year
const summedPlantationsLoss =
latestPlantationLoss &&
latestPlantationLoss.length &&
latestPlantationLoss[0].area
? sumBy(latestPlantationLoss, 'area')
: 0;
const summedPlantationsEmissions =
latestPlantationLoss &&
latestPlantationLoss.length &&
latestPlantationLoss[0].emissions
? sumBy(latestPlantationLoss, 'emissions')
: 0;
const summedLoss =
latestLoss && latestLoss.length && latestLoss[0].area
? sumBy(latestLoss, 'area')
: 0;
const summedEmissions =
latestLoss && latestLoss.length && latestLoss[0].emissions
? sumBy(latestLoss, 'emissions')
: 0;

const data = {
totalArea:
extent && extent.length && extent[0].total_area
? sumBy(extent, 'total_area')
: 0,
extent:
extent && extent.length && extent[0].extent
? sumBy(extent, 'extent')
: 0,
plantationsExtent:
plantationsExtent &&
plantationsExtent.length &&
plantationsExtent[0].extent
? sumBy(plantationsExtent, 'extent')
: 0,
primaryExtent:
primaryExtent && primaryExtent.length && primaryExtent[0].extent
? sumBy(primaryExtent, 'extent')
: 0,
totalLoss: {
area: summedLoss || 0,
year: latestYear || 0,
emissions: summedEmissions || 0,
},
plantationsLoss: {
area: summedPlantationsLoss || 0,
emissions: summedPlantationsEmissions || 0,
},
primaryLoss:
primaryLoss && primaryLoss.length
? reverse(sortBy(primaryLoss, 'year'))[0]
: {},
};

return data;
umd_tree_cover_loss__year: 2023,
isNaturalForest: true,
});

let extent = 0;
let totalArea = 0;

extentNaturalForestResponse.data.data.forEach((item) => {
totalArea += item.area__ha;

if (item.sbtn_natural_forests__class === 'Natural Forest')
extent += item.area__ha;
});

let lossArea = 0;
let emissions = 0;

lossNaturalForestResponse.data.data.forEach((item) => {
emissions += item.gfw_gross_emissions_co2e_all_gases__mg;

if (item.sbtn_natural_forests__class === 'Natural Forest') {
lossArea += item.area;
}
)
);
});

return {
totalArea,
extent,
plantationsExtent: 0,
primaryExtent: 0,
totalLoss: {
area: lossArea,
year: 2023,
emissions,
},
plantationsLoss: {
area: 0,
emissions: 0,
},
primaryLoss: {},
};
} catch (error) {
return {
totalArea: 0,
extent: 0,
plantationsExtent: 0,
primaryExtent: 0,
totalLoss: {
area: 0,
year: 0,
emissions: 0,
},
plantationsLoss: {
area: 0,
emissions: 0,
},
primaryLoss: {},
};
}
};

export const getContextSentence = (location, geodescriber, adminSentence) => {
if (isEmpty(geodescriber)) return {};
Expand Down

0 comments on commit a0c1203

Please sign in to comment.