Skip to content

Commit

Permalink
Merge pull request #4909 from wri/feat/FLAG-1210
Browse files Browse the repository at this point in the history
FLAG-1210: replace carto query with precalculated table for soil organic widget
  • Loading branch information
wri7tno authored Feb 3, 2025
2 parents a8aef20 + be2396c commit 2f50b2e
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 89 deletions.
13 changes: 6 additions & 7 deletions components/widgets/climate/carbon-stock/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { all, spread } from 'axios';

import { getSoilOrganicCarbon } from 'services/climate';
import { getBiomassStock } from 'services/analysis-cached';
import {
getBiomassStock,
getSoilOrganicCarbon,
} from 'services/analysis-cached';

import getWidgetProps from './selectors';

Expand Down Expand Up @@ -45,16 +47,13 @@ export default {
getData: (params) =>
all([getSoilOrganicCarbon(params), getBiomassStock(params)]).then(
spread((soilOrganicCarbon, biomassResponse) => {
const { adm0, adm1, adm2 } = params;
const { data } = biomassResponse.data;
const { rows } = soilOrganicCarbon.data;
const soilCarbonData = rows.find(
(el) => el.iso === adm0 && el.admin_1 === adm1 && el.admin_2 === adm2
);
const soilCarbonData = soilOrganicCarbon.data;
let parsedData = {};
if (data && data.length === 1) {
parsedData = {
...data[0],
...soilCarbonData[0],
soilCarbon: soilCarbonData.soil_carbon__t || 0,
soilCarbonDensity: soilCarbonData.soil_carbon_density__t_ha || 0,
};
Expand Down
14 changes: 7 additions & 7 deletions components/widgets/climate/carbon-stock/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ export const calculateData = createSelector(
const { variable } = settings;
const extent = (data && data.extent) || 0;
const soil = (data && data.gfw_soil_carbon_stocks_2000__mg_c) || 0;
const soilDensity = (data && data.soilCarbonDensity) || 0;
const soilDensity = (data && data.biomassdensity) || 0;

const aboveGroundCarbon =
const aboveGroundCarbonDensity =
(data && data.gfw_aboveground_carbon_stocks_2000__mg_c) || 0;
const belowGroundCarbon =
const belowGroundCarbonDensity =
(data && data.gfw_belowground_carbon_stocks_2000__mg_c) || 0;

const aboveGroundCarbonDensity =
extent > 0 ? aboveGroundCarbon / extent : 0;
const belowGroundCarbonDensity =
extent > 0 ? belowGroundCarbon / extent : 0;
const aboveGroundCarbon =
extent > 0 ? aboveGroundCarbonDensity * extent : 0;
const belowGroundCarbon =
extent > 0 ? belowGroundCarbonDensity * extent : 0;
const total = soil + aboveGroundCarbon + belowGroundCarbon;

return {
Expand Down
56 changes: 33 additions & 23 deletions components/widgets/climate/soil-organic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export default {
label: 'unit',
type: 'switch',
whitelist: ['totalBiomass', 'biomassDensity'],
border: true,
},
{
key: 'threshold',
label: 'canopy density',
type: 'mini-select',
metaKey: 'widget_canopy_density',
},
],
datasets: [
Expand All @@ -40,7 +47,7 @@ export default {
layers: [SOIL_CARBON_DENSITY],
},
],
refetchKeys: ['unit'],
refetchKeys: ['unit', 'threshold'],
chartType: 'rankedList',
visible: ['dashboard', 'analysis'],
colors: 'climate',
Expand All @@ -55,10 +62,11 @@ export default {
pageSize: 5,
page: 0,
unit: 'totalBiomass',
threshold: 30,
},
sentences: {
region:
'In 2000, {location} had a soil organic carbon density of {biomassDensity}, and a total carbon storage of {totalBiomass}.',
'In 2000, {location} had a soil organic carbon density of {biomassDensity}, and a total soil carbon storage of {totalBiomass}.',
globalBiomass:
'Around {value} of the world’s {label} is contained in the top 5 countries.',
globalDensity:
Expand All @@ -68,36 +76,38 @@ export default {
const location =
type === 'country'
? {
type,
adm0: adm0 && !adm1 ? null : adm0,
adm1: adm1 && !adm2 ? null : adm1,
adm2: null,
}
type,
adm0: adm0 && !adm1 ? null : adm0,
adm1: adm1 && !adm2 ? null : adm1,
adm2: null,
}
: {
type,
adm0,
adm1,
adm2,
};
type,
adm0,
adm1,
adm2,
};

return getOrganicSoilCarbonGrouped({ ...rest, ...location });
},
getDataURL: ({ type, adm0, adm1, adm2, ...rest } = {}) => {
const location =
type === 'country'
? {
type,
adm0: adm0 && !adm1 ? null : adm0,
adm1: adm1 && !adm2 ? null : adm1,
adm2: null,
}
type,
adm0: adm0 && !adm1 ? null : adm0,
adm1: adm1 && !adm2 ? null : adm1,
adm2: null,
}
: {
type,
adm0,
adm1,
adm2,
};
return [getOrganicSoilCarbonGrouped({ ...rest, ...location, download: true })];
type,
adm0,
adm1,
adm2,
};
return [
getOrganicSoilCarbonGrouped({ ...rest, ...location, download: true }),
];
},
getWidgetProps,
};
17 changes: 9 additions & 8 deletions components/widgets/climate/soil-organic/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const getSortedData = createSelector(
[getData, getSettings, getAdm1, getAdm2],
(data, settings, adm1, adm2) => {
if (isEmpty(data)) return null;
// console.log('soil-organic', { data, settings })

let regionKey = 'iso';
if (adm1) regionKey = 'adm1';
if (adm2) regionKey = 'adm2';
Expand Down Expand Up @@ -121,10 +121,10 @@ export const parseSentence = createSelector(
settings.unit === 'totalBiomass'
? formatNumber({ num: percent, unit: '%' })
: formatNumber({
num: avgBiomDensity,
unit: 'tC/ha',
spaceUnit: true,
});
num: avgBiomDensity,
unit: 'tC/ha',
spaceUnit: true,
});

const labels = {
globalDensity: 'soil organic carbon density',
Expand All @@ -134,9 +134,10 @@ export const parseSentence = createSelector(
// Properties defined for labels and sentences are named in a way that relates with the display
// but the units are somewhat fixed, due to their dependency on the whitelists for settings dropdowns.
// We map them here.
const sentenceLabelProperty = settings.unit === 'totalBiomass' ? 'globalBiomass' : 'globalDensity';
const sentenceLabelProperty =
settings.unit === 'totalBiomass' ? 'globalBiomass' : 'globalDensity';
const sentence = sentences[sentenceLabelProperty];
const label = labels[sentenceLabelProperty]
const label = labels[sentenceLabelProperty];

return {
sentence,
Expand All @@ -145,7 +146,7 @@ export const parseSentence = createSelector(
value,
},
};
};
}

// Standard processing for adm1 and adm2 areas, same sentence, same formatting.
const location_id = location && location.value;
Expand Down
8 changes: 4 additions & 4 deletions components/widgets/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ import naturalForest from 'components/widgets/land-cover/natural-forest';

// Climate
import woodyBiomass from 'components/widgets/climate/whrc-biomass/';
// import soilBiomass from 'components/widgets/climate/soil-organic';
import soilBiomass from 'components/widgets/climate/soil-organic';
import carbonFlux from 'components/widgets/climate/carbon-flux';
import emissionsDeforestation from 'components/widgets/climate/emissions-deforestation';
import emissionsDeforestationDrivers from 'components/widgets/climate/emissions-deforestation-drivers';
// import carbonStock from 'components/widgets/climate/carbon-stock';
import carbonStock from 'components/widgets/climate/carbon-stock';

// Land Use
import economicImpact from 'components/widgets/land-use/economic-impact';
Expand Down Expand Up @@ -112,8 +112,8 @@ export default {
emissionsDeforestation,
emissionsDeforestationDrivers,
woodyBiomass,
// soilBiomass,
// carbonStock,
soilBiomass,
carbonStock,

// land use
economicImpact,
Expand Down
51 changes: 51 additions & 0 deletions services/analysis-cached.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ const SQL_QUERIES = {
'SELECT SUM("whrc_aboveground_biomass_stock_2000__Mg") AS "whrc_aboveground_biomass_stock_2000__Mg", SUM("whrc_aboveground_co2_stock_2000__Mg") AS "whrc_aboveground_co2_stock_2000__Mg", SUM(umd_tree_cover_extent_2000__ha) AS umd_tree_cover_extent_2000__ha, SUM("gfw_aboveground_carbon_stocks_2000__Mg_C") as gfw_aboveground_carbon_stocks_2000__Mg_C, SUM("gfw_belowground_carbon_stocks_2000__Mg_C") as gfw_belowground_carbon_stocks_2000__Mg_C, SUM("gfw_soil_carbon_stocks_2000__Mg_C") as gfw_soil_carbon_stocks_2000__Mg_C FROM data {WHERE}',
biomassStockGrouped:
'SELECT {select_location}, SUM("whrc_aboveground_biomass_stock_2000__Mg") AS "whrc_aboveground_biomass_stock_2000__Mg", SUM("whrc_aboveground_co2_stock_2000__Mg") AS "whrc_aboveground_co2_stock_2000__Mg", SUM(umd_tree_cover_extent_2000__ha) AS umd_tree_cover_extent_2000__ha FROM data {WHERE} GROUP BY {location} ORDER BY {location}',
organicSoilCarbon:
'SELECT {location}, SUM("gfw_soil_carbon_stocks_2000__Mg_C") as gfw_soil_carbon_stocks_2000__Mg_C, SUM("gfw_soil_carbon_stocks_2000__Mg_C") / SUM("umd_tree_cover_extent_2000__ha") as gfw_soil_carbon_density__t_C_per_ha, SUM("gfw_aboveground_carbon_stocks_2000__Mg_C") / SUM("umd_tree_cover_extent_2000__ha") AS gfw_aboveground_carbon_stocks_2000__t_C_per_ha, SUM("gfw_belowground_carbon_stocks_2000__Mg_C") / SUM("umd_tree_cover_extent_2000__ha") as gfw_belowground_carbon_stocks_2000__t_C_per_ha FROM data {WHERE} GROUP BY {location}',
organicSoilCarbonGrouped:
'SELECT {select_location}, CASE WHEN SUM("umd_tree_cover_extent_2000__ha") = 0 THEN NULL ELSE SUM("gfw_soil_carbon_stocks_2000__Mg_C") END AS "gfw_soil_carbon_stocks_2000__Mg_C", CASE WHEN SUM("umd_tree_cover_extent_2000__ha") = 0 THEN NULL ELSE SUM("gfw_soil_carbon_stocks_2000__Mg_C") / SUM("umd_tree_cover_extent_2000__ha") END AS soil_carbon_density__t_ha FROM data {WHERE} GROUP BY {location} ORDER BY {location}',
treeCoverGainByPlantationType: `SELECT CASE WHEN gfw_planted_forests__type IS NULL THEN 'Outside of Plantations' ELSE gfw_planted_forests__type END AS plantation_type, SUM(umd_tree_cover_gain__ha) as gain_area_ha FROM data {WHERE} AND umd_tree_cover_gain__period in ({baselineYear}) GROUP BY gfw_planted_forests__type`,
Expand Down Expand Up @@ -2747,6 +2749,55 @@ export const getBiomassStock = (params) => {
}));
};

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

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

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

const url = encodeURI(
`${requestUrl}${SQL_QUERIES.organicSoilCarbon}`
.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: `soil_organic_carbon_by_region${
indicator ? `_in_${snakeCase(indicator.label)}` : ''
}__ha`,
url: getDownloadUrl(url),
};
}

return dataRequest.get(url).then((response) => ({
...response,
data: response.data.map((d) => ({
iso: d.iso,
soil_carbon__t: d.gfw_soil_carbon_stocks_2000__mg_c,
soil_carbon_density__t_ha: d.gfw_soil_carbon_density__t_c_per_ha,
totalbiomass: d.gfw_soil_carbon_stocks_2000__mg_c,
biomassdensity: d.gfw_soil_carbon_density__t_c_per_ha,
gfw_aboveground_carbon_stocks_2000__mg_c:
d.gfw_aboveground_carbon_stocks_2000__t_c_per_ha,
gfw_belowground_carbon_stocks_2000__mg_c:
d.gfw_belowground_carbon_stocks_2000__t_c_per_ha,
})),
}));
};

