Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FLAG-1154: update dashboard sentences for natural forest #4884

Open
wants to merge 3 commits into
base: feat/FLAG-1155--natural-forest-widget
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
102 changes: 90 additions & 12 deletions services/sentences.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ 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,
getExtent,
getLoss,
} from 'services/analysis-cached';

const ADMINS = {
adm0: null,
Expand All @@ -27,21 +30,21 @@ 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) =>
const getSentenceDataForIdn = (params = GLOBAL_LOCATION) =>
all([
getExtent(params),
getExtent({ ...params, forestType: 'plantations' }),
Expand Down Expand Up @@ -141,6 +144,80 @@ export const getSentenceData = (params = GLOBAL_LOCATION) =>
)
);

const getNaturalForestSentenceData = async (params = GLOBAL_LOCATION) => {
try {
const extentNaturalForestResponse = await getExtentNaturalForest(params);
const lossNaturalForestResponse = await getLossNaturalForest({
...params,
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: {},
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the dashboard sentences only require the following:

  • totalArea
  • extent
  • totalLoss: {
    area,
    year,
    emissions,
    }

hence I left the others with 0

} 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 getSentenceData = async (params = GLOBAL_LOCATION) => {
if (params.adm0 === 'IDN') {
return getSentenceDataForIdn(params);
}

return getNaturalForestSentenceData(params);
};

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

Expand Down Expand Up @@ -174,7 +251,6 @@ export const parseSentence = (
globalInitial,
countrySpecific,
co2Emissions,
end,
} = adminSentences;
const {
extent,
Expand Down Expand Up @@ -283,14 +359,16 @@ export const parseSentence = (
if (extent > 0 && totalLoss.area) {
sentence = areaPlantations && location ? withPlantationLoss : withLoss;
}
sentence = tropicalIsos.includes(adm0)
? sentence + co2Emissions
: sentence + end;

if (!location) sentence = globalInitial;
if (adm0 in countrySpecific) {
sentence = countrySpecific[adm0];
}

if (adm0 !== 'IDN') {
sentence += co2Emissions;
}

return {
sentence,
params,
Expand Down