Skip to content

Feature/whrc biomass widget (simple sentence) #3677

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

Merged
merged 25 commits into from
Feb 13, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
89c5185
whrc biomass widget (simple sentence)
dfrico Dec 19, 2018
cb8d380
Merge branch 'develop' of github.com:Vizzuality/gfw into feature/whrc…
edbrett Dec 20, 2018
de3a7ea
Merge branch 'develop' of github.com:Vizzuality/gfw into feature/whrc…
edbrett Jan 9, 2019
5ba2122
Added ranked list to simple sentence component
dfrico Jan 10, 2019
dad570e
Adding total biomass and biomass density options to widget, affecting…
dfrico Jan 11, 2019
84db6a6
whrc widget works for global
dfrico Jan 11, 2019
49d9f67
Added global sentence with params to whrc
dfrico Jan 11, 2019
b4559e0
Fixed occasional bug related to list keys
dfrico Jan 11, 2019
b037cbb
Climate colors for whrc widget correspond to climate layer
dfrico Jan 14, 2019
73d254f
Removed threshold from settings, canopy fixed on 30%
dfrico Jan 14, 2019
ae3a1f1
Fixed whrc widget for subregions
dfrico Jan 15, 2019
9b5d9d7
Changing units when chaging variable from settings
dfrico Jan 15, 2019
434dbed
Different sentences for density and total biomass
dfrico Jan 15, 2019
ad25273
Fixed a bug where subregions without data crashed the app
dfrico Jan 15, 2019
9099f6b
Merge branch 'develop' into feature/whrc-biomass
dfrico Jan 16, 2019
172e6e0
merge develop
edbrett Jan 17, 2019
a5b3121
Merge branch 'feature/whrc-biomass' of github.com:Vizzuality/gfw into…
edbrett Jan 17, 2019
ba23505
merge develop
edbrett Jan 17, 2019
1a14e54
Merge develop
dfrico Feb 5, 2019
c02fec4
WHRC new table integrated with widget
dfrico Feb 11, 2019
0913491
Added threshold to query
dfrico Feb 12, 2019
751a861
Fixed bug and added threshold in the settings
dfrico Feb 13, 2019
11ad8d3
Merge branch 'develop' into feature/whrc-biomass
dfrico Feb 13, 2019
37ac375
Small change to unit in list
dfrico Feb 13, 2019
91aef67
disable layers for old map
edbrett Feb 13, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ class NumberedList extends PureComponent {
<div className="item-name">{item.label}</div>
</div>
<div className="item-value">
{formatNumber({ num: item.value, unit })}
{formatNumber({
num: item.value,
unit: item.unit ? item.unit : unit
})}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class Widget extends PureComponent {
{loading && <Loader className="widget-loader" />}
{!loading &&
!error &&
!hasData && (
!hasData &&
Component && (
<NoContent message={`No data in selection for ${locationName}`} />
)}
{!loading &&
Expand All @@ -56,7 +57,8 @@ class Widget extends PureComponent {
/>
)}
{!error &&
hasData && (
hasData &&
Component && (
<Component
widget={widget}
data={data}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ class WidgetSettings extends PureComponent {
});
}

getUnit = (units, widget, settings, onSettingsChange) => {
if (units.length <= 1) return null;
if (units.length === 2) {
getUnitVariable = (items, widget, settings, onSettingsChange, type) => {
if (items.length <= 1) return null;
if (items.length === 2) {
return (
<Switch
theme="theme-switch-light"
label="UNIT"
value={settings.unit}
options={units}
label={type === 'unit' ? 'UNIT' : 'VARIABLE'}
value={settings[type]}
options={items}
onChange={option =>
onSettingsChange({ value: { unit: option }, widget })
onSettingsChange({ value: { [type]: option }, widget })
}
/>
);
Expand All @@ -35,11 +35,11 @@ class WidgetSettings extends PureComponent {
return (
<Dropdown
theme="theme-select-light"
label="UNIT"
value={settings.unit}
options={units}
label={type === 'unit' ? 'UNIT' : 'VARIABLE'}
value={settings[type]}
options={items}
onChange={option =>
onSettingsChange({ value: { unit: option.value }, widget })
onSettingsChange({ value: { [type]: option.value }, widget })
}
/>
);
Expand Down Expand Up @@ -118,6 +118,7 @@ class WidgetSettings extends PureComponent {
} = this.props;
const {
units,
variables,
forestTypes,
landCategories,
periods,
Expand All @@ -133,6 +134,7 @@ class WidgetSettings extends PureComponent {
} = this.props.options;
const hasExtraOptions =
units ||
variables ||
periods ||
years ||
startYears ||
Expand Down Expand Up @@ -284,7 +286,22 @@ class WidgetSettings extends PureComponent {
settings,
onSettingsChange
)}
{units && this.getUnit(units, widget, settings, onSettingsChange)}
{units &&
this.getUnitVariable(
units,
widget,
settings,
onSettingsChange,
'unit'
)}
{variables &&
this.getUnitVariable(
variables,
widget,
settings,
onSettingsChange,
'variable'
)}
{periods && (
<Dropdown
theme="theme-select-light"
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/components/widgets/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import * as treeCoverLocated from './widgets/land-cover/tree-cover-located';
// Climate
import * as emissions from './widgets/climate/emissions';
import * as emissionsDeforestation from './widgets/climate/emissions-deforestation';
import * as woodyBiomass from './widgets/climate/whrc-biomass/';
import * as emissionsPlantations from './widgets/climate/emissions-plantations';
import * as futureCarbonGains from './widgets/climate/future-carbon-gains';

Expand Down Expand Up @@ -65,6 +66,7 @@ export default {
// climate
emissions,
emissionsDeforestation,
woodyBiomass,
emissionsPlantations,
futureCarbonGains,
// biodiversity
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/components/widgets/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import forestTypes from 'data/forest-types.json';
import landCategories from 'data/land-categories.json';
import thresholds from 'data/thresholds.json';
import units from 'data/units.json';
import variables from 'data/variables.json';
import periods from 'data/periods.json';
import extentYears from 'data/extent-years.json';
import tscDriverGroups from 'data/tsc-loss-groups.json';
Expand All @@ -19,5 +20,6 @@ export default {
tscDriverGroups,
types,
weeks,
datasets
datasets,
variables
};
19 changes: 19 additions & 0 deletions app/javascript/components/widgets/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ export const getChildLocationData = createSelector(
}
);

export const getLocationDict = createSelector(
[getLocationData, selectLocation],
(locationData, location) => {
let values;
if (location.adm2) values = locationData.adm2;
else if (location.adm1) values = locationData.adm1;
else values = locationData.adm0;

return values.reduce(
(dict, next) => ({
...dict,
[next.value]: next.label
}),
{}
);
}
);

export const getLocationObject = createSelector(
[getActiveLocationData, selectLocation],
(adms, location) => {
Expand Down Expand Up @@ -298,6 +316,7 @@ export const getWidgetsProps = createStructuredSelector({
locationData: getActiveLocationData,
locationObject: getLocationObject,
locationName: getLocationName,
locationDict: getLocationDict,
childLocationData: getChildLocationData,
noWidgetsMessage: getNoWidgetsMessage,
isTropical: isTropicalLocation
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { getBiomassRanking } from 'services/climate';

export default ({ params }) =>
getBiomassRanking({ ...params }).then(res => res.data && res.data.rows);
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export default {
widget: 'whrc-biomass',
title: 'Biomass density in {location}',
categories: ['climate'],
types: ['global', 'country'],
admins: ['global', 'adm0', 'adm1', 'adm2'],
options: {
variables: ['totalbiomass', 'biomassdensity']
},
colors: 'climate',
dataType: 'loss',
metaKey: 'aboveground_biomass',
layers: ['f10bded4-94e2-40b6-8602-ae5bdfc07c08'],
sortOrder: {
summary: 0,
forestChange: 0
},
sentences: {
initial:
'In 2000, {location} had a biomass density of {biomassDensity}, and a total biomass of {totalBiomass}.',
totalbiomass:
'Around {value} of the world’s {label} is contained in the top 5 countries.',
biomassdensity:
'The average {label} of the world’s top 5 countries is {value}.'
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Component from 'components/widgets/components/widget-numbered-list';
import getData from './actions';
import getProps from './selectors';
import config from './config';
import settings from './settings';

export { Component, getData, getProps, config, settings };
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { createSelector, createStructuredSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import findIndex from 'lodash/findIndex';
import { formatNumber } from 'utils/format';
import { sortByKey } from 'utils/data';

// get list data
const getData = state => state.data && state.data;
const getLocationName = state => state.locationName || null;
const getLocation = state => state.allLocation || null;
const getLocationDict = state => state.locationDict || null;
const getLocationObject = state => state.locationObject || null;
const getSentences = state => state.config && state.config.sentences;
const getColors = state => state.colors || null;
const getSettings = state => state.settings || null;

const getSortedData = createSelector(
[getData, getSettings],
(data, settings) => {
if (isEmpty(data)) return null;
return sortByKey(data, settings.variable).reverse();
}
);

export const parseData = createSelector(
[
getSortedData,
getColors,
getLocation,
getLocationDict,
getLocationObject,
getSettings
],
(data, colors, location, locationsDict, locationObj, settings) => {
if (isEmpty(data)) return null;

let dataTrimmed = data.map((d, i) => ({
...d,
rank: i + 1
}));

let key;
if (data[0].admin_2) key = 'admin_2';
else if (data[0].admin_1) key = 'admin_1';
else key = 'iso';

if (location.payload.adm0) {
const locationIndex = findIndex(data, d => d[key] === locationObj.value);
if (locationIndex === -1) return null;

let trimStart = locationIndex - 2;
let trimEnd = locationIndex + 3;
if (locationIndex < 2) {
trimStart = 0;
trimEnd = 5;
}
if (locationIndex > data.length - 3) {
trimStart = data.length - 5;
trimEnd = data.length;
}
dataTrimmed = dataTrimmed.slice(trimStart, trimEnd);
}
const { query, type } = location;

return dataTrimmed.map((d, i) => ({
...d,
label: locationsDict[d[key]],
color: colors.density,
key: `${d.iso}-${i}`,
path: {
type,
payload: { type: 'country', adm0: d.iso },
query
},
value: d[settings.variable],
unit: settings.variable === 'totalbiomass' ? 't' : 't/ha'
}));
}
);

export const parseSentence = createSelector(
[getData, getLocationName, getSentences, getLocationDict, getSettings],
(data, location, sentences, locationsDict, settings) => {
if (!sentences || isEmpty(data)) return null;

if (location === 'global') {
const sorted = sortByKey(data, [settings.variable]).reverse();

let biomTop5 = 0;
let densTop5 = 0;
const biomTotal = sorted.reduce((acc, next, i) => {
if (i < 5) {
biomTop5 += next.totalbiomass;
densTop5 += next.biomassdensity;
}
return acc + next.totalbiomass;
}, 0);

const percent = biomTop5 / biomTotal * 100;
const avgBiomDensity = densTop5 / 5;

const value =
settings.variable === 'totalbiomass'
? formatNumber({ num: percent, unit: '%' })
: formatNumber({ num: avgBiomDensity, unit: 't/ha' });

const labels = {
biomassdensity: 'biomass density',
totalbiomass: 'total biomass'
};

return {
sentence: sentences[settings.variable],
params: {
label: labels[settings.variable],
value
}
};
}
const iso = Object.keys(locationsDict).find(
key => locationsDict[key] === location
);
const region = data.find(item => {
if (item.admin_2) return String(item.admin_2) === iso;
else if (item.admin_1) return String(item.admin_1) === iso;
return item.iso === iso;
});
if (!region) return null;

const { biomassdensity, totalbiomass } = region;
return {
sentence: sentences.initial,
params: {
location,
biomassDensity: formatNumber({ num: biomassdensity, unit: 't/ha' }),
totalBiomass: formatNumber({ num: totalbiomass, unit: 't' })
}
};
}
);

export default createStructuredSelector({
data: parseData,
sentence: parseSentence
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default {
threshold: 30,
startYear: 2001,
endYear: 2017,
extentYear: 2000,
layers: ['loss'],
pageSize: 5,
page: 0,
variable: 'totalbiomass'
};
3 changes: 2 additions & 1 deletion app/javascript/data/colors.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"noGain": "#e7e5a4"
},
"climate": {
"ramp": ["#EDD093", "#BFBC35", "#007F53", "#123A33"],
"ramp": [ "#EDD093", "#BFBC35", "#007F53", "#123A33"],
"density": "#895122",
"loss": {
"main": "#DF511E",
"secondary": "#F9A000"
Expand Down
9 changes: 9 additions & 0 deletions app/javascript/data/variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{
"label": "Total",
"value": "totalbiomass"
},{
"label": "Density",
"value": "biomassdensity"
}
]
Loading