diff --git a/components/widgets/climate/carbon-stock/index.js b/components/widgets/climate/carbon-stock/index.js index 723b74e4ac..ed08924d68 100644 --- a/components/widgets/climate/carbon-stock/index.js +++ b/components/widgets/climate/carbon-stock/index.js @@ -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'; @@ -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, }; diff --git a/components/widgets/climate/carbon-stock/selectors.js b/components/widgets/climate/carbon-stock/selectors.js index bb44ac06a7..2844fd6c55 100644 --- a/components/widgets/climate/carbon-stock/selectors.js +++ b/components/widgets/climate/carbon-stock/selectors.js @@ -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 { diff --git a/components/widgets/climate/soil-organic/index.js b/components/widgets/climate/soil-organic/index.js index 2ffc8116ce..334d41fae2 100644 --- a/components/widgets/climate/soil-organic/index.js +++ b/components/widgets/climate/soil-organic/index.js @@ -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: [ @@ -40,7 +47,7 @@ export default { layers: [SOIL_CARBON_DENSITY], }, ], - refetchKeys: ['unit'], + refetchKeys: ['unit', 'threshold'], chartType: 'rankedList', visible: ['dashboard', 'analysis'], colors: 'climate', @@ -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: @@ -68,17 +76,17 @@ 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 }); }, @@ -86,18 +94,20 @@ 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, - }; - return [getOrganicSoilCarbonGrouped({ ...rest, ...location, download: true })]; + type, + adm0, + adm1, + adm2, + }; + return [ + getOrganicSoilCarbonGrouped({ ...rest, ...location, download: true }), + ]; }, getWidgetProps, }; diff --git a/components/widgets/climate/soil-organic/selectors.js b/components/widgets/climate/soil-organic/selectors.js index 3894c9b4ad..4efe9f4023 100644 --- a/components/widgets/climate/soil-organic/selectors.js +++ b/components/widgets/climate/soil-organic/selectors.js @@ -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'; @@ -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', @@ -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, @@ -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; diff --git a/components/widgets/manifest.js b/components/widgets/manifest.js index d9c8a2f725..fe8b8c377b 100644 --- a/components/widgets/manifest.js +++ b/components/widgets/manifest.js @@ -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'; @@ -112,8 +112,8 @@ export default { emissionsDeforestation, emissionsDeforestationDrivers, woodyBiomass, - // soilBiomass, - // carbonStock, + soilBiomass, + carbonStock, // land use economicImpact, diff --git a/services/analysis-cached.js b/services/analysis-cached.js index f593cf03d5..29ee18dc53 100644 --- a/services/analysis-cached.js +++ b/services/analysis-cached.js @@ -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`, @@ -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 || {}; diff --git a/services/climate.js b/services/climate.js index 10434b7e89..b8bd31c930 100644 --- a/services/climate.js +++ b/services/climate.js @@ -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: @@ -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, - })), - }, - })); -};