// organic soil carbon grouped by location
export const getOrganicSoilCarbonGrouped = (params) => {
const { forestType, landCategory, ifl, download } = params || {};
Expand Down
40 changes: 0 additions & 40 deletions services/climate.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ const INDICATORS = [
];

const SQL_QUERIES = {
soil_organic_carbon: {
globalAndCountry:
'SELECT iso, SUM(total_soil_carbon) as soil_carbon__t, SUM(soil_carbon_density) as soil_carbon_density__t_ha FROM soil_carbon_gadm36 GROUP BY iso',
adm1: "SELECT iso, admin_1, SUM(total_soil_carbon) as soil_carbon__t, SUM(soil_carbon_density) as soil_carbon_density__t_ha FROM soil_carbon_gadm36 WHERE iso = '{adm0}' GROUP BY iso, admin_1",
adm2: "SELECT iso, admin_1, admin_2, SUM(total_soil_carbon) as soil_carbon__t, SUM(soil_carbon_density) as soil_carbon_density__t_ha FROM soil_carbon_gadm36 WHERE iso = '{adm0}' AND admin_1 = {adm1} GROUP BY iso, admin_1, admin_2",
},
cummulative:
"SELECT sum(alerts) AS alert__count, sum(cumulative_emissions) AS cumulative_emissions__t_C02, sum(cumulative_deforestation) AS cumulative_deforestation__ha, sum(loss_ha) AS treecover_loss__ha, sum(percent_to_emissions_target) AS percent_to_emissions_target, sum(percent_to_deforestation_target) AS percent_to_deforestation_target, year as year, country_iso, week as iso_week FROM a98197d2-cd8e-4b17-ab5c-fabf54b25ea0 WHERE country_iso = '{iso}' AND year IN ({year}) AND week <= 53 GROUP BY week, country_iso ORDER BY week ASC",
emissions:
Expand Down Expand Up @@ -73,37 +67,3 @@ export const getCumulative = ({ download, ...params }) =>
},
}));
});

export const getSoilOrganicCarbon = ({ adm0, adm1, adm2, download }) => {
let query;

if (!adm1) {
query = SQL_QUERIES.soil_organic_carbon.globalAndCountry;
} else if (adm1 && !adm2) {
query = SQL_QUERIES.soil_organic_carbon.adm1.replace('{adm0}', adm0);
} else if (adm1 && adm2) {
query = SQL_QUERIES.soil_organic_carbon.adm2
.replace('{adm0}', adm0)
.replace('{adm1}', adm1);
}

const url = `${CARTO_API}/sql?q=${query}`;

if (download) {
return {
name: 'soil_organic_carbon',
url: url.concat('&format=csv'),
};
}

return request.get(url).then((response) => ({
...response,
data: {
rows: response.data.rows.map((o) => ({
...o,
totalbiomass: o.soil_carbon__t,
biomassdensity: o.soil_carbon_density__t_ha,
})),
},
}));
};

0 comments on commit 2f50b2e

Please sign in to comment.