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

Deploy #4825

Merged
merged 8 commits into from
Jul 16, 2024
38 changes: 18 additions & 20 deletions components/widgets/fires/fires-alerts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,26 +327,24 @@ const defaultConfig = {
const maxYear = Math.max(...years);
const latestDate = latest && latest.date;

return (
{
alerts: data,
latest: latestDate,
options: {
compareYear: years
.filter((y) => y !== maxYear)
.map((y) => ({
label: y,
value: y,
})),
},
settings: {
startDateAbsolute: moment(latestDate)
.add(-3, 'month')
.format('YYYY-MM-DD'),
endDateAbsolute: latestDate,
},
} || {}
);
return {
alerts: data,
latest: latestDate,
options: {
compareYear: years
.filter((y) => y !== maxYear)
.map((y) => ({
label: y,
value: y,
})),
},
settings: {
startDateAbsolute: moment(latestDate)
.add(-3, 'month')
.format('YYYY-MM-DD'),
endDateAbsolute: latestDate,
},
};
})
);
},
Expand Down
137 changes: 118 additions & 19 deletions components/widgets/fires/fires-alerts/selectors.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
/* eslint-disable prefer-destructuring */
import { createSelector, createStructuredSelector } from 'reselect';
import {
isWithinInterval,
startOfWeek,
endOfWeek,
eachWeekOfInterval,
getYear,
getWeek,
} from 'date-fns';
import moment from 'moment';
import { formatNumber } from 'utils/format';
import isEmpty from 'lodash/isEmpty';
import sortBy from 'lodash/sortBy';
import orderBy from 'lodash/orderBy';
import sumBy from 'lodash/sumBy';
import groupBy from 'lodash/groupBy';
import toArray from 'lodash/toArray';
import max from 'lodash/max';
import min from 'lodash/min';

Expand All @@ -32,14 +41,91 @@ const getIndicator = (state) => state.indicator;

const MINGAP = 4;

const generateYearWeekArray = (startDate, endDate) => {
const weeks = eachWeekOfInterval(
{
start: startOfWeek(startDate, { weekStartsOn: 1 }),
end: endOfWeek(endDate, { weekStartsOn: 1 }),
},
{ weekStartsOn: 1 }
);

return weeks.map((date) => ({
year: getYear(date),
week: getWeek(date, { weekStartsOn: 1 }),
}));
};

const getAllAlerts = createSelector([getAlerts], (alerts) => {
if (!alerts) return null;

const filler = { iso: alerts[0]?.iso, alert__count: 0, confidence__cat: 'h' };
const minYear = '2012';
const maxYear = new Date();

const yearProperty = 'alert__year';
const weekProperty = 'alert__week';

const start = new Date(minYear?.toString());
const end = new Date(maxYear?.toString());
const completeYearWeekArray = generateYearWeekArray(start, end);

// Create a set of existing year-week combinations for quick lookup
const existingAlerts = new Set(
alerts.map((alert) => `${alert[yearProperty]}-${alert[weekProperty]}`)
);

// Iterate through the complete array and add missing values
const mockedAlerts = completeYearWeekArray.map((item) => {
const weekStartDate = startOfWeek(
new Date(item.year, 0, (item.week - 1) * 7),
{ weekStartsOn: 1 }
);
const weekEndDate = endOfWeek(new Date(item.year, 0, (item.week - 1) * 7), {
weekStartsOn: 1,
});

if (
isWithinInterval(weekStartDate, { start, end }) ||
isWithinInterval(weekEndDate, { start, end })
) {
const key = `${item.year}-${item.week}`;

if (!existingAlerts.has(key)) {
const mockedAlert = {
[yearProperty]: item.year,
[weekProperty]: item.week,
...filler,
};

return mockedAlert;
}
}

return null;
});

const allAlerts = [...alerts, ...mockedAlerts.filter((item) => !!item)];

// Sort the array again by year and week properties to maintain order
allAlerts.sort((a, b) => {
if (a[yearProperty] === b[yearProperty]) {
return a[weekProperty] - b[weekProperty];
}
return a[yearProperty] - b[yearProperty];
});

return allAlerts;
});

