Commit 16d00e88 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Merge branch 'wip_temperature-diff-fix' into 'master'

Edit calculation of temperature difference

Tweaks and bug fixes to the logic for calculation of temperature 
difference

See merge request !19
parents e02c4e2a 8b900e1d
......@@ -163,10 +163,9 @@ const calculateMinimumObservationValuesWithinInterval = function (
)
);
}
// Calculate minimum values of observations - monthly
// Note the use of the two nested `map` methods
if (aggregationInterval === "monthly") {
else if (aggregationInterval === "monthly") {
return uniqueCalendarDatesOrMonthsArr.map((uniqueCalendarMonthsArr, i) =>
uniqueCalendarMonthsArr.map((uniqueCalendarMonth) =>
calculateMinimumObservationValuesWithinMonthInterval(
......@@ -211,10 +210,9 @@ const calculateMaximumObservationValuesWithinInterval = function (
)
);
}
// Calculate maximum values of observations - monthly
// Note the use of the two nested `map` methods
if (aggregationInterval === "monthly") {
else if (aggregationInterval === "monthly") {
return uniqueCalendarDatesOrMonthsArr.map((uniqueCalendarMonthsArr, i) =>
uniqueCalendarMonthsArr.map((uniqueCalendarMonth) =>
calculateMaximumObservationValuesWithinMonthInterval(
......@@ -259,10 +257,9 @@ const calculateSumOfObservationValuesWithinInterval = function (
)
);
}
// Calculate sum of values of observations - monthly
// Note the use of the two nested `map` methods
if (aggregationInterval === "monthly") {
else if (aggregationInterval === "monthly") {
return uniqueCalendarDatesOrMonthsArr.map((uniqueCalendarMonthsArr, i) =>
uniqueCalendarMonthsArr.map((uniqueCalendarMonth) =>
calculateSumOfObservationValuesWithinMonthInterval(
......@@ -307,10 +304,9 @@ const calculateAverageOfObservationValuesWithinInterval = function (
)
);
}
// Calculate average of values of observations - monthly
// Note the use of the two nested `map` methods
if (aggregationInterval === "monthly") {
else if (aggregationInterval === "monthly") {
return uniqueCalendarDatesOrMonthsArr.map((uniqueCalendarMonthsArr, i) =>
uniqueCalendarMonthsArr.map((uniqueCalendarMonth) =>
calculateAverageOfObservationValuesWithinMonthInterval(
......
......@@ -16,18 +16,17 @@ const createTimeStringsForInterval = function (phenomenonSamplingRate) {
if (
phenomenonSamplingRate !== fifteenMinutes &&
phenomenonSamplingRate !== sixtyMinutes
)
) {
throw new Error(
`Check that the provided phenomenon sampling rate string is in this format: "15min" or "60min"`
);
}
// 15 min sampling rate
if (phenomenonSamplingRate === fifteenMinutes) {
else if (phenomenonSamplingRate === fifteenMinutes) {
return [startTime, endTimeFifteenMinutes];
}
// 60 min sampling rate
if (phenomenonSamplingRate === sixtyMinutes) {
else if (phenomenonSamplingRate === sixtyMinutes) {
return [startTime, endTimeSixtyMinutes];
}
};
......@@ -66,13 +65,15 @@ const getIndexOfTimestamp = function (inputTimestampArr, timestampOfInterest) {
);
// If the timestamp does not exist in the timestamp array
if (timestampIndex === -1)
if (timestampIndex === -1) {
throw new Error(
"A start or end timestamp could not be found in the timestamp array"
);
}
// If the timestamp exists in the timestamp array
return timestampIndex;
else {
return timestampIndex;
}
};
/**
......@@ -210,47 +211,56 @@ const extractObservationValuesWithinMonthInterval = function (
const [yearNum, monthNum] =
extractMonthYearDigitsFromCalendarMonthString(calendarMonthStr);
if (monthNum < 1 || monthNum > 12) return;
// All the months start on the first
const startDateStr = `${calendarMonthStr}-01`;
if (monthNum < 1 || monthNum > 12) {
throw new Error("The specified digit for the month of the year is invalid");
}
// February
if (monthNum === 2) {
else if (monthNum === 2) {
// Leap year
if (checkIfLeapYear(yearNum))
if (checkIfLeapYear(yearNum)) {
return extractObservationValuesWithinDatesInterval(
obsArray,
samplingRate,
startDateStr,
`${calendarMonthStr}-29`
);
}
// Non-leap year
else {
return extractObservationValuesWithinDatesInterval(
obsArray,
samplingRate,
startDateStr,
`${calendarMonthStr}-28`
);
}
}
// Months with 30 days
else if (
monthNum === 4 ||
monthNum === 6 ||
monthNum === 9 ||
monthNum === 11
) {
return extractObservationValuesWithinDatesInterval(
obsArray,
samplingRate,
startDateStr,
`${calendarMonthStr}-28`
`${calendarMonthStr}-30`
);
}
// Months with 30 days
if (monthNum === 4 || monthNum === 6 || monthNum === 9 || monthNum === 11)
// Months with 31 days
else {
return extractObservationValuesWithinDatesInterval(
obsArray,
samplingRate,
startDateStr,
`${calendarMonthStr}-30`
`${calendarMonthStr}-31`
);
// Months with 31 days
return extractObservationValuesWithinDatesInterval(
obsArray,
samplingRate,
startDateStr,
`${calendarMonthStr}-31`
);
}
};
/**
......
"use strict";
import { checkForAndDeleteUniqueObservationsFromLargerArray } from "./chartHelpers.mjs";
import {
checkForAndDeleteUniqueObservationsFromLargerArray,
extractSamplingRateFromDatastreamName,
extractBuildingIdFromDatastreamName,
} from "./chartHelpers.mjs";
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fetchData.mjs";
import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcessing.mjs";
/**
* Calculate the temperature difference, dT, between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL) for a single building
*
* @param {Array} observationsPlusMetadataArr A 1*2 array, where the first element is an array made up of two arrays of observations and the second element is an array of two metadata objects
* @returns {Array} An array made up of timestamps + values for dT
*/
const calculateVorlaufMinusRuecklaufTemperatureObservations = function (
observationsPlusMetadataArr
) {
// Extract Vorlauf temperature, Ruecklauf temperature; first element of array
const [[vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr]] =
observationsPlusMetadataArr;
// Compare the lengths of the observations arrays for VL and RL,
// delete the unique observation(s), if necessary
const [vorlaufTemperatureObsFinalArr, ruecklaufTemperatureObsFinalArr] =
vorlaufTemperatureObsArr.length === ruecklaufTemperatureObsArr.length
? [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr]
: checkForAndDeleteUniqueObservationsFromLargerArray(
vorlaufTemperatureObsArr,
ruecklaufTemperatureObsArr
);
// Extract the temperature values
const vorlaufTemperatureValues = vorlaufTemperatureObsFinalArr.map(
(vlTempObs) => vlTempObs[1]
);
const ruecklaufTemperatureValues = ruecklaufTemperatureObsFinalArr.map(
(rlTempObs) => rlTempObs[1]
);
// Check that the final observation arrays have equal lengths
if (
vorlaufTemperatureObsFinalArr.length !==
ruecklaufTemperatureObsFinalArr.length
) {
throw new Error(
"The two observations arrays (VL and RL) have different lengths"
);
}
// The final observation arrays now have equal length, we need only use one of them for looping
// Resulting array contains the following pairs (timestamp + dT)
else {
return vorlaufTemperatureObsFinalArr.map((vlTempObsFinal, i) => {
// Use timestamp from VL, since is equal to that of RL
const timestamp = vlTempObsFinal[0];
// Case 1: One of the observation values is `null`,
// no need to calculate temperature difference
// Case 2: Neither of the observation values is `null`,
// calculate temperature difference
return vorlaufTemperatureValues[i] === null ||
ruecklaufTemperatureValues[i] === null
? [timestamp, null]
: [
timestamp,
vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i],
];
});
}
};
/**
* Create synthetic metadata for the temperature difference, dT, between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL) of a single building
*
* @param {Array} observationsPlusMetadataArr A 1*2 array, where the first element is an array made up of two arrays of observations and the second element is an array of two metadata objects
* @returns {Object} A metadata object for dT, made up of three properties: description, name and unit of measurement
*/
const createVorlaufMinusRuecklaufTemperatureMetadata = function (
observationsPlusMetadataArr
) {
// Extract metadata; second element of array, note that we skip the first element
const [, [metadataVorlauf, metadataRuecklauf]] = observationsPlusMetadataArr;
// From Vorlauf metadata, extract `name` and `unitOfMeasurement`
const {
name: datastreamNameVorlauf,
unitOfMeasurement: unitOfMeasurementVorlauf,
} = metadataVorlauf;
// From Ruecklauf metadata, extract `name`
const { name: datastreamNameRuecklauf } = metadataRuecklauf;
// Extract the phenomenon names from the Datastream names
const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
datastreamNameVorlauf
);
const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
);
// Create our custom datastream description text
// The resulting datastream description string has two `temperature` substrings;
// replace the first occurence with an empty string
const descriptionTempDifference =
`Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
"temperature",
""
);
// Create an array of the VL datastream name, this array has only one element.
// We need this structure since the functions `extractBuildingIdFromDatastreamName`
// and `extractSamplingRateFromDatastreamName` expect an array of datastream names
const datastreamNameVorlaufArr = [datastreamNameVorlauf];
// Extract the building ID from the datastream name
const buildingId = extractBuildingIdFromDatastreamName(
datastreamNameVorlaufArr
);
// Extract the sampling rate from the datastream name
const samplingRate = extractSamplingRateFromDatastreamName(
datastreamNameVorlaufArr
);
// Create our custom datastream name text
const nameTempDifference = `${buildingId} / dT Temperature difference (VL-RL) DS:${samplingRate}`;
return {
descriptionTempDifference,
nameTempDifference,
unitOfMeasurementVorlauf,
};
};
/**
* Calculate the temperature difference, dT, between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL). In addition, create synthetic metadata
......@@ -37,13 +168,6 @@ export const calculateVorlaufMinusRuecklaufTemperature = async function (
// Note: We have to use a for/of loop here due to the asynchronous nature of our code
for (const bldgDataPtSamplingRateNestedArr of buildingDataPointSamplingRateNestedTwiceArr) {
// Use the first element of the nested array to extract building ID + sampling rate
// Note: we skip the second element
const [buildingId, , samplingRate] = bldgDataPtSamplingRateNestedArr[0];
const BUILDING_ID = buildingId;
const SAMPLING_RATE = samplingRate;
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
baseUrl,
......@@ -51,83 +175,20 @@ export const calculateVorlaufMinusRuecklaufTemperature = async function (
bldgDataPtSamplingRateNestedArr
);
// Extract Vorlauf temperature, Ruecklauf temperature and metadata
const [
[vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr],
[metadataVorlauf, metadataRuecklauf],
] = observationsPlusMetadata;
// Compare the lengths of the observations arrays for VL and RL,
// delete the unique observation(s), if necessary
const [vorlaufTemperatureObsFinalArr, ruecklaufTemperatureObsFinalArr] =
vorlaufTemperatureObsArr.length === ruecklaufTemperatureObsArr.length
? [vorlaufTemperatureObsArr, ruecklaufTemperatureObsArr]
: checkForAndDeleteUniqueObservationsFromLargerArray(
vorlaufTemperatureObsArr,
ruecklaufTemperatureObsArr
);
// Extract the temperature values
const vorlaufTemperatureValues = vorlaufTemperatureObsFinalArr.map(
(vlTempObs) => vlTempObs[1]
);
const ruecklaufTemperatureValues = ruecklaufTemperatureObsFinalArr.map(
(rlTempObs) => rlTempObs[1]
);
// The arrays have equal length, we need only use one of them for looping
// Resulting array contains the following pairs (timestamp + dT)
const vorlaufMinusRuecklaufTemperatureObs = vorlaufTemperatureObsArr.map(
(vlTempObs, i) => {
// Use timestamp from VL, since is equal to that of RL
const timestamp = vlTempObs[0];
// Case 1: One of the observation values is `null`,
// no need to calculate temperature difference
if (
vorlaufTemperatureValues[i] === null ||
ruecklaufTemperatureValues[i] === null
) {
return [timestamp, null];
}
// Case 2: Neither of the observation values is `null`,
// calculate temperature difference
return [
timestamp,
vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i],
];
}
);
// dT observations (timestamp + value)
const vorlaufMinusRuecklaufTemperatureObs =
calculateVorlaufMinusRuecklaufTemperatureObservations(
observationsPlusMetadata
);
// From Vorlauf metadata, extract `name` and `unitOfMeasurement`
// dT metadata
const {
name: datastreamNameVorlauf,
unitOfMeasurement: unitOfMeasurementVorlauf,
} = metadataVorlauf;
// From Ruecklauf metadata, extract `name`
const { name: datastreamNameRuecklauf } = metadataRuecklauf;
// Extract the phenomenon names from the Datastream names
const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
datastreamNameVorlauf
descriptionTempDifference,
nameTempDifference,
unitOfMeasurementVorlauf,
} = createVorlaufMinusRuecklaufTemperatureMetadata(
observationsPlusMetadata
);
const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
);
// Create our custom datastream description text
// The resulting datastream description string has two `temperature` substrings;
// replace the first occurence with an empty string
const descriptionTempDifference =
`Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
"temperature",
""
);
// Create our custom datastream name text
const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`;
// The datastream object that we return needs to have these property names
const description = descriptionTempDifference;
......
......@@ -48,20 +48,21 @@ const createSeriesOptionsForColumnChart = function (
if (
formattedAggregatedResultForColumnChart.length !==
buildingIdsPhenomenonNamesArr.length
)
) {
throw new Error(
"The observations array and phenomenon names array have different lengths"
);
return formattedAggregatedResultForColumnChart.map(
(formattedAggResArray, i) => {
return {
name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedAggResArray,
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
};
}
);
} else {
return formattedAggregatedResultForColumnChart.map(
(formattedAggResArray, i) => {
return {
name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedAggResArray,
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
};
}
);
}
};
/**
......@@ -83,16 +84,17 @@ const drawColumnChartHighcharts = function (
aggregationType;
// Check whether the datastream properties are for aggregated observations
// Case 1: No aggregation
if (extractedFormattedDatastreamProperties?.aggregationType === undefined) {
// Case 1: No aggregation
({
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
} = extractedFormattedDatastreamProperties);
} else {
// Case 2: Aggregation
}
// Case 2: Aggregation
else {
({
datastreamNamesArr,
phenomenonNamesArr,
......
......@@ -53,18 +53,18 @@ const removeUniqueObservationsFromLargerArray = function (
largerObsArr
) {
// Create a reversed copy of the indexes array, so that the larger index is removed first
const reversedUniqueIndexesArr = uniqueIndexesArr.reverse();
const uniqueIndexesReversedCopyArr = [...uniqueIndexesArr].reverse();
// Create a copy the larger observation array, will be modified in place
const processedLargerObsArr = largerObsArr;
// Create a copy of the larger observation array, will be modified in place
const largerObsCopyArr = [...largerObsArr];
reversedUniqueIndexesArr.forEach((index) => {
if (index > -1) {
processedLargerObsArr.splice(index, 1);
uniqueIndexesReversedCopyArr.forEach((uniqueIndex) => {
if (uniqueIndex > -1) {
largerObsCopyArr.splice(uniqueIndex, 1);
}
});
return processedLargerObsArr;
return largerObsCopyArr;
};
/**
......@@ -75,10 +75,11 @@ const removeUniqueObservationsFromLargerArray = function (
*/
const getLargerArrayBetweenTwoInputArrays = function (firstArr, secondArr) {
if (firstArr.length === secondArr.length) return;
if (firstArr.length > secondArr.length) return firstArr;
if (firstArr.length < secondArr.length) return secondArr;
else if (firstArr.length > secondArr.length) {
return firstArr;
} else if (firstArr.length < secondArr.length) {
return secondArr;
}
};
/**
......@@ -89,10 +90,11 @@ const getLargerArrayBetweenTwoInputArrays = function (firstArr, secondArr) {
*/
const getSmallerArrayBetweenTwoInputArrays = function (firstArr, secondArr) {
if (firstArr.length === secondArr.length) return;
if (firstArr.length < secondArr.length) return firstArr;
if (firstArr.length > secondArr.length) return secondArr;
else if (firstArr.length < secondArr.length) {
return firstArr;
} else if (firstArr.length > secondArr.length) {
return secondArr;
}
};
/**
......@@ -162,17 +164,17 @@ const checkForAndDeleteUniqueObservationsFromLargerArray = function (
obsArrayTwo
) {
if (obsArrayOne.length === obsArrayTwo.length) return;
// Case 1: obsArrayOne.length < obsArrayTwo.length
if (obsArrayOne.length < obsArrayTwo.length) {
// Case 1: obsArrayTwo larger than obsArrayOne
else if (obsArrayOne.length < obsArrayTwo.length) {
const [biggerObsArr, smallerObsArr] =
deleteUniqueObservationsFromLargerArray(obsArrayOne, obsArrayTwo);
return [smallerObsArr, biggerObsArr];
}
// Case 2: obsArrayOne.length > obsArrayTwo.length
return deleteUniqueObservationsFromLargerArray(obsArrayOne, obsArrayTwo);
// Case 2: obsArrayOne larger than obsArrayTwo
else if (obsArrayOne.length > obsArrayTwo.length) {
return deleteUniqueObservationsFromLargerArray(obsArrayOne, obsArrayTwo);
}
};
/**
......@@ -194,14 +196,16 @@ const convertHexColorToRGBColor = function (hexCode) {
"#91e8e1": "rgb(145, 232, 225)",
};
if (hexToRGBMapping?.[hexCode] === undefined)
if (hexToRGBMapping?.[hexCode] === undefined) {
throw new Error(
"The provided hex code is not valid or is not supported by this function"
);
}
// Extract the RGB color elements as a single string
// The individual color elements are separated by commas
return (hexToRGBMapping?.[hexCode]).slice(4, -1);
else {
return (hexToRGBMapping?.[hexCode]).slice(4, -1);
}
};
/**
......@@ -264,11 +268,13 @@ const createPartialTitleForLineOrColumnChart = function (
) {
// Case 1: No aggregation; return empty string
if (!aggregationInterval && !aggregationType) return ``;
// Case 2: Aggregation; capitalize the first characters
return `${
aggregationInterval.slice(0, 1).toUpperCase() + aggregationInterval.slice(1)
} ${aggregationType.slice(0, 1).toUpperCase() + aggregationType.slice(1)}`;
else {
return `${
aggregationInterval.slice(0, 1).toUpperCase() +
aggregationInterval.slice(1)
} ${aggregationType.slice(0, 1).toUpperCase() + aggregationType.slice(1)}`;
}
};
/**
......@@ -289,12 +295,13 @@ const createFullTitleForLineOrColumnChart = function (
aggregationInterval,
aggregationType
)}${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
// Case 2: Aggregation
return `${createPartialTitleForLineOrColumnChart(
aggregationInterval,
aggregationType
)}: ${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
else {
return `${createPartialTitleForLineOrColumnChart(
aggregationInterval,
aggregationType
)}: ${createCombinedTextDelimitedByComma(phenomenonNamesArr)}`;
}
};
/**
......@@ -376,6 +383,8 @@ export {
checkForAndDeleteUniqueObservationsFromLargerArray,
createCombinedTextDelimitedByAmpersand,
createCombinedTextDelimitedByComma,
extractSamplingRateFromDatastreamName,
extractBuildingIdFromDatastreamName,
createFullTitleForLineOrColumnChart,
createTitleForHeatmap,
createSubtitleForChart,
......
......@@ -53,19 +53,20 @@ const createSeriesOptionsForLineChart = function (
if (
formattedObsArraysForLineChart.length !==
buildingIdsPhenomenonNamesArr.length
)
) {
throw new Error(
"The observations array and phenomenon names array have different lengths"
);
return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
return {
name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedObsArray,
color: seriesColorsArr[i],
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
};
});
} else {
return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
return {
name: `${buildingIdsPhenomenonNamesArr[i]}`,
data: formattedObsArray,
color: seriesColorsArr[i],
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
};
});
}
};
/**
......
......@@ -45,9 +45,10 @@ const formatSensorThingsApiResponseForScatterPlot = function (
return createCombinedObservationValues(obsArrayOneFinal, obsArrayTwoFinal);
}
// When our observation arrays already have SAME lengths
return createCombinedObservationValues(obsArrayOne, obsArrayTwo);
else {
return createCombinedObservationValues(obsArrayOne, obsArrayTwo);
}
};
/**
......@@ -105,21 +106,22 @@ const createYAxisTitleTextScatterPlot = function (
// y-axis phenomenon symbols start at array index 1
const unitOfMeasurementSymbolsYAxisArr = unitOfMeasurementSymbolsArr.slice(1);
const combinedNameSymbolArr = phenomenonNamesYAxisArr.map(
(phenomenonNameYAxis, i) =>
`${phenomenonNameYAxis} [${unitOfMeasurementSymbolsYAxisArr[i]}]`
);
// The phenomenon names and unit of measurement arrays should have equal lengths
// Use one of the arrays for looping
if (
phenomenonNamesYAxisArr.length !== unitOfMeasurementSymbolsYAxisArr.length
)
) {
throw new Error(
"The phenomenon names array and unit of measurement symbols array have different lengths"
);
const combinedNameSymbolArr = phenomenonNamesYAxisArr.map(
(phenomenonNameYAxis, i) =>
`${phenomenonNameYAxis} [${unitOfMeasurementSymbolsYAxisArr[i]}]`
);
return createCombinedTextDelimitedByComma(combinedNameSymbolArr);
} else {
return createCombinedTextDelimitedByComma(combinedNameSymbolArr);
}
};
/**
......@@ -159,18 +161,19 @@ const createSeriesOptionsForScatterPlot = function (
// Use one of the arrays for looping
if (
formattedObsArraysForScatterPlot.length !== phenomenonNamesYAxisArr.length
)
) {
throw new Error(
"The observations array and phenomenon names array have different lengths"
);
return formattedObsArraysForScatterPlot.map((formattedObsArray, i) => {
return {
name: `${phenomenonNamesYAxisArr[i]}, ${phenomenonNameXAxis}`,
data: formattedObsArray,
color: seriesColors[i],
};
});
} else {
return formattedObsArraysForScatterPlot.map((formattedObsArray, i) => {
return {
name: `${phenomenonNamesYAxisArr[i]}, ${phenomenonNameXAxis}`,
data: formattedObsArray,
color: seriesColors[i],
};
});
}
};
/**
......
......@@ -111,24 +111,22 @@ const getSelectedOptionsFromAllDropDownLists = function () {
);
// Ensure that all the options have at least one selection
if (selectedChartTypeArr.length === 0)
if (selectedChartTypeArr.length === 0) {
throw new Error("Please ensure that the chart type is selected");
if (selectedBuildingDataPointOptionsSplitArr.length === 0)
} else if (selectedBuildingDataPointOptionsSplitArr.length === 0) {
throw new Error("Please ensure that at least one data point is selected");
if (selectedSamplingRateArr.length === 0)
} else if (selectedAggregationOptionsArr.length === 0) {
throw new Error("Please ensure that the aggregation type is selected");
if (selectedSamplingRateArr.length === 0)
} else if (selectedSamplingRateArr.length === 0) {
throw new Error("Please ensure that the sampling rate is selected");
return [
selectedChartTypeArr,
selectedBuildingDataPointOptionsSplitArr,
selectedAggregationOptionsArr,
selectedSamplingRateArr,
];
} else {
return [
selectedChartTypeArr,
selectedBuildingDataPointOptionsSplitArr,
selectedAggregationOptionsArr,
selectedSamplingRateArr,
];
}
};
/**
......@@ -231,14 +229,6 @@ const extractTemperatureDifferenceOptions = function (
const bldgDataPntSamplingRateAbbrvArr =
buildingDataPointSamplingRateAbbrevArr[foundIndex];
// Extract the building and sampling rate strings
// Note: we have ignored the second element
// const [bldgAbbrv, , samplingRateAbbrv] = bldgDataPntSamplingRateAbbrvArr;
// Create a new array that contains two elements,
// the building and sampling rate abbreviated strings
// const bldgSamplingRateAbbrvArr = [bldgAbbrv, samplingRateAbbrv];
temperatureDifferenceOptionsAbbrevArr.push(bldgDataPntSamplingRateAbbrvArr);
});
......@@ -326,9 +316,8 @@ const checkIfSelectedBuildingDataPointsOptionsAreValid = function (
throw new Error("A heatmap can only display one data point at a time");
}
}
// A scatter plot requires at least two data points
if (selectedChartType === "Scatter Plot") {
else if (selectedChartType === "Scatter Plot") {
if (selectedBuildingsDataPointsSamplingRateAbbrevNestedArr.length >= 2)
return true;
else if (
......@@ -418,29 +407,6 @@ const getBuildingSensorSamplingRateAbbreviation = function (
},
};
if (
fullFormToAbbreviationMapping["buildings"]?.[buildingFullForm] === undefined
)
throw new Error(
"The provided building ID is not valid or is not supported by this function"
);
if (
fullFormToAbbreviationMapping["phenomenon"]?.[phenomenonFullForm] ===
undefined
)
throw new Error(
"The provided data point is not valid or is not supported by this function"
);
if (
fullFormToAbbreviationMapping["samplingRate"]?.[samplingRateFullForm] ===
undefined
)
throw new Error(
"The provided sampling rate is not valid or is not supported by this function"
);
const buildingAbbrev =
fullFormToAbbreviationMapping["buildings"]?.[buildingFullForm];
......@@ -450,7 +416,21 @@ const getBuildingSensorSamplingRateAbbreviation = function (
const samplingRateAbbrev =
fullFormToAbbreviationMapping["samplingRate"]?.[samplingRateFullForm];
return [buildingAbbrev, phenomenonAbbrev, samplingRateAbbrev];
if (buildingAbbrev === undefined) {
throw new Error(
"The provided building ID is not valid or is not supported by this function"
);
} else if (phenomenonAbbrev === undefined) {
throw new Error(
"The provided data point is not valid or is not supported by this function"
);
} else if (samplingRateAbbrev === undefined) {
throw new Error(
"The provided sampling rate is not valid or is not supported by this function"
);
} else {
return [buildingAbbrev, phenomenonAbbrev, samplingRateAbbrev];
}
};
/**
......@@ -483,18 +463,19 @@ const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function (
// Assume that the buildings and data points arrays have equal length
// use one of the arrays for looping
if (selectedBuildingsArr.length !== selectedDataPointsArr.length)
if (selectedBuildingsArr.length !== selectedDataPointsArr.length) {
throw new Error(
"The buildings array and data points array have different lengths"
);
return selectedBuildingsArr.map((selectedBuilding, i) =>
getBuildingSensorSamplingRateAbbreviation(
selectedBuilding,
selectedDataPointsArr[i],
...selectedSamplingRateArr
)
);
} else {
return selectedBuildingsArr.map((selectedBuilding, i) =>
getBuildingSensorSamplingRateAbbreviation(
selectedBuilding,
selectedDataPointsArr[i],
...selectedSamplingRateArr
)
);
}
};
export {
......
......@@ -11,14 +11,18 @@ const matchUnitOfMeasurementSymbolStringToSymbol = function (
const unicodeCodePointDegreeSymbol = "\u00B0";
const unicodeCodePointSuperscriptThree = "\u00B3";
if (unitOfMeasurementSymbolString === "degC")
// Symbol - temperature
if (unitOfMeasurementSymbolString === "degC") {
return `${unicodeCodePointDegreeSymbol}C`;
if (unitOfMeasurementSymbolString === "m3/h")
}
// Symbol - flow rate
else if (unitOfMeasurementSymbolString === "m3/h") {
return `m${unicodeCodePointSuperscriptThree}/h`;
}
// If no symbol exists
return unitOfMeasurementSymbolString;
else {
return unitOfMeasurementSymbolString;
}
};
/**
......@@ -94,39 +98,37 @@ const extractPropertiesFromFormattedDatastreamMetadata = function (
if (
formattedDatastreamsMetadataArr === undefined ||
isMetadataForAggregation === undefined
)
) {
throw new Error(
"This function expects two arguments, ensure that both have been supplied"
);
if (
} else if (
formattedDatastreamsMetadataArr &&
isMetadataForAggregation &&
(aggregationInterval === undefined || aggregationType === undefined)
)
) {
throw new Error(
"This function expects four arguments, ensure that all of them have been supplied"
);
if (
} else if (
isMetadataForAggregation &&
aggregationInterval !== "daily" &&
aggregationInterval !== "monthly"
)
) {
throw new Error(
`The supported aggegation interval strings are "daily" or "monthly"`
);
if (
} else if (
isMetadataForAggregation &&
aggregationType !== "minimum" &&
aggregationType !== "maximum" &&
aggregationType !== "sum" &&
aggregationType !== "average"
)
) {
throw new Error(
`The supported aggegation type strings are "minimum", "maximum", "sum" or "average"`
);
}
// Create arrays from the properties of the formatted datastream metadata
const datastreamDescriptionsArr = formattedDatastreamsMetadataArr.map(
......@@ -150,7 +152,7 @@ const extractPropertiesFromFormattedDatastreamMetadata = function (
);
// Case 1: Metadata NOT USED for aggregation; "isMetadataForAggregation" = false
if (!isMetadataForAggregation)
if (!isMetadataForAggregation) {
return {
datastreamDescriptionsArr,
datastreamNamesArr,
......@@ -158,17 +160,19 @@ const extractPropertiesFromFormattedDatastreamMetadata = function (
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
};
}
// Case 2: Metadata USED for aggregation; "isMetadataForAggregation" = true
return {
datastreamDescriptionsArr,
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
aggregationInterval,
aggregationType,
};
else {
return {
datastreamDescriptionsArr,
datastreamNamesArr,
phenomenonNamesArr,
buildingIdsPhenomenonNamesArr,
unitOfMeasurementSymbolsArr,
aggregationInterval,
aggregationType,
};
}
};
export {
......
......@@ -82,14 +82,27 @@ export const getDatastreamIdFromBuildingNumber = function (
},
};
if (
if (buildingToDatastreamMapping?.[buildingNumber] === undefined) {
throw new Error(
"The supplied building number is not valid or is not supported by this function"
);
} else if (
buildingToDatastreamMapping?.[buildingNumber]?.[phenomenon] === undefined
) {
throw new Error(
"The supplied phenomenon name is not valid or is not supported by this function"
);
} else if (
buildingToDatastreamMapping?.[buildingNumber]?.[phenomenon]?.[
samplingRate
] === undefined
)
return;
return Number(
buildingToDatastreamMapping[buildingNumber][phenomenon][samplingRate]
);
) {
throw new Error(
"The supplied sampling rate is not valid or is not supported by this function"
);
} else {
return Number(
buildingToDatastreamMapping[buildingNumber][phenomenon][samplingRate]
);
}
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment