Skip to content

Commit

Permalink
perf: extract isConsumption checks to derived atom (#7164)
Browse files Browse the repository at this point in the history
  • Loading branch information
VIKTORVAV99 authored Oct 3, 2024
1 parent 1a2a50b commit a79ebeb
Show file tree
Hide file tree
Showing 21 changed files with 114 additions and 170 deletions.
6 changes: 2 additions & 4 deletions web/src/components/ZoneGauges.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useAtomValue } from 'jotai';
import { useTranslation } from 'react-i18next';
import { StateZoneData } from 'types';
import { Mode } from 'utils/constants';
import { getCarbonIntensity, getFossilFuelRatio, getRenewableRatio } from 'utils/helpers';
import { productionConsumptionAtom } from 'utils/state/atoms';
import { isConsumptionAtom } from 'utils/state/atoms';

import CarbonIntensitySquare from './CarbonIntensitySquare';
import { CircularGauge } from './CircularGauge';
Expand All @@ -18,8 +17,7 @@ export default function ZoneGaugesWithCO2Square({
withTooltips = false,
}: ZoneGaugesWithCO2SquareProps) {
const { t } = useTranslation();
const mixMode = useAtomValue(productionConsumptionAtom);
const isConsumption = mixMode === Mode.CONSUMPTION;
const isConsumption = useAtomValue(isConsumptionAtom);
const intensity = getCarbonIntensity(zoneData, isConsumption);
const renewable = getRenewableRatio(zoneData, isConsumption);
const fossilFuelPercentage = getFossilFuelRatio(zoneData, isConsumption);
Expand Down
15 changes: 10 additions & 5 deletions web/src/features/charts/BreakdownChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import { Factory, Zap } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { ElectricityModeType } from 'types';
import trackEvent from 'utils/analytics';
import { Mode, TimeAverages, TrackEvent } from 'utils/constants';
import { TimeAverages, TrackEvent } from 'utils/constants';
import { formatCo2 } from 'utils/formatting';
import { dataSourcesCollapsedBreakdownAtom, isHourlyAtom } from 'utils/state/atoms';
import {
dataSourcesCollapsedBreakdownAtom,
isConsumptionAtom,
isHourlyAtom,
} from 'utils/state/atoms';

import { ChartTitle } from './ChartTitle';
import { DataSources } from './DataSources';
Expand All @@ -35,7 +39,8 @@ function BreakdownChart({
datetimes,
timeAverage,
}: BreakdownChartProps) {
const { data, mixMode } = useBreakdownChartData();
const { data } = useBreakdownChartData();
const isConsumption = useAtomValue(isConsumptionAtom);
const [dataSourcesCollapsedBreakdown, setDataSourcesCollapsedBreakdown] = useAtom(
dataSourcesCollapsedBreakdownAtom
);
Expand All @@ -51,7 +56,7 @@ function BreakdownChart({
return null;
}

const isBreakdownGraphOverlayEnabled = mixMode === Mode.CONSUMPTION && !isHourly;
const isBreakdownGraphOverlayEnabled = isConsumption && !isHourly;

const { chartData, valueAxisLabel, layerFill, layerKeys } = data;

Expand All @@ -61,7 +66,7 @@ function BreakdownChart({
const formatAxisTick = (t: number) => formatCo2({ value: t, total: maxEmissions });

const titleDisplayMode = displayByEmissions ? 'emissions' : 'electricity';
const titleMixMode = mixMode === Mode.CONSUMPTION ? 'origin' : 'production';
const titleMixMode = isConsumption ? 'origin' : 'production';

const hasEnoughDataToDisplay = datetimes?.length > 2;

Expand Down
8 changes: 4 additions & 4 deletions web/src/features/charts/bar-breakdown/BarBreakdownChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { TrackEvent } from 'utils/constants';
import {
dataSourcesCollapsedBarBreakdownAtom,
displayByEmissionsAtom,
isConsumptionAtom,
isHourlyAtom,
productionConsumptionAtom,
} from 'utils/state/atoms';
import { useBreakpoint } from 'utils/styling';

Expand Down Expand Up @@ -59,14 +59,14 @@ function BarBreakdownChart({
const { t } = useTranslation();
const isBiggerThanMobile = useBreakpoint('sm');
const isHourly = useAtomValue(isHourlyAtom);
const [mixMode] = useAtom(productionConsumptionAtom);
const isConsumption = useAtomValue(isConsumptionAtom);
const width = observerWidth + X_PADDING;

const graphUnit = useMemo(
() =>
currentZoneDetail &&
determineUnit(displayByEmissions, currentZoneDetail, mixMode, isHourly, t),
[displayByEmissions, currentZoneDetail, mixMode, isHourly, t]
determineUnit(displayByEmissions, currentZoneDetail, isConsumption, isHourly, t),
[currentZoneDetail, displayByEmissions, isConsumption, isHourly, t]
);

const [tooltipData, setTooltipData] = useState<{
Expand Down
30 changes: 6 additions & 24 deletions web/src/features/charts/bar-breakdown/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Mode } from 'utils/constants';

import {
convertPrice,
ExchangeDataType,
Expand Down Expand Up @@ -348,11 +346,7 @@ describe('getExchangeData', () => {
exchange: { AT: -934, ES: 934 },
exchangeCapacities: { ES: exchangeCapacity, AT: exchangeCapacity },
};
const result = getExchangeData(
exchangeCapacitiesZoneDetailsData,
['ES', 'AT'],
Mode.CONSUMPTION
);
const result = getExchangeData(exchangeCapacitiesZoneDetailsData, ['ES', 'AT'], true);

expect(result).to.deep.eq([
{
Expand All @@ -375,11 +369,7 @@ describe('getExchangeData', () => {
const exchangeCapacitiesZoneDetailsData = {
...zoneDetailsData,
};
const result = getExchangeData(
exchangeCapacitiesZoneDetailsData,
['ES'],
Mode.CONSUMPTION
);
const result = getExchangeData(exchangeCapacitiesZoneDetailsData, ['ES'], true);

expect(result).to.deep.eq([
{
Expand All @@ -398,11 +388,7 @@ describe('getExchangeData', () => {
exchange: {},
exchangeCapacity: { ES: exchangeCapacity },
};
const result = getExchangeData(
exchangeCapacitiesZoneDetailsData,
['ES'],
Mode.CONSUMPTION
);
const result = getExchangeData(exchangeCapacitiesZoneDetailsData, ['ES'], true);

expect(result).to.deep.equal([
{
Expand All @@ -424,11 +410,7 @@ describe('getExchangeCo2Intensity', () => {
exchangeCo2Intensities: { ES: 999 },
};

const result = getExchangeCo2Intensity(
'ES',
exchangeCapacitiesZoneDetailsData,
Mode.CONSUMPTION
);
const result = getExchangeCo2Intensity('ES', exchangeCapacitiesZoneDetailsData, true);
expect(result).to.eq(999);
});
describe('when exchange value is less than 0', () => {
Expand All @@ -442,7 +424,7 @@ describe('getExchangeCo2Intensity', () => {
const result = getExchangeCo2Intensity(
'ES',
exchangeCapacitiesZoneDetailsData,
Mode.CONSUMPTION
true
);
expect(result).to.eq(187.32);
});
Expand All @@ -456,7 +438,7 @@ describe('getExchangeCo2Intensity', () => {
const result = getExchangeCo2Intensity(
'ES',
exchangeCapacitiesZoneDetailsData,
Mode.PRODUCTION
false
);
expect(result).to.eq(190.6);
});
Expand Down
10 changes: 5 additions & 5 deletions web/src/features/charts/bar-breakdown/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ZoneDetail,
ZoneKey,
} from 'types';
import { Mode, modeOrderBarBreakdown } from 'utils/constants';
import { modeOrderBarBreakdown } from 'utils/constants';
import { getProductionCo2Intensity, round } from 'utils/helpers';
import { EnergyUnits } from 'utils/units';

Expand All @@ -23,7 +23,7 @@ const DEFAULT_FLAG_SIZE = 16;
export function getExchangeCo2Intensity(
zoneKey: ZoneKey,
zoneData: ZoneDetail,
electricityMixMode: Mode
isConsumption: boolean
) {
const exchange = zoneData.exchange?.[zoneKey];
const exchangeCo2Intensity = zoneData.exchangeCo2Intensities?.[zoneKey];
Expand All @@ -33,7 +33,7 @@ export function getExchangeCo2Intensity(
}

// We don't use getCO2IntensityByMode in order to more easily return 0 for invalid numbers
if (electricityMixMode === Mode.CONSUMPTION) {
if (isConsumption) {
return zoneData.co2intensity || 0;
}

Expand Down Expand Up @@ -139,15 +139,15 @@ export interface ExchangeDataType {
export const getExchangeData = (
data: ZoneDetail,
exchangeKeys: ZoneKey[],
electricityMixMode: Mode
isConsumption: boolean
): ExchangeDataType[] =>
exchangeKeys.map((zoneKey: ZoneKey) => {
// Power in MW
const exchange = data.exchange?.[zoneKey];
const exchangeCapacityRange = data.exchangeCapacities?.[zoneKey] ?? [0, 0];

// Exchange CO₂ intensity
const gCo2eqPerkWh = getExchangeCo2Intensity(zoneKey, data, electricityMixMode);
const gCo2eqPerkWh = getExchangeCo2Intensity(zoneKey, data, isConsumption);
const gCo2eq = gCo2eqPerkWh * 1000 * exchange;

return {
Expand Down
15 changes: 7 additions & 8 deletions web/src/features/charts/graphUtils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ElectricityStorageType, ZoneDetail } from 'types';
import { Mode } from 'utils/constants';
import { describe, expect, it } from 'vitest';

import {
Expand Down Expand Up @@ -237,45 +236,45 @@ describe('getTotalEmissionsAvailable and ElectricityAvailable', () => {
} as ZoneDetail;

it('handles emissions for consumption', () => {
const actual = getTotalEmissionsAvailable(zoneData, Mode.CONSUMPTION);
const actual = getTotalEmissionsAvailable(zoneData, true);
expect(actual).to.deep.eq(175);
});

it('handles power for consumption', () => {
const actual = getTotalElectricityAvailable(zoneData, Mode.CONSUMPTION);
const actual = getTotalElectricityAvailable(zoneData, true);
expect(actual).to.deep.eq(350);
});

it('handles emissions for production', () => {
const actual = getTotalEmissionsAvailable(zoneData, Mode.PRODUCTION);
const actual = getTotalEmissionsAvailable(zoneData, false);
expect(actual).to.deep.eq(150);
});

it('returns NaN when missing productionValue', () => {
const actual = getTotalEmissionsAvailable(
{ ...zoneData, totalCo2Production: null } as unknown as ZoneDetail,
Mode.PRODUCTION
false
);
expect(actual).to.deep.eq(Number.NaN);
});

it('handles power for production', () => {
const actual = getTotalElectricityAvailable(zoneData, Mode.PRODUCTION);
const actual = getTotalElectricityAvailable(zoneData, false);
expect(actual).to.deep.eq(250);
});

it('returns 0 when productionValue is 0', () => {
const actual = getTotalElectricityAvailable(
{ ...zoneData, totalProduction: 0, totalDischarge: 0 },
Mode.PRODUCTION
false
);
expect(actual).to.deep.eq(0);
});

it('returns NaN when missing productionValue', () => {
const actual = getTotalElectricityAvailable(
{ ...zoneData, totalProduction: null },
Mode.PRODUCTION
false
);
expect(actual).to.deep.eq(Number.NaN);
});
Expand Down
27 changes: 14 additions & 13 deletions web/src/features/charts/graphUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TFunction } from 'i18next';
import { CircleDashed, LucideIcon, TrendingUpDown } from 'lucide-react';
import { MouseEvent } from 'react';
import { ElectricityStorageType, GenerationType, Maybe, ZoneDetail } from 'types';
import { EstimationMethods, Mode, modeOrder } from 'utils/constants';
import { EstimationMethods, modeOrder } from 'utils/constants';
import { formatCo2, formatEnergy, formatPower } from 'utils/formatting';

import { AreaGraphElement } from './types';
Expand Down Expand Up @@ -87,21 +87,22 @@ export const getGenerationTypeKey = (name: string): GenerationType | undefined =
};

/** Returns the total electricity that is available in the zone (e.g. production + discharge + imports) */
export function getTotalElectricityAvailable(zoneData: ZoneDetail, mixMode: Mode) {
const includeImports = mixMode === Mode.CONSUMPTION;
export function getTotalElectricityAvailable(
zoneData: ZoneDetail,
isConsumption: boolean
) {
const totalDischarge = zoneData.totalDischarge ?? 0;
const totalImport = zoneData.totalImport ?? 0;

if (zoneData.totalProduction === null) {
return Number.NaN;
}

return zoneData.totalProduction + totalDischarge + (includeImports ? totalImport : 0);
return zoneData.totalProduction + totalDischarge + (isConsumption ? totalImport : 0);
}

/** Returns the total emissions that is available in the zone (e.g. production + discharge + imports) */
export function getTotalEmissionsAvailable(zoneData: ZoneDetail, mixMode: Mode) {
const includeImports = mixMode === Mode.CONSUMPTION;
export function getTotalEmissionsAvailable(zoneData: ZoneDetail, isConsumption: boolean) {
const totalCo2Discharge = zoneData.totalCo2Discharge ?? 0;
const totalCo2Import = zoneData.totalCo2Import ?? 0;

Expand All @@ -110,9 +111,7 @@ export function getTotalEmissionsAvailable(zoneData: ZoneDetail, mixMode: Mode)
}

return (
zoneData.totalCo2Production +
totalCo2Discharge +
(includeImports ? totalCo2Import : 0)
zoneData.totalCo2Production + totalCo2Discharge + (isConsumption ? totalCo2Import : 0)
);
}

Expand All @@ -127,13 +126,13 @@ export const getNextDatetime = (datetimes: Date[], currentDate: Date) => {
export function determineUnit(
displayByEmissions: boolean,
currentZoneDetail: ZoneDetail,
mixMode: Mode,
isConsumption: boolean,
isHourly: boolean,
t: TFunction
) {
if (displayByEmissions) {
return getUnit(
formatCo2({ value: getTotalEmissionsAvailable(currentZoneDetail, mixMode) }) +
formatCo2({ value: getTotalEmissionsAvailable(currentZoneDetail, isConsumption) }) +
' ' +
t('ofCO2eq')
);
Expand All @@ -142,11 +141,13 @@ export function determineUnit(
return isHourly
? getUnit(
formatPower({
value: getTotalElectricityAvailable(currentZoneDetail, mixMode),
value: getTotalElectricityAvailable(currentZoneDetail, isConsumption),
})
)
: getUnit(
formatEnergy({ value: getTotalElectricityAvailable(currentZoneDetail, mixMode) })
formatEnergy({
value: getTotalElectricityAvailable(currentZoneDetail, isConsumption),
})
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import useGetZone from 'api/getZone';
import { useAtomValue } from 'jotai';
import { useParams } from 'react-router-dom';
import { Mode, SpatialAggregate } from 'utils/constants';
import { SpatialAggregate } from 'utils/constants';
import {
productionConsumptionAtom,
isConsumptionAtom,
selectedDatetimeStringAtom,
spatialAggregateAtom,
} from 'utils/state/atoms';
Expand All @@ -23,10 +23,9 @@ export default function useBarBreakdownChartData() {
const { zoneId } = useParams();
const viewMode = useAtomValue(spatialAggregateAtom);
const selectedDatetimeString = useAtomValue(selectedDatetimeStringAtom);
const mixMode = useAtomValue(productionConsumptionAtom);
const isCountryView = viewMode === SpatialAggregate.COUNTRY;
const currentData = zoneData?.zoneStates?.[selectedDatetimeString];
const isConsumption = mixMode === Mode.CONSUMPTION;
const isConsumption = useAtomValue(isConsumptionAtom);
if (isLoading) {
return { isLoading };
}
Expand All @@ -46,7 +45,7 @@ export default function useBarBreakdownChartData() {

const productionData = getProductionData(currentData); // TODO: Consider memoing this
const exchangeData = isConsumption
? getExchangeData(currentData, exchangeKeys, mixMode)
? getExchangeData(currentData, exchangeKeys, isConsumption)
: []; // TODO: Consider memoing this

const { exchangeY } = getDataBlockPositions(
Expand Down
Loading

0 comments on commit a79ebeb

Please sign in to comment.