export const getData = createSelector(
[getAlerts, getLatest],
(data, latest) => {
[getAllAlerts, getLatest, getOptionsSelected],
(data, latest, options) => {
if (!data || isEmpty(data)) return null;

const { confidence } = options;
const parsedData = data.map((d) => ({
...d,
count: d.alert__count || d.area_ha,
count: d.alert__count || d.area_ha || 0,
week: parseInt(d.alert__week, 10),
year: parseInt(d.alert__year, 10),
}));
Expand Down Expand Up @@ -71,7 +157,7 @@ export const getData = createSelector(
};

years.forEach((year) => {
const yearDataByWeek = groupBy(groupedByYear[year], 'week');
const yearDataByWeek = toArray(groupBy(groupedByYear[year], 'week'));
const lastWeekOfYearIso = moment(`${year}-12-31`).isoWeek();
const yearLength = { [year]: moment(`${year}-12-31`).isoWeek() };

Expand All @@ -86,26 +172,38 @@ export const getData = createSelector(
}

for (let i = 1; i <= yearLength[year]; i += 1) {
if (Object.keys(yearDataByWeek).length < i) {
if (yearDataByWeek.length < i) {
return;
}

const alerts = [];
const yearDataLength = yearDataByWeek[i]
? yearDataByWeek[i].length - 1
: 0;

let objectsReduced = { count: 0, week: i, year: parseInt(year, 10) };

for (let index = 0; index <= yearDataLength; index += 1) {
if (yearDataByWeek[i]) {
objectsReduced = Object.assign(objectsReduced, {
...yearDataByWeek[i][index],
count: objectsReduced.count + yearDataByWeek[i][index].count,
});
alerts.push(yearDataByWeek[i][index]);
}
}

formattedData.push(objectsReduced);
if (confidence.value === 'h') {
formattedData.push(...alerts);
} else {
const allConfidencesAggregated = alerts.reduce(
(acc, curr) => {
return {
...curr,
confidence__cat: '', // high, low and normal
alert__count: acc?.alert__count + curr?.alert__count,
count: acc?.alert__count + curr?.alert__count,
};
},
{ alert__count: 0 }
);

formattedData.push(allConfidencesAggregated);
}
}
});

Expand Down Expand Up @@ -187,12 +285,13 @@ export const parseData = createSelector(
return {
...d,
compareYear,
compareCount: compareWeek ? compareWeek.count : null,
compareCount: compareWeek ? compareWeek.count : 0,
};
}

return d;
});

return parsedData;
}
);
Expand Down Expand Up @@ -270,7 +369,7 @@ export const parseConfig = createSelector(
unit: ` ${dataset.toUpperCase()} alerts`,
color: colors.main,
unitFormat: (value) =>
Number.isInteger(value) && formatNumber({ num: value, unit: ',' }),
Number.isInteger(value) ? formatNumber({ num: value, unit: ',' }) : 0,
},
];

Expand All @@ -289,17 +388,17 @@ export const parseConfig = createSelector(
color: '#49b5e3',
nullValue: 'No data available',
unitFormat: (value) =>
Number.isInteger(value) && formatNumber({ num: value, unit: ',' }),
Number.isInteger(value) ? formatNumber({ num: value, unit: ',' }) : 0,
});
}

return {
...getChartConfig(colors, moment(latest), {}, ''),
xAxis: {
dataKey: 'monthLabel',
tickCount: 12,
interval: 4,
scale: 'point',
tickFormatter: (t) => moment(t).format('MMM'),
interval: 0,
tickFormatter: (t) => t.charAt(0).toUpperCase() + t.slice(1),
...(typeof endIndex === 'number' &&
typeof startIndex === 'number' &&
endIndex - startIndex < 10 && {
Expand Down
35 changes: 23 additions & 12 deletions components/widgets/utils/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import concat from 'lodash/concat';
import maxBy from 'lodash/maxBy';
import minBy from 'lodash/minBy';
import sumBy from 'lodash/sumBy';
import upperCase from 'lodash/upperCase';
import moment from 'moment';
import range from 'lodash/range';
import upperCase from 'lodash';

const translateMeans = (means, latest) => {
if (!means || !means.length) return null;
Expand Down Expand Up @@ -309,17 +309,28 @@ export const getCumulativeStatsData = (data) => {
};

export const getDatesData = (data) =>
data.map((d) => ({
...d,
date: d.date
? moment(d.date).format('YYYY-MM-DD')
: moment()
.year(d.year)
.isoWeek(d.week)
.startOf('isoWeek')
.format('YYYY-MM-DD'),
month: upperCase(moment().year(d.year).isoWeek(d.week).format('MMM')),
}));
data.map((d, index) => {
const firstDayOfWeek = moment()
.year(d.year)
.isoWeek(d.week)
.startOf('isoWeek');

return {
...d,
...((firstDayOfWeek.date() <= 7 || index === 0) &&
d?.confidence__cat === 'h' && {
monthLabel: moment().year(d.year).isoWeek(d.week).format('MMM'),
}),
date: d.date
? moment(d.date).format('YYYY-MM-DD')
: moment()
.year(d.year)
.isoWeek(d.week)
.startOf('isoWeek')
.format('YYYY-MM-DD'),
month: upperCase(moment().year(d.year).isoWeek(d.week).format('MMM')),
};
});

export const getChartConfig = (
colors,
Expand Down
Loading