Commit 35dc06f4 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

New function: callback function that draws chart

Function uses options from drop-down list that have been selected by a
user to populate the appropriate observations and then draw the
appropriate chart
parent 59f58680
......@@ -69,7 +69,6 @@
Custom JS -->
<script defer type="module" src="js/appCesium.js"></script>
<script defer type="module" src="js/appChart.js"></script>
<script defer type="module" src="js/dropDownList.js"></script>
</head>
<body class="sb-nav-fixed">
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
......@@ -131,6 +130,21 @@
<label for="droneMode">Drone View</label>
</div>
<br /> -->
<div id="drop-down--chart-type-parent">
<span><strong>Chart type</strong></span>
<div class="nowrap">
<!-- We need the `multiple` attribute for the dropdowns even if
we do not need to support multiple selections. This seems to
be a quirk of the `vanillaSelectBox` library -->
<select id="drop-down--chart-type" multiple>
<option>Column</option>
<option>Line</option>
<option>Heatmap</option>
<option>Scatter Plot</option>
</select>
</div>
</div>
<br />
<div id="drop-down--bldg-data-point-parent">
<span><strong>Building(s), Data Point(s)</strong></span>
<div class="nowrap">
......@@ -140,6 +154,9 @@
size="5"
>
<!-- Note: The values of the option elements have to be unique -->
<optgroup label="Other">
<option>Außentemp</option>
</optgroup>
<optgroup label="Bau 101">
<option>101/VL</option>
<option>101/RL</option>
......@@ -174,9 +191,6 @@
<option>225/Energie</option>
<option>225/Energie_VERBR</option>
</optgroup>
<optgroup label="Other">
<option>Außentemp</option>
</optgroup>
</select>
</div>
</div>
......@@ -216,21 +230,6 @@
</div>
</div>
<br />
<div id="drop-down--chart-type-parent">
<span><strong>Chart type</strong></span>
<div class="nowrap">
<!-- We need the `multiple` attribute for the dropdowns even if
we do not need to support multiple selections. This seems to
be a quirk of the `vanillaSelectBox` library -->
<select id="drop-down--chart-type" multiple>
<option>Column</option>
<option>Line</option>
<option>Heatmap</option>
<option>Scatter Plot</option>
</select>
</div>
</div>
<br />
<button id="btn-draw-chart">Draw Chart</button>
<!-- <span><strong>Display Options</strong></span>
<div class="nowrap">
......
......@@ -5,765 +5,380 @@ import {
QUERY_PARAMS_COMBINED,
} from "./src_modules/baseUrlPlusQueryParams.mjs";
import {
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs";
import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs";
import {
formatSensorThingsApiResponseForHeatMap,
drawHeatMapHighcharts,
} from "./src_modules/chartHeatmap.mjs";
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./src_modules/fetchData.mjs";
import {
formatSensorThingsApiResponseForScatterPlot,
drawScatterPlotHighcharts,
} from "./src_modules/chartScatterPlot.mjs";
formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";
import {
formatAggregationResultForColumnChart,
drawColumnChartHighcharts,
} from "./src_modules/chartColumn.mjs";
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs";
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./src_modules/fetchData.mjs";
import { drawColumnChartHighcharts } from "./src_modules/chartColumn.mjs";
import {
formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";
showLoadingSpinner,
hideLoadingSpinner,
} from "./src_modules/loadingIndicator.mjs";
import { calculateVorlaufMinusRuecklaufTemperature } from "./src_modules/calculateTemperatureDiff.mjs";
import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs";
import {
extractObservationsWithinDatesInterval,
extractUniqueCalendarDatesFromTimestamp,
extractUniqueCalendarMonthsFromCalendarDates,
} from "./src_modules/aggregateHelpers.mjs";
import {
calculateMinimumObservationValuesWithinInterval,
calculateMaximumObservationValuesWithinInterval,
calculateSumOfObservationValuesWithinInterval,
calculateAverageOfObservationValuesWithinInterval,
} from "./src_modules/aggregate.mjs";
/**
* Test plotting of temp difference (dT) using heatmap
*/
const drawHeatmapHCUsingTempDifference = async function () {
try {
const [observationsTemperatureDiff225Arr, metadataTemperatureDiff225Arr] =
await calculateVorlaufMinusRuecklaufTemperature(
BASE_URL,
QUERY_PARAMS_COMBINED,
"225",
"60min"
);
// We want to have nested arrays, so as to mimick the nested responses we get from fetching observations + metadata
const observationsTemperatureDiff225NestedArr = [
observationsTemperatureDiff225Arr,
];
splitMultipleOptionsTextDelimitedBySlash,
getSelectedOptionsFromAllDropDownLists,
checkIfSelectedOptionsContainTemperatureDifference,
deleteTemperatureDifferenceOptions,
extractTemperatureDifferenceOptions,
extractBuildingPlusSamplingRate,
checkIfChartRequiresRawObservations,
getAbbreviationsForSelectedOptionsFromAllDropDownLists,
} from "./src_modules/dropDownListHelpers.mjs";
const metadataTemperatureDiff225NestedArr = [metadataTemperatureDiff225Arr];
// Format the observations
const formattedTempDiff225NestedArr =
observationsTemperatureDiff225NestedArr.map((obsArr) =>
formatSensorThingsApiResponseForHeatMap(obsArr)
);
// Format the metadata
const formattedTempDiff225MetadataNestedArr =
metadataTemperatureDiff225NestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedTempDiff225Properties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedTempDiff225MetadataNestedArr,
false
);
// First need to extract the formatted observations from the nested array
// Heatmap only needs one set of formatted observation values
drawHeatMapHighcharts(
...formattedTempDiff225NestedArr,
extractedFormattedTempDiff225Properties
);
} catch (err) {
console.error(err);
}
};
import {
drawHeatmapBasedOnSelectedOptions,
drawScatterPlotFromChartSelection,
drawLineChartBasedOnSelectedAggregationOptions,
drawColumnChartBasedOnSelectedAggregationOptions,
} from "./src_modules/dropDownListProcessing.mjs";
/**
* Test drawing of scatter plot chart
* Use the `vanillaDropDown` library to style the buildings & data points drop down list
*
* @returns {undefined}
*/
const drawScatterPlotHCTest2 = async function () {
try {
const sensorsOfInterestNestedArr = [
["weather_station_521", "outside_temp", "60min"],
["225", "vl", "60min"],
["125", "rl", "60min"],
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the combined arrays for observations and metadata
const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// Extract values for x-axis and y-axis
// x-axis values are first element of nested observations array
const [obsXAxisArr] = observationsNestedArr.slice(0, 1);
// y-axis values are rest of elements of nested observations array
const obsYAxisNestedArr = observationsNestedArr.slice(1);
// Create formatted array(s) for observations
const formattedObservationsArr = obsYAxisNestedArr.map((obsYAxisArr) =>
formatSensorThingsApiResponseForScatterPlot(obsXAxisArr, obsYAxisArr)
);
// Create formatted array(s) for metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj, false)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
false
);
drawScatterPlotHighcharts(
formattedObservationsArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
const styleBuildingsDataPointsDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`; supports the selection of multiple options
new vanillaSelectBox("#drop-down--bldg-data-point", {
"disableSelectAll": true,
"maxSelect": 5,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Test drawing of line chart with multiple series
* Use the `vanillaDropDown` library to style the aggregation type drop down list
*
* @returns {undefined}
*/
const testLineChartMultipleSeries = async function () {
try {
const sensorsOfInterestNestedArr = [
["225", "vl", "60min"],
["125", "rl", "60min"],
["weather_station_521", "outside_temp", "60min"],
];
const observationsPlusMetadataArr =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata arrays of arrays
const [observationsNestedArr, metadataNestedArr] =
observationsPlusMetadataArr;
// Format the observations
const formattedObservationsNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
formatDatastreamMetadataForChart(metadataArr)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
false
);
drawLineChartHighcharts(
formattedObservationsNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
const styleAggregationDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--aggregation-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Test drawing of column chart using aggregation / sum result - monthly
* Use the `vanillaDropDown` library to style the third sampling rate down list
*
* @returns {undefined}
*/
const drawColumnChartMonthlySumTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-05-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate sum of values of observations - monthly
const observationsSumMonthlyNestedArr =
calculateSumOfObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations
const formattedObservationsSumMonthlyNestedArr =
observationsSumMonthlyNestedArr.map((obsSumMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsSumMonthlyArr
)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"sum"
);
drawColumnChartHighcharts(
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
const styleSamplingRateDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--sampling-rate", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Test drawing of column chart using aggregation / sum result - daily
* Use the `vanillaDropDown` library to style the chart type drop down list
*
* @returns {undefined}
*/
const drawColumnChartDailySumTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-05-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Calculate sum of values of observations - daily
const observationsSumDailyNestedArr =
calculateSumOfObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - daily
const formattedObservationsSumDailyNestedArr =
observationsSumDailyNestedArr.map((obsSumDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsSumDailyArr
)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"sum"
);
drawColumnChartHighcharts(
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
const styleChartTypeDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--chart-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Test drawing of column chart using raw observations
* Callback function that wraps the logic of populating the linked drop down lists.
* Will run on `DOMContentLoaded` event
*
* @returns {undefined}
*/
const drawColumnChartNonAggregationTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// Format the observations
const formattedObservationsNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataArr) =>
formatDatastreamMetadataForChart(metadataArr)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
false
);
drawColumnChartHighcharts(
formattedObservationsNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
const afterDocumentLoads = function () {
styleBuildingsDataPointsDropDown();
styleAggregationDropDown();
styleSamplingRateDropDown();
styleChartTypeDropDown();
};
/**
* Test drawing of line chart using aggregation / average result - monthly
* Callback function that draws a chart using options from the drop-down list that
* have been selected by a user.
* Will be run when the user clicks a button
*
* @async
* @returns {undefined} undefined
*/
const drawLineChartMonthlyAverageTest = async function () {
const drawChartUsingSelectedOptions = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
const selectedOptionsAllDropDownLists =
getSelectedOptionsFromAllDropDownLists();
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Note: The aggregation type + duration and chart type are the second and
// fourth elements respectively, we have ignored the first and third elements
const [, selectedAggregationTypeDurationArr, , selectedChartTypeArr] =
selectedOptionsAllDropDownLists;
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-05-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate average of values of observations - monthly
const observationsAverageMonthlyNestedArr =
calculateAverageOfObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarMonthsNestedArr,
"monthly"
// Create an array of aggregation type and duration
const selectedAggregationTypeDurationSplitNestedArr =
splitMultipleOptionsTextDelimitedBySlash(
selectedAggregationTypeDurationArr
);
// Format the observations
const formattedObservationsAverageMonthlyNestedArr =
observationsAverageMonthlyNestedArr.map((obsAverageMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsAverageMonthlyArr
)
);
// Separate the aggregation type and the aggregation duration strings
const [selectedAggregationTypeDurationSplitArr] =
selectedAggregationTypeDurationSplitNestedArr;
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
const [selectedAggregationTypeArr, selectedAggregationDuration] =
selectedAggregationTypeDurationSplitArr;
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"average"
// Array of building(s) + data point(s) + sampling rate
const selectedBuildingsDataPointsSamplingRateAbbrev =
getAbbreviationsForSelectedOptionsFromAllDropDownLists(
selectedOptionsAllDropDownLists
);
drawLineChartHighcharts(
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
};
/**
* Test drawing of line chart using aggregation / average result - daily
*/
const drawLineChartDailyAverageTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
// Create copies of the arrays of building(s) + data point(s) + sampling rate
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy = [
...selectedBuildingsDataPointsSamplingRateAbbrev,
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-05-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Calculate average of values of observations - daily
const observationsAverageDailyNestedArr =
calculateAverageOfObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - daily
const formattedObservationsAverageDailyNestedArr =
observationsAverageDailyNestedArr.map((obsAverageDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsAverageDailyArr
)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"average"
);
drawLineChartHighcharts(
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
};
/**
* Test drawing of line chart using aggregation / minimum result - daily
*/
const drawLineChartDailyMinTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
const selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy = [
...selectedBuildingsDataPointsSamplingRateAbbrev,
];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-05-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
// Check if we have non-computed
const selectedBuildingsDataPointsSamplingRateAbbrevNonComputed =
checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Calculate average of values of observations - daily
const observationsMinimumDailyNestedArr =
calculateMinimumObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarDatesNestedArr,
"daily"
);
? deleteTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy
)
: selectedBuildingsDataPointsSamplingRateAbbrevNonComputedCopy;
// Check if we have computed / dT
const selectedBuildingsDataPointsSamplingRateAbbrevComputed =
checkIfSelectedOptionsContainTemperatureDifference(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy
)
? extractTemperatureDifferenceOptions(
selectedBuildingsDataPointsSamplingRateAbbrevComputedCopy
)
: [];
// Display the loading indicator
showLoadingSpinner();
// Fetch the observations + metadata / non-computed
const observationsPlusMetadataNonComputed =
selectedBuildingsDataPointsSamplingRateAbbrevNonComputed.length === 0
? [[], []]
: await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
selectedBuildingsDataPointsSamplingRateAbbrevNonComputed
);
// Fetch the observations + metadata / computed (dT)
const observationsPlusMetadataComputed =
selectedBuildingsDataPointsSamplingRateAbbrevComputed.length === 0
? [[], []]
: await calculateVorlaufMinusRuecklaufTemperature(
BASE_URL,
QUERY_PARAMS_COMBINED,
extractBuildingPlusSamplingRate(
selectedBuildingsDataPointsSamplingRateAbbrevComputed
)
);
// Extract the combined arrays for observations and metadata / non-computed
const [observationsNestedNonComputedArr, metadataNestedNonComputedArr] =
observationsPlusMetadataNonComputed;
// Extract the combined arrays for observations and metadata / computed (dT)
const [observationsNestedComputedArr, metadataNestedComputedArr] =
observationsPlusMetadataComputed;
// Create a combined array of observations and metadata
const observationsPlusMetadataCombined = [
[...observationsNestedNonComputedArr, ...observationsNestedComputedArr],
[...metadataNestedNonComputedArr, ...metadataNestedComputedArr],
];
// Format the observations - daily
const formattedObservationsMinimumDailyNestedArr =
observationsMinimumDailyNestedArr.map((obsMinDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsMinDailyArr
)
);
const [observationsComboNestedArr, metadataComboNestedArr] =
observationsPlusMetadataCombined;
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
// Create formatted array(s) for metadata - used by ALL chart types
const formattedMetadataNestedArr = metadataComboNestedArr.map(
(metadataObj) => formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
// Extract the formatted metadata properties - used by ALL chart types
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"minimum"
false
);
drawLineChartHighcharts(
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} catch (err) {
console.error(err);
}
};
// The formatted abbreviations array is nested
const [selectedBuildingsDataPointsSamplingRateAbbrevArr] =
selectedBuildingsDataPointsSamplingRateAbbrev;
/**
* Test drawing of line chart using aggregation / maximum result - daily
*/
const drawLineChartMonthlyMaxTest = async function () {
try {
const sensorsOfInterestNestedArr = [
["125", "vl", "60min"],
["225", "vl", "60min"],
];
// Extract the formatted sampling rate string - used by ALL chart types
const [, , selectedSamplingRateAbbrev] =
selectedBuildingsDataPointsSamplingRateAbbrevArr;
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
sensorsOfInterestNestedArr
);
// User-specified start date and end date for aggregation - used by MULTIPLE chart types
const aggregationStartDate = "2020-01-01";
const aggregationEndDate = "2020-12-31";
// Extract the observations and metadata for each sensor
// Array elements in same order as input array
const [obsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// User-specified start date and end date
const startDate = "2020-02-01";
const endDate = "2020-12-31";
// Extract observations within the user-specified start and end date
const observationsNestedArr = obsNestedArr.map((obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
startDate,
endDate
)
// Extract observations within the user-specified start and end date - used by MULTIPLE chart types
const observationsAggregationNestedArr = observationsComboNestedArr.map(
(obsArr) =>
extractObservationsWithinDatesInterval(
obsArr,
"60min",
aggregationStartDate,
aggregationEndDate
)
);
// Unique calendar dates
const uniqueCalendarDatesNestedArr = observationsNestedArr.map(
// Unique calendar dates - used by MULTIPLE chart types
const uniqueCalendarDatesNestedArr = observationsAggregationNestedArr.map(
(observationsArr) =>
extractUniqueCalendarDatesFromTimestamp(observationsArr)
);
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate maximum values of observations - monthly
const observationsMaxMonthlyNestedArr =
calculateMaximumObservationValuesWithinInterval(
observationsNestedArr,
"60min",
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations - monthly
const formattedObservationsMaxMonthlyNestedArr =
observationsMaxMonthlyNestedArr.map((obsMaxMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsMaxMonthlyArr
)
);
// Format the metadata
const formattedMetadataNestedArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"maximum"
);
drawLineChartHighcharts(
formattedObservationsMaxMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
selectedChartTypeArr.forEach((selectedChartType) => {
if (selectedChartType === "Heatmap") {
// We are interested in raw observations
if (
checkIfChartRequiresRawObservations(
selectedAggregationTypeArr,
selectedAggregationDuration
)
) {
drawHeatmapBasedOnSelectedOptions(
selectedBuildingsDataPointsSamplingRateAbbrev,
observationsComboNestedArr,
extractedFormattedDatastreamProperties
);
} else {
throw new Error(
"This type of chart (Heatmap) does not support aggregated results"
);
}
}
if (selectedChartType === "Scatter Plot") {
// We are interested in raw observations
if (
checkIfChartRequiresRawObservations(
selectedAggregationTypeArr,
selectedAggregationDuration
)
) {
drawScatterPlotFromChartSelection(
selectedBuildingsDataPointsSamplingRateAbbrev,
observationsComboNestedArr,
extractedFormattedDatastreamProperties
);
} else {
throw new Error(
"This type of chart (Scatter Plot) does not support aggregated results"
);
}
}
if (selectedChartType === "Line") {
// We are interested in raw observations or aggregated observations
// Raw observations
if (selectedAggregationTypeArr === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsLineChartNestedArr =
observationsComboNestedArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
drawLineChartHighcharts(
formattedRawObservationsLineChartNestedArr,
extractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawLineChartBasedOnSelectedAggregationOptions(
selectedAggregationTypeArr,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
}
if (selectedChartType === "Column") {
// We are interested in raw observations or aggregated observations
// Raw observations
if (selectedAggregationTypeArr === "None (raw data)") {
// Create formatted array(s) for observations
const formattedRawObservationsColumnChartNestedArr =
observationsComboNestedArr.map((observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
drawColumnChartHighcharts(
formattedRawObservationsColumnChartNestedArr,
extractedFormattedDatastreamProperties
);
}
// Aggregated observations
else {
drawColumnChartBasedOnSelectedAggregationOptions(
selectedAggregationTypeArr,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
);
}
}
});
} catch (err) {
console.error(err);
} finally {
// Hide the loading indicator
hideLoadingSpinner();
}
};
// drawScatterPlotHCTest2();
// drawHeatmapHCUsingTempDifference();
// testLineChartMultipleSeries();
// drawColumnChartMonthlySumTest();
// drawColumnChartDailySumTest();
// drawColumnChartNonAggregationTest();
// drawLineChartMonthlyAverageTest();
// drawLineChartDailyAverageTest();
// drawLineChartDailyMinTest();
// drawLineChartMonthlyMaxTest();
document.addEventListener("DOMContentLoaded", afterDocumentLoads);
document
.querySelector("#btn-draw-chart")
.addEventListener("click", drawChartUsingSelectedOptions);
......@@ -7,127 +7,139 @@ import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./fe
import { extractPhenomenonNameFromDatastreamName } from "./fetchedDataProcessing.mjs";
/**
* Calculate the temperature difference, dT, between Vorlauf temperature [VL] and Rücklauf temperature [RL] (i.e., dT = VL - RL)
* Calculate the temperature difference, dT, between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL). In addition, create synthetic metadata
* for the temperature difference
* @async
* @param {String} baseUrl Base URL of the STA server
* @param {Object} urlParams The URL parameters to be sent together with the GET request
* @param {String} buildingId The building ID as a string
* @param {String} samplingRate The sampling rate as a string
* @returns {Promise} A promise that contains an array (that is made up of a temperature difference array and a metadata object) when fulfilled
* @param {Array} buildingSamplingRateNestedArr A N*1 array (where N >= 1) containing a nested array of buildings & sampling rates as strings, i.e. [["101", "15min"]] or [["101", "15min"], ["102", "60min"]] or [["101", "15min"], ["102", "60min"], ["225", "60min"]], etc
* @returns {Promise} A promise that contains a 1*2 array (the first element is an array that contans N Observations arrays; and the second element is an array of N Datastream metadata objects) when fulfilled
*/
export const calculateVorlaufMinusRuecklaufTemperature = async function (
baseUrl,
urlParams,
buildingId,
samplingRate
buildingSamplingRateNestedArr
) {
try {
const bldgSensorSamplingRateNestedArr = [
[buildingId, "vl", samplingRate],
[buildingId, "rl", samplingRate],
];
const BUILDING_ID = buildingId;
const SAMPLING_RATE = samplingRate;
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
baseUrl,
urlParams,
bldgSensorSamplingRateNestedArr
// Arrays to store our results
const combinedObservationsArr = [];
const combinedMetadataArr = [];
const buildingDataPointSamplingRateNestedTwiceArr =
buildingSamplingRateNestedArr.map((bldgSmplngRate) => {
// The building ID is the first element, sampling rate is second element
return [
[bldgSmplngRate[0], "vl", bldgSmplngRate[1]],
[bldgSmplngRate[0], "rl", bldgSmplngRate[1]],
];
});
// 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,
urlParams,
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]
);
// 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];
// 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],
];
}
);
// Case 2: Neither of the observation values is `null`,
// calculate temperature difference
return [
timestamp,
vorlaufTemperatureValues[i] - ruecklaufTemperatureValues[i],
];
}
);
// 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",
""
// 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 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;
const name = nameTempDifference;
const unitOfMeasurement = unitOfMeasurementVorlauf;
return [
vorlaufMinusRuecklaufTemperatureObs,
{
description,
name,
unitOfMeasurement,
},
];
// 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;
const name = nameTempDifference;
const unitOfMeasurement = unitOfMeasurementVorlauf;
// Add the observations and metadata to our arrays
combinedObservationsArr.push(vorlaufMinusRuecklaufTemperatureObs);
combinedMetadataArr.push({ description, name, unitOfMeasurement });
}
return [combinedObservationsArr, combinedMetadataArr];
} catch (err) {
console.error(err);
}
......
"use strict";
import {
BASE_URL,
QUERY_PARAMS_COMBINED,
} from "./src_modules/baseUrlPlusQueryParams.mjs";
import { getMetadataPlusObservationsFromSingleOrMultipleDatastreams } from "./src_modules/fetchData.mjs";
import {
formatDatastreamMetadataForChart,
extractPropertiesFromFormattedDatastreamMetadata,
} from "./src_modules/fetchedDataProcessing.mjs";
import {
formatSensorThingsApiResponseForLineOrColumnChart,
drawLineChartHighcharts,
} from "./src_modules/chartLine.mjs";
import {
formatSensorThingsApiResponseForHeatMap,
drawHeatMapHighcharts,
} from "./src_modules/chartHeatmap.mjs";
import {
showLoadingSpinner,
hideLoadingSpinner,
} from "./src_modules/loadingIndicator.mjs";
import { vanillaSelectBox } from "./thirdparty/vanillaSelectBox.mjs";
/**
* Use the `vanillaDropDown` library to style the first level drop down list
*
* @returns {undefined}
*/
const styleLevelOneDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`; supports the selection of multiple options
new vanillaSelectBox("#drop-down--bldg-data-point", {
"disableSelectAll": true,
"maxSelect": 5,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the second level drop down list
*
* @returns {undefined}
*/
const styleLevelTwoDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--aggregation-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the third level drop down list
*
* @returns {undefined}
*/
const styleLevelThreeDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--sampling-rate", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Use the `vanillaDropDown` library to style the fourth level drop down list
*
* @returns {undefined}
*/
const styleLevelFourDropDown = function () {
// Create our dropdown list using `vanillaSelectBox`
new vanillaSelectBox("#drop-down--chart-type", {
"disableSelectAll": true,
"maxSelect": 1,
"placeHolder": "--Select--",
"search": false,
});
};
/**
* Callback function that wraps the logic of populating the linked drop down lists.
* Will run on `DOMContentLoaded` event
*
* @returns {undefined}
*/
const afterDocumentLoads = function () {
styleLevelOneDropDown();
styleLevelTwoDropDown();
styleLevelThreeDropDown();
styleLevelFourDropDown();
};
/**
* Get the selected option(s) from a dropdown list
*
......@@ -126,7 +22,6 @@ const getSelectedOptionsFromDropDownList = function (selectorStr) {
/**
* Process the selected option(s) from a buildings & data points dropdown list.
* This is currently the first dropdown list in the UI.
*
* @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements
* @returns {Array} An array of string(s) representing the processed value(s) of the selected buildings & data points option(s)
......@@ -138,10 +33,9 @@ const processSelectionsFromBuildingDataPointOptions = function (
const selectedOptionsBuildingDataPointArr = [];
selectedOptionsArr.forEach((optionStr) => {
// Case 1: <option> element's value CONTAINS a "/" character
// We wish to create a string like this `Bau 101/VL`
if (optionStr.includes("/")) {
// Case 1: <option> element's value CONTAINS a "/" character
// We wish to create a string like this `Bau 101/VL`
// Split the <option> element's value into two substrings
const optionsStrPartOne = optionStr.slice(0, 3);
const optionsStrPartTwo = optionStr.slice(3);
......@@ -153,9 +47,10 @@ const processSelectionsFromBuildingDataPointOptions = function (
const optionsStrNew = optionsStrPartOneNew + optionsStrPartTwo;
selectedOptionsBuildingDataPointArr.push(optionsStrNew);
} else {
// Case 2: <option> element's value DOES NOT CONTAIN a "/" character
// We wish to create a string like this `Other/Außentemp`
}
// Case 2: <option> element's value DOES NOT CONTAIN a "/" character
// We wish to create a string like this `Other/Außentemp`
else {
selectedOptionsBuildingDataPointArr.push(`Other/${optionStr}`);
}
});
......@@ -166,11 +61,23 @@ const processSelectionsFromBuildingDataPointOptions = function (
/**
* Split an option element's value (a string) using a forward slash character ("/") as the delimiter
*
* @param {String} selectedOptionsStr A string representing the value of the selected `<option>` element
* @returns {String} Resulting strings after splitting
*/
const splitOptionsTextDelimitedBySlash = function (selectedOptionsStr) {
return selectedOptionsStr.split("/");
};
/**
* Split an array of option element's values (strings) which have a forward slash character ("/") as the delimiter
*
* @param {Array} selectedOptionsArr An array of string(s) representing the value(s) of the selected `<option>` elements
* @returns {Array} An array made up of resulting strings after splitting
*/
const splitOptionsTextDelimitedBySlash = function (selectedOptionsArr) {
return selectedOptionsArr.map((selectedOption) => selectedOption.split("/"));
const splitMultipleOptionsTextDelimitedBySlash = function (selectedOptionsArr) {
return selectedOptionsArr.map((selectedOption) =>
splitOptionsTextDelimitedBySlash(selectedOption)
);
};
/**
......@@ -185,7 +92,9 @@ const getSelectedOptionsFromAllDropDownLists = function () {
// Separate the building ID from the data point
const selectedBuildingDataPointOptionsSplitArr =
splitOptionsTextDelimitedBySlash(selectedBuildingDataPointOptionsArr);
splitMultipleOptionsTextDelimitedBySlash(
selectedBuildingDataPointOptionsArr
);
const selectedAggregationOptionsArr = getSelectedOptionsFromDropDownList(
"#drop-down--aggregation-type"
......@@ -200,7 +109,6 @@ const getSelectedOptionsFromAllDropDownLists = function () {
);
// Ensure that all the options have at least one selection
if (
selectedBuildingDataPointOptionsSplitArr.length === 0 ||
selectedAggregationOptionsArr.length === 0 ||
......@@ -217,6 +125,177 @@ const getSelectedOptionsFromAllDropDownLists = function () {
];
};
/**
* Check whether the abbreviated buildings + data points + sampling rate strings
* contain the temperature difference [dT] between Vorlauf temperature [VL] and
* Rücklauf temperature [RL] (i.e., dT = VL - RL). Unlike all the other data points,
* this data point is computed in a separate step
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of strings representing the abbreviated building + data point + sampling rate values
* @returns {Boolean} true if the selected options contain the string `dT`, false otherwise
*/
const checkIfSelectedOptionsContainTemperatureDifference = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Create a flattened copy of our input array,
// then check if it contains the string `dT`
return buildingDataPointSamplingRateAbbrevArr.flat().includes("dT");
};
/**
* Get the index(es) of the the abbreviated buildings + data points + sampling rate string(s)
* that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains an integer(s) whose value(s) are the index(es) of the abbreviated building + data point + sampling rate string(s) containing the temperature difference (dT)
*/
const getIndexesOfTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// An array to store the final result
const foundIndexesArr = [];
// Use the index, i, provided by `forEach` array method
buildingDataPointSamplingRateAbbrevArr.forEach(
(bldgDataPntSamplingRateAbbrvArr, i) => {
if (bldgDataPntSamplingRateAbbrvArr.includes("dT")) {
foundIndexesArr.push(i);
}
}
);
return foundIndexesArr;
};
/**
* Delete the abbreviated building + data point + sampling rate string(s) that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
*/
const deleteTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Calculate the index(es) that we wish to delete
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
// Delete the index(es) of `dT`, modifies the array in place
// Note: The resulting array is sparse
foundIndexesArr.forEach(
(foundIndex) => delete buildingDataPointSamplingRateAbbrevArr[foundIndex]
);
// Array to store our final result
const buildingDataPointFinalArr = [];
// Remove the empty sub array(s) that makes entire array sparse
// Note: `empty` does not mean `undefined` or `null`
buildingDataPointSamplingRateAbbrevArr.forEach(
(bldgDataPntSmplingRateAbbrvArr) => {
if (typeof bldgDataPntSmplingRateAbbrvArr === "object") {
buildingDataPointFinalArr.push(bldgDataPntSmplingRateAbbrvArr);
}
}
);
return buildingDataPointFinalArr;
};
/**
* Extract the abbreviated building + data point + sampling rate string(s) that contains the temperature difference (dT)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
*/
const extractTemperatureDifferenceOptions = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Array to store final result
const temperatureDifferenceOptionsAbbrevArr = [];
// Calculate the index(es) that we wish to extract
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
foundIndexesArr.forEach((foundIndex) => {
// Extracted array for a single found index
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);
});
return temperatureDifferenceOptionsAbbrevArr;
};
/**
* Extract the abbreviated building + sampling rate string(s) for use in calculating the temperature difference (dT = VL - RL)
*
* @param {Array} buildingDataPointSamplingRateAbbrevArr An array that contains nested array(s) made up of abbreviated building + data point + sampling rate string(s)
* @returns {Array} An array that contains nested array(s) made up of abbreviated building + sampling rate string(s)
*/
const extractBuildingPlusSamplingRate = function (
buildingDataPointSamplingRateAbbrevArr
) {
// Array to store final result
const temperatureDifferenceOptionsAbbrevArr = [];
// Calculate the index(es) that we wish to extract
const foundIndexesArr = getIndexesOfTemperatureDifferenceOptions(
buildingDataPointSamplingRateAbbrevArr
);
foundIndexesArr.forEach((foundIndex) => {
// Extracted array for a single found index
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(bldgSamplingRateAbbrvArr);
});
return temperatureDifferenceOptionsAbbrevArr;
};
/**
* Determine if a chart requires raw observations instead of aggregated observations
*
* @param {String} selectedAggregationType The selected aggregation type
* @param {String} selectedAggregationDuration The selected aggregation duration
* @returns {Boolean} true if the chart requires raw observations, false if not
*/
const checkIfChartRequiresRawObservations = function (
selectedAggregationType,
selectedAggregationDuration
) {
if (
selectedAggregationType === "None (raw data)" &&
selectedAggregationDuration === undefined
) {
return true;
} else {
return false;
}
};
/**
* Get the abbreviated form of building IDs, phenomenon names and sensor sampling rates
* @param {String} buildingFullForm A string representation of the full form of a building ID
......@@ -239,17 +318,18 @@ const getBuildingSensorSamplingRateAbbreviation = function (
"Bau 225": "225",
"Other": "weather_station_521",
},
phenomenon: {
VL: "vl",
RL: "rl",
dT: "dT",
Durchfluss: "flow",
Leistung: "power",
Energie: "energy",
Energie_VERBR: "energy_verb",
Außentemp: "outside_temp",
},
samplingRate: {
"15 min": "15min",
"60 min": "60min",
......@@ -330,88 +410,13 @@ const getAbbreviationsForSelectedOptionsFromAllDropDownLists = function (
);
};
/**
* Callback function for chart selection using drop down list
* @returns {undefined}
*/
const selectChartTypeFromDropDown = async function () {
try {
const selectedOptions = getSelectedOptionsFromDropDownLists();
if (selectedOptions === undefined) return;
const selectedOptionsAbbreviationsArr =
getBuildingSensorSamplingRateAbbreviation(...selectedOptions);
const selectedChartType = document.querySelector(
"#drop-down--chart-type"
).value;
if (selectedChartType === "--Select--") return;
// Display the loading indicator
showLoadingSpinner();
// The `getMetadataPlusObservationsFromSingleOrMultipleDatastreams` function expects a nested array structure
const abbreviationsNestedArr = [selectedOptionsAbbreviationsArr];
const observationsPlusMetadata =
await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
BASE_URL,
QUERY_PARAMS_COMBINED,
abbreviationsNestedArr
);
// Extract the combined arrays for observations and metadata
const [observationsNestedArr, metadataNestedArr] = observationsPlusMetadata;
// Create formatted array(s) for observations - line chart
const formattedObsLineChartNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForLineOrColumnChart(observationsArr)
);
// Create formatted array(s) for observations - heatmap
const formattedObsHeatMapNestedArr = observationsNestedArr.map(
(observationsArr) =>
formatSensorThingsApiResponseForHeatMap(observationsArr)
);
// Create formatted array(s) for metadata - same for both chart types
const formattedMetadataArr = metadataNestedArr.map((metadataObj) =>
formatDatastreamMetadataForChart(metadataObj)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataArr,
false
);
if (selectedChartType === "Line") {
drawLineChartHighcharts(
formattedObsLineChartNestedArr,
extractedFormattedDatastreamProperties
);
} else if (selectedChartType === "Heatmap") {
// First need to extract the formatted observations from the nested array
// Heatmap only needs one set of formatted observation values
drawHeatMapHighcharts(
...formattedObsHeatMapNestedArr,
extractedFormattedDatastreamProperties
);
}
} catch (err) {
console.error(err);
} finally {
// Hide the loading indicator
hideLoadingSpinner();
}
export {
splitMultipleOptionsTextDelimitedBySlash,
getSelectedOptionsFromAllDropDownLists,
checkIfSelectedOptionsContainTemperatureDifference,
deleteTemperatureDifferenceOptions,
extractTemperatureDifferenceOptions,
extractBuildingPlusSamplingRate,
checkIfChartRequiresRawObservations,
getAbbreviationsForSelectedOptionsFromAllDropDownLists,
};
document.addEventListener("DOMContentLoaded", afterDocumentLoads);
document
.querySelector("#drop-down--chart-type")
.addEventListener("change", selectChartTypeFromDropDown);
import { drawLineChartHighcharts } from "./chartLine.mjs";
import {
formatSensorThingsApiResponseForHeatMap,
drawHeatMapHighcharts,
} from "./chartHeatmap.mjs";
import {
formatSensorThingsApiResponseForScatterPlot,
drawScatterPlotHighcharts,
} from "./chartScatterPlot.mjs";
import {
formatAggregationResultForColumnChart,
drawColumnChartHighcharts,
} from "./chartColumn.mjs";
import { extractUniqueCalendarMonthsFromCalendarDates } from "./aggregateHelpers.mjs";
import {
calculateMinimumObservationValuesWithinInterval,
calculateMaximumObservationValuesWithinInterval,
calculateSumOfObservationValuesWithinInterval,
calculateAverageOfObservationValuesWithinInterval,
} from "./aggregate.mjs";
import { extractPropertiesFromFormattedDatastreamMetadata } from "./fetchedDataProcessing.mjs";
/**
* Draw a heatmap based on the selected options from a drop-down list
*
* @param {Array} selectedBuildingsDataPointsSamplingRateAbbrevArr An array which contains one or more nested arrays of abbreviations of building(s), data point(s) and sampling rate(s)
* @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations
* @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties
* @returns {undefined} undefined
*/
const drawHeatmapBasedOnSelectedOptions = function (
selectedBuildingsDataPointsSamplingRateAbbrevArr,
observationsComboNestedArr,
extractedFormattedDatastreamProperties
) {
if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length === 1) {
// Create formatted array(s) for observations
const formattedObservationsHeatMapNestedArr =
observationsComboNestedArr.map((observationsArr) =>
formatSensorThingsApiResponseForHeatMap(observationsArr)
);
// Note: The resulting array is nested and is not suitable for heatmap,
// extract the nested array
const [formattedObservationsHeatMapArr] =
formattedObservationsHeatMapNestedArr;
drawHeatMapHighcharts(
formattedObservationsHeatMapArr,
extractedFormattedDatastreamProperties
);
} else if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length < 1) {
throw new Error("Please select at least one data point");
} else {
throw new Error(
"This type of chart (Heatmap) can only display one data point at a time"
);
}
};
/**
* Draw a scatter plot based on the selected options from a drop-down list
*
* @param {Array} selectedBuildingsDataPointsSamplingRateAbbrevArr An array which contains one or more nested arrays of abbreviations of building(s), data point(s) and sampling rate(s)
* @param {Array} observationsComboNestedArr An array that contains non-computed (raw) observations and computed (temperature difference, dT) observations
* @param {Object} extractedFormattedDatastreamProperties An object that contains array(s) of formatted Datastream properties
* @returns {undefined} undefined
*/
const drawScatterPlotFromChartSelection = function (
selectedBuildingsDataPointsSamplingRateAbbrevArr,
observationsComboNestedArr,
extractedFormattedDatastreamProperties
) {
// Check the length of buildings + data points + sampling rate array
if (selectedBuildingsDataPointsSamplingRateAbbrevArr.length >= 2) {
// Extract values for x-axis and y-axis
// x-axis values are first element of nested observations array
const [obsXAxisArr] = observationsComboNestedArr.slice(0, 1);
// y-axis values are rest of elements of nested observations array
const obsYAxisNestedArr = observationsComboNestedArr.slice(1);
// Create formatted array(s) for observations
const formattedObservationsScatterPlotArr = obsYAxisNestedArr.map(
(obsYAxisArr) =>
formatSensorThingsApiResponseForScatterPlot(obsXAxisArr, obsYAxisArr)
);
drawScatterPlotHighcharts(
formattedObservationsScatterPlotArr,
extractedFormattedDatastreamProperties
);
} else {
throw new Error("A scatter plot chart requires at least two data points");
}
};
/**
* Calculate the daily sum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (daily sum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatDailySumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Calculate sum of values of observations - daily
const observationsSumDailyNestedArr =
calculateSumOfObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - sum / daily
const formattedObservationsSumDailyNestedArr =
observationsSumDailyNestedArr.map((obsSumDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsSumDailyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"sum"
);
return [
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the monthly sum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (monthly sum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatMonthlySumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate sum of values of observations - monthly
const observationsSumMonthlyNestedArr =
calculateSumOfObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations - sum / monthly
const formattedObservationsSumMonthlyNestedArr =
observationsSumMonthlyNestedArr.map((obsSumMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsSumMonthlyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"sum"
);
return [
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the daily maximum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (daily maximum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatDailyMaximumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Calculate minimum of values of observations - daily
const observationsMaximumDailyNestedArr =
calculateMaximumObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - min / daily
const formattedObservationsMaximumDailyNestedArr =
observationsMaximumDailyNestedArr.map((obsMinDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsMinDailyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"maximum"
);
return [
formattedObservationsMaximumDailyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the monthly maximum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (monthly maximum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatMonthlyMaximumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate minimum of values of observations - monthly
const observationsMaximumMonthlyNestedArr =
calculateMaximumObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations - max / monthly
const formattedObservationsMaximumMonthlyNestedArr =
observationsMaximumMonthlyNestedArr.map((obsMaxMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsMaxMonthlyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"maximum"
);
return [
formattedObservationsMaximumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the daily minimum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (daily minimum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatDailyMinimumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Calculate minimum of values of observations - daily
const observationsMinimumDailyNestedArr =
calculateMinimumObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - min / daily
const formattedObservationsMinimumDailyNestedArr =
observationsMinimumDailyNestedArr.map((obsMinDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsMinDailyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"minimum"
);
return [
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the monthly minimum of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (monthly minimum) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatMonthlyMinimumObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate minimum of values of observations - monthly
const observationsMinimumMonthlyNestedArr =
calculateMinimumObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations - min / monthly
const formattedObservationsMinimumMonthlyNestedArr =
observationsMinimumMonthlyNestedArr.map((obsMinMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsMinMonthlyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"minimum"
);
return [
formattedObservationsMinimumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the daily average of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (daily average) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatDailyAverageObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Calculate average of values of observations - daily
const observationsAverageDailyNestedArr =
calculateAverageOfObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
"daily"
);
// Format the observations - average / daily
const formattedObservationsAverageDailyNestedArr =
observationsAverageDailyNestedArr.map((obsAverageDailyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarDatesNestedArr[i],
obsAverageDailyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"daily",
"average"
);
return [
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Calculate the monthly average of observations and format these aggregated observations
*
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {Array} An array whose first element is the formatted aggregated (monthly average) observations. The second element is an object made up of extracted & formatted datastream properties
*/
const calculateAndFormatMonthlyAverageObservations = function (
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
) {
// Unique calendar months
const uniqueCalendarMonthsNestedArr = uniqueCalendarDatesNestedArr.map(
(uniqueCalendarDatesArr) =>
extractUniqueCalendarMonthsFromCalendarDates(uniqueCalendarDatesArr)
);
// Calculate average of values of observations - monthly
const observationsAverageMonthlyNestedArr =
calculateAverageOfObservationValuesWithinInterval(
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarMonthsNestedArr,
"monthly"
);
// Format the observations - average / monthly
const formattedObservationsAverageMonthlyNestedArr =
observationsAverageMonthlyNestedArr.map((obsAverageMonthlyArr, i) =>
formatAggregationResultForColumnChart(
uniqueCalendarMonthsNestedArr[i],
obsAverageMonthlyArr
)
);
// Extract the formatted metadata properties
const extractedFormattedDatastreamProperties =
extractPropertiesFromFormattedDatastreamMetadata(
formattedMetadataNestedArr,
true,
"monthly",
"average"
);
return [
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties,
];
};
/**
* Draw a line chart based on the selected aggregation options from a drop-down list
*
* @param {String} selectedAggregationType A string representing the selected aggregation type. The currently supported strings include `Sum`, `Maximum`, `Minimum` and `Average`
* @param {String} selectedAggregationDuration A string representing the selected aggregation duration. The currently supported strings include `Daily` and `Monthly`
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {undefined} undefined
*/
const drawLineChartBasedOnSelectedAggregationOptions = function (
selectedAggregationType,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
) {
if (
selectedAggregationType === "Sum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / sum
const [
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailySumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Sum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / sum
const [
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlySumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Maximum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / maximum
const [
formattedObservationsMaximumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyMaximumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsMaximumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Maximum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / maximum
const [
formattedObservationsMaximumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyMaximumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsMaximumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Minimum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / minimum
const [
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyMinimumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Minimum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / minimum
const [
formattedObservationsMinimumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyMinimumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsMinimumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Average" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / average
const [
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyAverageObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationType === "Average" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / average
const [
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyAverageObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawLineChartHighcharts(
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
}
};
/**
* Draw a column chart based on the selected aggregation options from a drop-down list
*
* @param {String} selectedAggregationType A string representing the selected aggregation type. The currently supported strings include `Sum`, `Maximum`, `Minimum` and `Average`
* @param {String} selectedAggregationDuration A string representing the selected aggregation duration. The currently supported strings include `Daily` and `Monthly`
* @param {Array} observationsAggregationNestedArr An array made up of sub-array(s) of aggregated observations
* @param {String} selectedSamplingRateAbbrev A string representing the abbreviated form of the selected sampling rate option
* @param {Array} uniqueCalendarDatesNestedArr An array made up of sub-array(s) of unique calendar date(s) string(s)
* @param {Array} formattedMetadataNestedArr An array of sub-arrays of formatted metadata properties
* @returns {undefined} undefined
*/
const drawColumnChartBasedOnSelectedAggregationOptions = function (
selectedAggregationTypeArr,
selectedAggregationDuration,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
uniqueCalendarDatesNestedArr,
formattedMetadataNestedArr
) {
if (
selectedAggregationTypeArr === "Sum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / sum
const [
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailySumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsSumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Sum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / sum
const [
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlySumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsSumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Maximum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / maximum
const [
formattedObservationsMaximumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyMaximumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsMaximumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Maximum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / maximum
const [
formattedObservationsMaximumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyMaximumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsMaximumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Minimum" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / minimum
const [
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyMinimumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsMinimumDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Minimum" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / minimum
const [
formattedObservationsMinimumMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyMinimumObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsMinimumMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Average" &&
selectedAggregationDuration === "Daily"
) {
// Formatted observations and metadata for chart - daily / average
const [
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatDailyAverageObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsAverageDailyNestedArr,
extractedFormattedDatastreamProperties
);
} else if (
selectedAggregationTypeArr === "Average" &&
selectedAggregationDuration === "Monthly"
) {
// Formatted observations and metadata for chart - monthly / average
const [
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties,
] = calculateAndFormatMonthlyAverageObservations(
uniqueCalendarDatesNestedArr,
observationsAggregationNestedArr,
selectedSamplingRateAbbrev,
formattedMetadataNestedArr
);
drawColumnChartHighcharts(
formattedObservationsAverageMonthlyNestedArr,
extractedFormattedDatastreamProperties
);
}
};
export {
drawHeatmapBasedOnSelectedOptions,
drawScatterPlotFromChartSelection,
drawLineChartBasedOnSelectedAggregationOptions,
drawColumnChartBasedOnSelectedAggregationOptions,
};
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