|
| 1 | +import { createSelector } from 'reselect'; |
| 2 | +import isEmpty from 'lodash/isEmpty'; |
| 3 | +import uniqBy from 'lodash/uniqBy'; |
| 4 | +import sumBy from 'lodash/sumBy'; |
| 5 | +import { sortByKey } from 'utils/data'; |
| 6 | +import { format } from 'd3-format'; |
| 7 | + |
| 8 | +// get list data |
| 9 | +const getLoss = state => state.data.loss || null; |
| 10 | +const getExtent = state => state.data.extent || null; |
| 11 | +const getSettings = state => state.settings || null; |
| 12 | +const getOptions = state => state.options || null; |
| 13 | +const getActiveIndicator = state => state.activeIndicator; |
| 14 | +const getLocation = state => state.location || null; |
| 15 | +const getLocationsMeta = state => |
| 16 | + (!state.region ? state.regions : state.subRegions) || null; |
| 17 | +const getLocationNames = state => state.locationNames || null; |
| 18 | +const getColors = state => state.colors || null; |
| 19 | +const getSentences = state => state.config && state.config.sentences; |
| 20 | + |
| 21 | +export const mapData = createSelector( |
| 22 | + [getLoss, getExtent, getSettings, getLocation, getLocationsMeta], |
| 23 | + (data, extent, settings, location, meta) => { |
| 24 | + if (!data || isEmpty(data) || !meta || isEmpty(meta)) return null; |
| 25 | + const { startYear, endYear } = settings; |
| 26 | + const mappedData = data.map(d => { |
| 27 | + const region = meta.find(l => d.id === l.value); |
| 28 | + const loss = |
| 29 | + sumBy( |
| 30 | + d.loss.filter(l => l.year >= startYear && l.year <= endYear), |
| 31 | + 'area_loss' |
| 32 | + ) || 0; |
| 33 | + const locationExtent = extent.filter(l => l.id === d.id); |
| 34 | + const percentage = loss / locationExtent[0].extent * 100; |
| 35 | + return { |
| 36 | + label: (region && region.label) || '', |
| 37 | + loss, |
| 38 | + percentage, |
| 39 | + value: settings.unit === 'ha' ? loss : percentage, |
| 40 | + path: `/country/${location.country}/${ |
| 41 | + location.region ? `${location.region}/` : '' |
| 42 | + }${d.id}` |
| 43 | + }; |
| 44 | + }); |
| 45 | + |
| 46 | + return mappedData; |
| 47 | + } |
| 48 | +); |
| 49 | + |
| 50 | +export const parseData = createSelector( |
| 51 | + [mapData, getColors], |
| 52 | + (data, colors) => { |
| 53 | + if (!data) return null; |
| 54 | + const sortedData = sortByKey(uniqBy(data, 'label'), 'value', true); |
| 55 | + |
| 56 | + return sortedData.map(o => ({ |
| 57 | + ...o, |
| 58 | + color: colors.main |
| 59 | + })); |
| 60 | + } |
| 61 | +); |
| 62 | + |
| 63 | +export const getSentence = createSelector( |
| 64 | + [ |
| 65 | + mapData, |
| 66 | + getSettings, |
| 67 | + getOptions, |
| 68 | + getLocation, |
| 69 | + getActiveIndicator, |
| 70 | + getLocationNames, |
| 71 | + getSentences |
| 72 | + ], |
| 73 | + |
| 74 | + (data, settings, options, location, indicator, locationNames, sentences) => { |
| 75 | + if (!data || !options || !indicator || !locationNames) return ''; |
| 76 | + const { |
| 77 | + initial, |
| 78 | + withIndicator, |
| 79 | + initialPercent, |
| 80 | + withIndicatorPercent |
| 81 | + } = sentences; |
| 82 | + const { startYear, endYear } = settings; |
| 83 | + const totalLoss = sumBy(data, 'loss'); |
| 84 | + const currentLocation = |
| 85 | + locationNames && locationNames.current && locationNames.current.label; |
| 86 | + const topRegion = data.length && data[0]; |
| 87 | + const avgLossPercentage = sumBy(data, 'percentage') / data.length; |
| 88 | + const avgLoss = sumBy(data, 'loss') / data.length; |
| 89 | + let percentileLoss = 0; |
| 90 | + let percentileLength = 0; |
| 91 | + |
| 92 | + while ( |
| 93 | + (percentileLength < data.length && percentileLoss / totalLoss < 0.5) || |
| 94 | + (percentileLength < 10 && data.length > 10) |
| 95 | + ) { |
| 96 | + percentileLoss += data[percentileLength].loss; |
| 97 | + percentileLength += 1; |
| 98 | + } |
| 99 | + const topLoss = percentileLoss / totalLoss * 100; |
| 100 | + let sentence = |
| 101 | + indicator.value === 'gadm28' ? initialPercent : withIndicatorPercent; |
| 102 | + if (settings.unit !== '%') { |
| 103 | + sentence = indicator.value === 'gadm28' ? initial : withIndicator; |
| 104 | + } |
| 105 | + |
| 106 | + const params = { |
| 107 | + indicator: indicator.value, |
| 108 | + location: currentLocation, |
| 109 | + startYear, |
| 110 | + endYear, |
| 111 | + topLoss: `${format('.0f')(topLoss)}%`, |
| 112 | + percentileLength, |
| 113 | + region: percentileLength > 1 ? topRegion.label : 'This region', |
| 114 | + value: |
| 115 | + topRegion.percentage > 1 && settings.unit === '%' |
| 116 | + ? `${format('.0f')(topRegion.percentage)}%` |
| 117 | + : `${format('.3s')(topRegion.loss)}ha`, |
| 118 | + average: |
| 119 | + topRegion.percentage > 1 && settings.unit === '%' |
| 120 | + ? `${format('.0f')(avgLossPercentage)}%` |
| 121 | + : `${format('.3s')(avgLoss)}ha` |
| 122 | + }; |
| 123 | + |
| 124 | + return { |
| 125 | + sentence, |
| 126 | + params |
| 127 | + }; |
| 128 | + } |
| 129 | +); |
0 commit comments