Commit d5b98048 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Merge branch 'wip_scatter-plot-2' into 'master'

Update scatter plot chart

Improve logic for drawing scatter plot chart

See merge request !2
parents f6f1d4ad 08df8dd6
...@@ -78,6 +78,10 @@ const getDatastreamIdFromBuildingNumber = function ( ...@@ -78,6 +78,10 @@ const getDatastreamIdFromBuildingNumber = function (
energy: { "15min": "122", "60min": "128" }, energy: { "15min": "122", "60min": "128" },
energy_verb: { "15min": "134", "60min": "140" }, energy_verb: { "15min": "134", "60min": "140" },
}, },
weather_station_521: {
outside_temp: { "15min": "141", "60min": "142" },
},
}; };
if ( if (
...@@ -163,7 +167,7 @@ const axiosGetRequest = function (urlObservations, urlParamObj) { ...@@ -163,7 +167,7 @@ const axiosGetRequest = function (urlObservations, urlParamObj) {
* @param {String} urlDatastream A URL that fetches a Datastream from an STA instance * @param {String} urlDatastream A URL that fetches a Datastream from an STA instance
* @returns {Promise} A promise that contains a metadata object for a Datastream when fulfilled * @returns {Promise} A promise that contains a metadata object for a Datastream when fulfilled
*/ */
const getDatastreamMetadata = async function (urlDatastream) { const getMetadataFromSingleDatastream = async function (urlDatastream) {
try { try {
// Extract properties of interest // Extract properties of interest
const { const {
...@@ -176,6 +180,32 @@ const getDatastreamMetadata = async function (urlDatastream) { ...@@ -176,6 +180,32 @@ const getDatastreamMetadata = async function (urlDatastream) {
} }
}; };
/**
* Retrieve metadata from multiple datastreams
* @async
* @param {Array} datastreamsUrlArr An array that contains N Datastream URL strings
* @returns {Promise} A promise that contains an array of N Datastream metadata objects when fulfilled
*/
const getMetadataFromMultipleDatastreams = async function (datastreamsUrlArr) {
try {
// Array to store our final result
const datastreamMetadataArr = [];
// Use for/of loop - we need to maintain the order of execution of the async operations
for (const datastreamUrl of datastreamsUrlArr) {
// Metadata from a single Datastream
const datastreamMetadata = await getMetadataFromSingleDatastream(
datastreamUrl
);
datastreamMetadataArr.push(datastreamMetadata);
}
return datastreamMetadataArr;
} catch (err) {
console.error(err);
}
};
/** /**
* Format the response containing a Datastream's metadata from Sensorthings API * Format the response containing a Datastream's metadata from Sensorthings API
* @param {Object} datastreamMetadata An object containing a Datastream's metadata * @param {Object} datastreamMetadata An object containing a Datastream's metadata
...@@ -371,9 +401,9 @@ const drawHeatMapHC = function ( ...@@ -371,9 +401,9 @@ const drawHeatMapHC = function (
/** /**
* Convert the observations' phenomenonTime from an ISO 8601 string to Unix epoch * Convert the observations' phenomenonTime from an ISO 8601 string to Unix epoch
* @param {Array} obsArray Response from SensorThings API as array * @param {Array} obsArray Response from SensorThings API as array
* @returns {Array} Array of formatted observations suitable for use in a line chart * @returns {Array} Array of formatted observations suitable for use in a line chart or scatter plot
*/ */
const formatSTAResponseForLineChart = function (obsArray) { const formatSTAResponseForLineChartOrScatterPlot = function (obsArray) {
if (!obsArray) return; if (!obsArray) return;
const dataSTAFormatted = obsArray.map((result) => { const dataSTAFormatted = obsArray.map((result) => {
...@@ -434,6 +464,273 @@ const drawLineChartHC = function ( ...@@ -434,6 +464,273 @@ const drawLineChartHC = function (
}); });
}; };
/**
* Determines the timestamps that are missing from a smaller set of observations. Based on the comparison of two observation arrays, where one array is larger than the other
* @param {Array} obsTimestampArrayOne An array of timestamps for the first set of observations
* @param {Array} obsTimestampArrayTwo An array of timstamps for the second set of observations
* @returns {Array} An array of timestamps missing from either set of observations
*/
const getSymmetricDifferenceBetweenArrays = function (
obsTimestampArrayOne,
obsTimestampArrayTwo
) {
const differenceBetweenArrays = obsTimestampArrayOne
.filter((timestampOne) => !obsTimestampArrayTwo.includes(timestampOne))
.concat(
obsTimestampArrayTwo.filter(
(timestampTwo) => !obsTimestampArrayTwo.includes(timestampTwo)
)
);
return differenceBetweenArrays;
};
/**
* Determines the indexes of timestamps that are missing from a smaller set of observatiuons. Based on the comparison of two observation arrays, where one array is larger than the other
* @param {Array} missingTimestampsArr An array of strings representing the missing timestamps
* @param {Array} largerObsTimestampArr An array of timestamps for the larger array of observations
* @returns {Array} An array of the indexes of the missing observations
*/
const getIndexOfMissingObservation = function (
missingTimestampsArr,
largerObsTimestampArr
) {
const indexesMissingObs = missingTimestampsArr.map((index) =>
largerObsTimestampArr.indexOf(index)
);
return indexesMissingObs;
};
/**
* Removes observations (by modifying array in place) from a larger set of observations that are missing from a smaller set of observatiuons. Based on the comparison of two observation arrays, where one array is larger than the other
* @param {Array} missingIndexesArr An array of the indexes of the observations missing from the smaller set of observations
* @param {Array} largerObsArr The larger array of observations (timestamp + value) which is modified in place
* @returns {undefined}
*/
const removeMissingObservationFromLargerArray = function (
missingIndexesArr,
largerObsArr
) {
missingIndexesArr.forEach((index) => {
if (index > -1) {
largerObsArr.splice(index, 1);
}
});
};
/**
* Compares the length of two input arrays to determine the larger one
* @param {Array} firstArr First input array
* @param {Array} secondArr Second input array
* @returns {Array} The larger array
*/
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;
};
/**
* Extracts and combines observation values from two imput observation arrays of equal length
* @param {Array} obsArrayOne First set of N observations (timestamp + value)
* @param {Array} obsArrayTwo Second set of N observations (timestamp + value)
* @returns {Array} A 2*N array of observation values from both input observation arrays
*/
const createCombinedObservationValues = function (obsArrayOne, obsArrayTwo) {
// Extract the values from the two observation arrays
const obsValuesOne = obsArrayOne.map((result) => result[1]);
const obsValuesTwo = obsArrayTwo.map((result) => result[1]);
// Since the arrays are of equal length, we need only use one of the arrays for looping
const obsValuesOnePlusTwo = obsValuesOne.map((obsValOne, i) => {
return [obsValOne, obsValuesTwo[i]];
});
return obsValuesOnePlusTwo;
};
/**
* Format the response from SensorThings API to make it suitable for scatter plot
* @param {Array} obsArrayOne Response from SensorThings API as array
* @param {Array} obsArrayTwo Response from SensorThings API as array
* @returns {Array} Array of formatted observations suitable for use in a scatter plot
*/
const formatSTAResponseForScatterPlot = function (obsArrayOne, obsArrayTwo) {
// When our observation arrays have DIFFERENT lengths
if (obsArrayOne.length !== obsArrayTwo.length) {
// Create arrays with timestamps only
const obsArrayOneTimestamp = obsArrayOne.map(
(obsTimeValue) => obsTimeValue[0]
);
const obsArrayTwoTimestamp = obsArrayTwo.map(
(obsTimeValue) => obsTimeValue[0]
);
const missingTimestamp = getSymmetricDifferenceBetweenArrays(
obsArrayOneTimestamp,
obsArrayTwoTimestamp
);
// Determine the larger observation timestamp array
const biggerObsTimestampArr = getLargerArrayBetweenTwoInputArrays(
obsArrayOneTimestamp,
obsArrayTwoTimestamp
);
// Indexes of the missing observations
const indexesMissingObsArr = getIndexOfMissingObservation(
missingTimestamp,
biggerObsTimestampArr
);
// Determine the larger observation array
const biggerObsArr = getLargerArrayBetweenTwoInputArrays(
obsArrayOne,
obsArrayTwo
);
// Remove the missing observation from the larger array of observations
// Modifies the array in place
removeMissingObservationFromLargerArray(indexesMissingObsArr, biggerObsArr);
return createCombinedObservationValues(obsArrayOne, obsArrayTwo);
}
// When our observation arrays already have SAME lengths
return createCombinedObservationValues(obsArrayOne, obsArrayTwo);
};
/**
* Draw a scatter plot using Highcharts library
* @param {*} formattedObsArrayForSeriesOnePlusSeriesTwo Response from SensorThings API formatted for use in a scatter plot
* @param {*} formattedDatastreamMetadataSeriesOne Object containing Datastream metadata for the first chart series
* @param {*} formattedDatastreamMetadataSeriesTwo Object containing Datastream metadata for the second chart series
* @returns {undefined}
*/
const drawScatterPlotHC = function (
formattedObsArrayForSeriesOnePlusSeriesTwo,
formattedDatastreamMetadataSeriesOne,
formattedDatastreamMetadataSeriesTwo
) {
const {
datastreamDescription: DATASTREAM_DESCRIPTION_SERIES_1,
datastreamName: DATASTREAM_NAME_SERIES_1,
phenomenonName: PHENOMENON_NAME_SERIES_1,
unitOfMeasurementSymbol: PHENOMENON_SYMBOL_SERIES_1,
} = formattedDatastreamMetadataSeriesOne;
const {
datastreamDescription: DATASTREAM_DESCRIPTION_SERIES_2,
datastreamName: DATASTREAM_NAME_SERIES_2,
phenomenonName: PHENOMENON_NAME_SERIES_2,
unitOfMeasurementSymbol: PHENOMENON_SYMBOL_SERIES_2,
} = formattedDatastreamMetadataSeriesTwo;
// Order of axes
// Y-Axis -- Series 2
// X-Axis -- Series 1
const CHART_TITLE = `${PHENOMENON_NAME_SERIES_2} Versus ${PHENOMENON_NAME_SERIES_1}`;
const CHART_SUBTITLE = `Source: ${DATASTREAM_NAME_SERIES_2} & ${DATASTREAM_NAME_SERIES_1}`;
const SERIES_1_NAME = `${PHENOMENON_NAME_SERIES_1}`;
const SERIES_1_SYMBOL = `${PHENOMENON_SYMBOL_SERIES_1}`;
const SERIES_2_NAME = `${PHENOMENON_NAME_SERIES_2}`;
const SERIES_2_SYMBOL = `${PHENOMENON_SYMBOL_SERIES_2}`;
const SERIES_COMBINED_NAME = "Y, X";
const SERIES_COMBINED_SYMBOL_COLOR_RGB_ELEMENTS = "223, 83, 83";
const SERIES_COMBINED_SYMBOL_COLOR_OPACITY = ".3";
const SERIES_COMBINED_SYMBOL_COLOR = `rgba(${SERIES_COMBINED_SYMBOL_COLOR_RGB_ELEMENTS}, ${SERIES_COMBINED_SYMBOL_COLOR_OPACITY})`;
const MARKER_RADIUS = 2;
Highcharts.chart("chart-scatter-plot", {
chart: {
type: "scatter",
zoomType: "xy",
},
boost: {
useGPUTranslations: true,
usePreAllocated: true,
},
title: {
text: CHART_TITLE,
},
subtitle: {
text: CHART_SUBTITLE,
},
xAxis: {
labels: {
format: `{value}`,
},
title: {
enabled: true,
text: `${SERIES_1_NAME} [${SERIES_1_SYMBOL}]`,
},
startOnTick: true,
endOnTick: true,
showLastLabel: true,
},
yAxis: [
{
labels: {
format: `{value}`,
},
title: {
text: `${SERIES_2_NAME} [${SERIES_2_SYMBOL}]`,
},
},
],
legend: {
enabled: false,
},
plotOptions: {
scatter: {
marker: {
radius: MARKER_RADIUS,
states: {
hover: {
enabled: true,
lineColor: "rgb(100,100,100)",
},
},
},
states: {
hover: {
marker: {
enabled: false,
},
},
},
tooltip: {
headerFormat: "{series.name}<br>",
pointFormat: `<b>{point.y:.2f} ${SERIES_1_SYMBOL}, {point.x:.2f} ${SERIES_2_SYMBOL}</b>`,
},
},
},
series: [
{
name: SERIES_COMBINED_NAME,
color: SERIES_COMBINED_SYMBOL_COLOR,
data: formattedObsArrayForSeriesOnePlusSeriesTwo,
},
],
});
};
/** /**
* Follows "@iot.nextLink" links in SensorThingsAPI's response * Follows "@iot.nextLink" links in SensorThingsAPI's response
* Appends new results to existing results * Appends new results to existing results
...@@ -498,23 +795,24 @@ const getCombinedObservationsFromAllNextLinks = function ( ...@@ -498,23 +795,24 @@ const getCombinedObservationsFromAllNextLinks = function (
* @param {Promise} metadataPlusObsPromiseArray An array that contains two promises, one for datastream metadata, the other for observations * @param {Promise} metadataPlusObsPromiseArray An array that contains two promises, one for datastream metadata, the other for observations
* @returns {Promise} A promise that contains two arrays when fulfilled, one for datastream metadata and the other for observations * @returns {Promise} A promise that contains two arrays when fulfilled, one for datastream metadata and the other for observations
*/ */
const getMetadataPlusObservationsForChart = async function ( const getMetadataPlusObservationsFromSingleDatastream = async function (
metadataPlusObsPromiseArray metadataPlusObsPromiseArray
) { ) {
try {
// Array to store our final result // Array to store our final result
const combinedResolvedPromises = []; const combinedResolvedPromises = [];
// Use for/of loop - we need to maintain the order of execution of the async operations // Use for/of loop - we need to maintain the order of execution of the async operations
for (const promise of metadataPlusObsPromiseArray) { for (const promise of metadataPlusObsPromiseArray) {
try {
// Resolved value of a single promise // Resolved value of a single promise
const resolvedPromise = await promise; const resolvedPromise = await promise;
combinedResolvedPromises.push(resolvedPromise); combinedResolvedPromises.push(resolvedPromise);
}
return combinedResolvedPromises;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
}
return combinedResolvedPromises;
}; };
/** /**
...@@ -526,398 +824,106 @@ const getMetadataPlusObservationsForChart = async function ( ...@@ -526,398 +824,106 @@ const getMetadataPlusObservationsForChart = async function (
const getObservationsFromMultipleDatastreams = async function ( const getObservationsFromMultipleDatastreams = async function (
observationPromiseArray observationPromiseArray
) { ) {
try {
// Array to store our final result // Array to store our final result
const observationsAllDatastreamsArr = []; const observationsAllDatastreamsArr = [];
// Use for/of loop - we need to maintain the order of execution of the async operations // Use for/of loop - we need to maintain the order of execution of the async operations
for (const observationPromise of observationPromiseArray) { for (const observationPromise of observationPromiseArray) {
try {
// Observations from a single Datastream // Observations from a single Datastream
const observations = await observationPromise; const observations = await observationPromise;
observationsAllDatastreamsArr.push(observations); observationsAllDatastreamsArr.push(observations);
}
return observationsAllDatastreamsArr;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
}
return observationsAllDatastreamsArr;
}; };
// Building + phenomenon + sampling rate /**
const buildingsSensorSamplingRateRLArr = [ * Retrieve the metadata from multiple Datastreams and the Observations corresponding to these Datastreams
["101", "rl", "60min"], * @async
["102", "rl", "60min"], * @param {Array} bldgSensorSamplingRateArr A 3*N array containing buildings, sensors & sampling rates as strings, e.g. ["101", "rl", "60min"]
["107", "rl", "60min"], * @returns {Promise} A promise that contains a N*2 array (the first element is an array of Observations and the second element is an array of Datastream metadata objects) when fulfilled
["112, 118", "rl", "60min"], */
["125", "rl", "60min"], const getMetadataPlusObservationsFromMultipleDatastreams = async function (
["225", "rl", "60min"], bldgSensorSamplingRateArr
]; ) {
try {
// Datastreams IDs if (!bldgSensorSamplingRateArr) return;
const datastreamsRLArr = buildingsSensorSamplingRateRLArr.map((bldg) =>
getDatastreamIdFromBuildingNumber(...bldg)
);
// Datastreams URLs // Datastreams IDs
const datastreamsUrlRLArr = datastreamsRLArr.map((datastreamId) => const datastreamsIdsArr = bldgSensorSamplingRateArr.map(
(bldgSensorSamplingRate) =>
getDatastreamIdFromBuildingNumber(...bldgSensorSamplingRate)
);
// Observations URLs
const observationsUrlArr = datastreamsIdsArr.map((datastreamId) =>
getObservationsUrl(BASE_URL, datastreamId) getObservationsUrl(BASE_URL, datastreamId)
); );
// Promise objects - Observations / RL // Datastreams URLs
const observationsPromisesRLArr = datastreamsUrlRLArr.map((obsUrl) => const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) =>
getDatastreamUrl(BASE_URL, datastreamId)
);
// Promise objects - Observations
const observationsPromisesArr = observationsUrlArr.map((obsUrl) =>
getCombinedObservationsFromAllNextLinks( getCombinedObservationsFromAllNextLinks(
axiosGetRequest(obsUrl, QUERY_PARAMS_COMBINED) axiosGetRequest(obsUrl, QUERY_PARAMS_COMBINED)
) )
); );
// getObservationsFromMultipleDatastreams(observationsPromisesRLArr).then((x) =>
// console.log(x)
// );
const drawScatterPlotHC = function () {
// Ruecklauf
const ruecklaufArr = [
[1578193200000, 69.1999969482422],
[1578196800000, 69.1999969482422],
[1578200400000, 69.1999969482422],
[1578204000000, 69.1999969482422],
[1578207600000, 69.1999969482422],
[1578211200000, 69.1999969482422],
[1578214800000, 69.1999969482422],
[1578218400000, 69.1999969482422],
[1578222000000, 69.1999969482422],
[1578225600000, 69.1999969482422],
[1578229200000, 69.1999969482422],
[1578232800000, 69.1999969482422],
[1578236400000, 69.1999969482422],
[1578240000000, 69.1999969482422],
[1578243600000, 69.1999969482422],
[1578247200000, 69.1999969482422],
[1578250800000, 69.1999969482422],
[1578254400000, 69.1999969482422],
[1578258000000, 69.1999969482422],
[1578261600000, 69.1999969482422],
[1578265200000, 69.1999969482422],
[1578268800000, 69.1999969482422],
[1578272400000, 69.1999969482422],
[1578276000000, 69.1999969482422],
[1578279600000, 69.1999969482422],
[1578283200000, 69.1999969482422],
[1578286800000, 69.1999969482422],
[1578290400000, 69.1999969482422],
[1578294000000, 69.1999969482422],
[1578297600000, 69.1999969482422],
[1578301200000, 69.1999969482422],
[1578304800000, 69.1999969482422],
[1578308400000, 69.1999969482422],
[1578312000000, 69.1999969482422],
[1578315600000, 69.1999969482422],
[1578319200000, 69.1999969482422],
[1578322800000, 69.1999969482422],
[1578326400000, 69.1999969482422],
[1578330000000, 69.1999969482422],
[1578333600000, 69.1999969482422],
[1578337200000, 69.1999969482422],
[1578340800000, 69.1999969482422],
[1578344400000, 69.1999969482422],
[1578348000000, 69.1999969482422],
[1578351600000, 70.3556109079997],
[1578355200000, 76.920997634146],
[1578358800000, 79.4292947098697],
[1578362400000, 79.2650916245309],
[1578366000000, 79.6125674172757],
[1578369600000, 79.0597236964905],
[1578373200000, 77.7484098868052],
[1578376800000, 77.1226613864899],
[1578380400000, 76.9194480415149],
[1578384000000, 78.0028471359237],
[1578387600000, 77.1535494270819],
[1578391200000, 75.0470741498029],
[1578394800000, 74.679502580818],
[1578398400000, 73.6077361986314],
[1578402000000, 72.5580677314758],
[1578405600000, 72.3134755830553],
[1578409200000, 73.2778338997311],
[1578412800000, 73.7656394293467],
[1578416400000, 74.4736907299466],
[1578420000000, 74.046935040758],
[1578423600000, 73.4957105572807],
[1578427200000, 73.9627712815163],
[1578430800000, 74.0438044241729],
[1578434400000, 73.3727496036106],
[1578438000000, 73.1666655679279],
[1578441600000, 73.3418058388816],
[1578445200000, 73.6250001589457],
[1578448800000, 73.829112378629],
[1578452400000, 74.564083528116],
[1578456000000, 75.5183061171072],
[1578459600000, 77.3372781058983],
[1578463200000, 78.0196371225993],
[1578466800000, 77.6398578971368],
[1578470400000, 78.5464104081542],
[1578474000000, 78.7977605936686],
[1578477600000, 76.0006624035588],
[1578481200000, 74.818987728345],
[1578484800000, 72.7776491559135],
[1578488400000, 71.1266380795161],
[1578492000000, 71.3866485616896],
[1578495600000, 72.1584558128357],
[1578499200000, 72.7288795283423],
[1578502800000, 73.2401491424669],
[1578506400000, 72.613320930343],
[1578510000000, 71.7903886201647],
[1578513600000, 71.4483344078064],
[1578517200000, 71.8162703686467],
[1578520800000, 71.3690680013303],
[1578524400000, 70.6132688085203],
[1578528000000, 69.9669739277875],
[1578531600000, 69.2502318650422],
[1578535200000, 68.8407318482576],
[1578538800000, 71.4223982252898],
[1578542400000, 68.8941290716666],
[1578546000000, 71.8311421724037],
[1578549600000, 72.5245706435945],
];
// Power
const powerArr = [
[1578193200000, 0],
[1578196800000, 0],
[1578200400000, 0],
[1578204000000, 0],
[1578207600000, 0],
[1578211200000, 0],
[1578214800000, 0],
[1578218400000, 0],
[1578222000000, 0],
[1578225600000, 0],
[1578229200000, 0],
[1578232800000, 0],
[1578236400000, 0],
[1578240000000, 0],
[1578243600000, 0],
[1578247200000, 0],
[1578250800000, 0],
[1578254400000, 0],
[1578258000000, 0],
[1578261600000, 0],
[1578265200000, 0],
[1578268800000, 0],
[1578272400000, 0],
[1578276000000, 0],
[1578279600000, 0],
[1578283200000, 0],
[1578286800000, 0],
[1578290400000, 0],
[1578294000000, 0],
[1578297600000, 0],
[1578301200000, 0],
[1578304800000, 0],
[1578308400000, 0],
[1578312000000, 0],
[1578315600000, 0],
[1578319200000, 0],
[1578322800000, 0],
[1578326400000, 0],
[1578330000000, 0],
[1578333600000, 0],
[1578337200000, 0],
[1578340800000, 0],
[1578344400000, 0],
[1578348000000, 0],
[1578351600000, 0.831280025800069],
[1578355200000, 27.4361266860337],
[1578358800000, 4.02296011930285],
[1578362400000, 5.46578637448993],
[1578366000000, 189.045738115567],
[1578369600000, 262.879154692536],
[1578373200000, 182.996291840137],
[1578376800000, 253.720326864073],
[1578380400000, 266.71791350888],
[1578384000000, 258.650130305165],
[1578387600000, 256.817462126146],
[1578391200000, 251.198874591439],
[1578394800000, 245.782954276794],
[1578398400000, 225.835229413786],
[1578402000000, 191.164833256192],
[1578405600000, 189.317473084174],
[1578409200000, 160.866751228135],
[1578412800000, 165.104705085896],
[1578416400000, 185.380724406267],
[1578420000000, 6.318082232318],
[1578423600000, 22.6244981930396],
[1578427200000, 0.125080846609247],
[1578430800000, 0.858333364129066],
[1578434400000, 3.15562303745482],
[1578438000000, 1.73965485449897],
[1578441600000, 3.73938900530338],
[1578445200000, 0.641666680574417],
[1578448800000, 1.64397225697835],
[1578452400000, 14.7165156847371],
[1578456000000, 6.7406491904815],
[1578459600000, 257.018884414906],
[1578463200000, 282.409075120573],
[1578466800000, 284.999958205159],
[1578470400000, 291.20836768991],
[1578474000000, 285.753944205729],
[1578477600000, 248.43810322171],
[1578481200000, 227.135268204399],
[1578484800000, 182.10778157076],
[1578488400000, 169.076414526325],
[1578492000000, 160.098294117384],
[1578495600000, 149.832191919638],
[1578499200000, 195.966023142751],
[1578502800000, 159.01891281008],
[1578506400000, 3.94323859943668],
[1578510000000, 9.29238140483663],
[1578513600000, 4.09348021179692],
[1578517200000, 0],
[1578520800000, 0],
[1578524400000, 0],
[1578528000000, 0],
[1578531600000, 0],
[1578535200000, 0],
[1578538800000, 154.315364068476],
[1578542400000, 193.405831769548],
[1578546000000, 136.484141248209],
[1578549600000, 209.041194383494],
];
const CHART_TITLE = "Height Versus Weight of 507 Individuals by Gender";
const CHART_SUBTITLE = "Source: Heinz 2003";
const X_AXIS_TITLE = "Height (cm)";
const SERIES_1_NAME = "Rücklauftemp";
const SERIES_1_SYMBOL_COLOR = "rgba(119, 152, 191, .5)";
const SERIES_1_TEXT_COLOR = "rgb(119, 152, 191)"; // remove transparency from symbol color for a more "intense" color
const SERIES_1_SYMBOL = "°C";
const SERIES_2_NAME = "Power";
const SERIES_2_SYMBOL_COLOR = "rgba(223, 83, 83, .5)";
const SERIES_2_TEXT_COLOR = "rgb(223, 83, 83)"; // remove transparency from symbol color for a more "intense" color
const SERIES_2_SYMBOL = "kW";
Highcharts.chart("chart-scatter-plot", {
chart: {
type: "scatter",
zoomType: "xy",
},
title: {
text: CHART_TITLE,
},
subtitle: { // Observations array
text: CHART_SUBTITLE, const observationsArr = await getObservationsFromMultipleDatastreams(
}, observationsPromisesArr
);
xAxis: { // Metadata array
title: { const metadataArr = await getMetadataFromMultipleDatastreams(
enabled: true, datastreamsUrlArr
text: X_AXIS_TITLE, );
},
type: "datetime",
startOnTick: true,
endOnTick: true,
showLastLabel: true,
},
yAxis: [ return [observationsArr, metadataArr];
{ } catch (err) {
// Primary yAxis console.error(err);
labels: { }
format: `{value} ${SERIES_1_SYMBOL}`, };
style: {
color: SERIES_1_TEXT_COLOR,
},
},
title: {
text: SERIES_1_NAME,
style: {
color: SERIES_1_TEXT_COLOR,
},
},
},
{
// Secondary yAxis
title: {
text: SERIES_2_NAME,
style: {
color: SERIES_2_TEXT_COLOR,
},
},
labels: {
format: `{value} ${SERIES_2_SYMBOL}`,
style: {
color: SERIES_2_TEXT_COLOR,
},
},
opposite: true,
},
],
legend: { /**
layout: "vertical", * Test drawing of scatter plot chart
align: "left", */
verticalAlign: "top", const drawScatterPlotHCTest2 = async function () {
x: 100, const sensorsOfInterestArr = [
y: 70, ["225", "vl", "60min"],
floating: true, // ["125", "rl", "60min"],
backgroundColor: Highcharts.defaultOptions.chart.backgroundColor, ["weather_station_521", "outside_temp", "60min"],
borderWidth: 1, ];
},
plotOptions: { const observationsPlusMetadata =
scatter: { await getMetadataPlusObservationsFromMultipleDatastreams(
marker: { sensorsOfInterestArr
radius: 5, );
states: {
hover: {
enabled: true,
lineColor: "rgb(100,100,100)",
},
},
},
states: {
hover: {
marker: {
enabled: false,
},
},
},
tooltip: {
headerFormat: "{point.x:%e %b, %Y %H:%M:%S}: <b>{point.y}</b>",
pointFormat: "{point.x} cm, {point.y} kg",
valueDecimals: 2,
},
},
},
series: [ // Extract the observations and metadata for each sensor
{ // Array elements in same order as input array
name: SERIES_1_NAME, const [
color: SERIES_1_SYMBOL_COLOR, [obsSensorOneArr, obsSensorTwoArr],
data: ruecklaufArr, [metadataSensorOne, metadataSensorTwo],
tooltip: { ] = observationsPlusMetadata;
valueSuffix: ` ${SERIES_1_SYMBOL}`,
}, drawScatterPlotHC(
}, formatSTAResponseForScatterPlot(obsSensorOneArr, obsSensorTwoArr),
{ formatDatastreamMetadataForChart(metadataSensorOne),
name: SERIES_2_NAME, formatDatastreamMetadataForChart(metadataSensorTwo)
color: SERIES_2_SYMBOL_COLOR, );
data: powerArr,
// need this property for the dual y-axes to work
// defines the y-axis that this series refers to
yAxis: 1,
tooltip: {
valueSuffix: ` ${SERIES_2_SYMBOL}`,
},
},
],
});
}; };
drawScatterPlotHC(); (async () => {
await drawScatterPlotHCTest2();
})();
export { export {
BASE_URL, BASE_URL,
...@@ -927,12 +933,12 @@ export { ...@@ -927,12 +933,12 @@ export {
getObservationsUrl, getObservationsUrl,
createTemporalFilterString, createTemporalFilterString,
axiosGetRequest, axiosGetRequest,
getDatastreamMetadata, getMetadataFromSingleDatastream,
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
formatSTAResponseForHeatMap, formatSTAResponseForHeatMap,
drawHeatMapHC, drawHeatMapHC,
formatSTAResponseForLineChart, formatSTAResponseForLineChartOrScatterPlot,
drawLineChartHC, drawLineChartHC,
getCombinedObservationsFromAllNextLinks, getCombinedObservationsFromAllNextLinks,
getMetadataPlusObservationsForChart, getMetadataPlusObservationsFromSingleDatastream,
}; };
...@@ -7,14 +7,14 @@ import { ...@@ -7,14 +7,14 @@ import {
getDatastreamUrl, getDatastreamUrl,
getObservationsUrl, getObservationsUrl,
axiosGetRequest, axiosGetRequest,
getDatastreamMetadata, getMetadataFromSingleDatastream,
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
formatSTAResponseForHeatMap, formatSTAResponseForHeatMap,
drawHeatMapHC, drawHeatMapHC,
formatSTAResponseForLineChart, formatSTAResponseForLineChartOrScatterPlot,
drawLineChartHC, drawLineChartHC,
getCombinedObservationsFromAllNextLinks, getCombinedObservationsFromAllNextLinks,
getMetadataPlusObservationsForChart, getMetadataPlusObservationsFromSingleDatastream,
} from "./appChart.js"; } from "./appChart.js";
const buildingsAvailableSensorsArr = [ const buildingsAvailableSensorsArr = [
...@@ -289,13 +289,15 @@ const selectChartTypeFromDropDown = async function () { ...@@ -289,13 +289,15 @@ const selectChartTypeFromDropDown = async function () {
const URL_OBSERVATIONS = getObservationsUrl(BASE_URL, selectedDatastream); const URL_OBSERVATIONS = getObservationsUrl(BASE_URL, selectedDatastream);
// Create promises // Create promises
const promiseDatastreamMetadata = getDatastreamMetadata(URL_DATASTREAM); const promiseDatastreamMetadata =
getMetadataFromSingleDatastream(URL_DATASTREAM);
const promiseCombinedObservations = getCombinedObservationsFromAllNextLinks( const promiseCombinedObservations = getCombinedObservationsFromAllNextLinks(
axiosGetRequest(URL_OBSERVATIONS, QUERY_PARAMS_COMBINED) axiosGetRequest(URL_OBSERVATIONS, QUERY_PARAMS_COMBINED)
); );
// Pass promises to our async function // Pass promises to our async function
const metadataPlusObservations = await getMetadataPlusObservationsForChart([ const metadataPlusObservations =
await getMetadataPlusObservationsFromSingleDatastream([
promiseCombinedObservations, promiseCombinedObservations,
promiseDatastreamMetadata, promiseDatastreamMetadata,
]); ]);
...@@ -306,7 +308,7 @@ const selectChartTypeFromDropDown = async function () { ...@@ -306,7 +308,7 @@ const selectChartTypeFromDropDown = async function () {
if (selectedChartType === "Line") { if (selectedChartType === "Line") {
drawLineChartHC( drawLineChartHC(
formatSTAResponseForLineChart(combinedObs), formatSTAResponseForLineChartOrScatterPlot(combinedObs),
formatDatastreamMetadataForChart(datastreamMetadata) formatDatastreamMetadataForChart(datastreamMetadata)
); );
} else if (selectedChartType === "Heatmap") { } else if (selectedChartType === "Heatmap") {
......
Supports Markdown
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