Reputation: 432
I am currently using Medical Dashboard of Lightningcharts js. When the same patient is opened in two different machines (say two desktops) then the charts for the channels/parameters (ECG, Pulse rate and Respiratory rate) are different for different machines. Currently the data fed to the charts is live from a WebSocket and is coming from a device present at the client location. The expectation is to have consistent and same graphs on multiple devices for a particular patient.
After performing rigorous end to end testing, it was found that the data sent from backend and received on the frontend is exactly same and is received on the same timestamp in different devices. We also checked that the array used as input for the channels is being fed with the correct data. This was observed in multiple machines/devices. The question that we are currently pondering on is why different graphs are getting drawn if the data fed to the lightning charts component are the same in multiple devices?
I think it might have to do something with the addData() function used as callback with requestAnimatedFrame() method (depends on the system performance to handles all those executions).
I am also wondering, does generating charts depend on the performance of the system as well? We verified this by checking FPS on multiple devices and found out that even with multiple devices having same FPS (around 60) shows different graphs.
We also created the single chart from scratch and used different (scheduler) logic to push data into the array (apart from logic used in Medical Dashboard example) and in this case as well the graphs generated are different in multiple devices.
Sharing pieces of code used for this component.
Main object that holds all channels with the dataset:
const channels: iChannel[] = [
{
shortName: "ECG/EKG",
name: "Electrocardiogram",
type: "ecg",
dataSet: [],
yStart: -50,
yEnd: 160,
}, other channels...
];
Add data function used to push data into array:
const addData = () => {
const tNow = window.performance.now();
const seriesNewPoints = seriesList.map((_) => []);
if (tNow - lastDataReceivedTime.current > 20000) {
// If no data received, reset everything.
channels.forEach((channel) => {
channel.dataSet.length = 0;
});
uiList.forEach((ui) => {
ui.labelEcgHeartRate && ui.labelEcgHeartRate.setText("");
ui.labelBpmValue && ui.labelBpmValue.setText("");
ui.labelBpmValue && ui.labelBloodPIValue.setText("");
ui.labelMinMaxBPValue && ui.labelMinMaxBPValue.setText("");
ui.labelMeanBPValue && ui.labelMeanBPValue.setText("");
ui.labelRespiratoryValue && ui.labelRespiratoryValue.setText("");
});
}
while (tNow > tSamplePos) {
const x = tSamplePos;
for (let i = 0; i < seriesList.length - 1; i++) {
const channel = channels[i];
const dataSet = channel.dataSet;
const sample = dataSet[iSampleX % dataSet.length];
// @ts-ignore
seriesNewPoints[i].push({ x, y: sample });
}
tSamplePos += 1000 / SAMPLE_RATE;
iSampleX += 1;
}
seriesList.forEach((series, i) => series.add(seriesNewPoints[i]));
channelIncomingDataPointsCount += seriesNewPoints[0].length;
requestAnimationFrame(addData);
};
requestAnimationFrame(addData);
let channelIncomingDataPointsCount = 0;
let channelIncomingDataPointsLastUpdate = window.performance.now();
setInterval(() => {
const tNow = window.performance.now();
const chDataPointsPerSecond = Math.round(
(channelIncomingDataPointsCount * 1000) /
(tNow - channelIncomingDataPointsLastUpdate)
);
uiList.forEach((ui, i) => {
ui.labelSampleRate.setText(`${chDataPointsPerSecond} samples / second`);
});
channelIncomingDataPointsCount = 0;
channelIncomingDataPointsLastUpdate = tNow;
}, 2000);
Websocket connection:
function createSocketConnection(uiList, addData) {
const socket = new WebSocket(websocketURL);
socket.onmessage = function (event) {
const message = JSON.parse(event.data);
updateChartData(message, uiList);
requestAnimationFrame(addData);
};
Here updateChartData() is used to push data to the array.
UpdateChartData function(): starts
const updateChartData = (response: any, uiList: any) => {
let ecgData = response?.ecg?.split("^");
let ecgHeartRate = response?.ecgHeartRate;
...Extracting all parameters needed
//For Absolute values
uiList.forEach((ui) => {
if (ui.labelEcgHeartRate) {
if (ecgHeartRate) {
ui.labelEcgHeartRate.setText(ecgHeartRate.toString());
}
}
Pushing data into the array:
const ecgIndex = channels.findIndex(
(channel) => channel.type === ChartDataType.ecg
);
if (ecgData) {
ecgData
?.filter((item: number) => item < 1000)
?.map((item: string) => {
return channels[ecgIndex].dataSet.push(item);
});
}
Similar logic used for other channels.
UpdateChartData function(): ends
Screenshots stating the same: Both screenshots are taken at the same time in different devices.
I thought that since its real time data and data received will be huge and rate of receiving the data will be significantly greater, so I did a controlled testing in the testing environment with limited sets of data being sent periodically. This was tested only for one (ECG) channel, which currently has a Y–range set from –50 to 160. So, we created custom dataset where each follow-up object will have values ranging from –50 to 160 (increasing order) and next object will be ranging from 160 to –50 (decreasing order) and so on... This would form a chart that would look like this: /\/\/\/\/\/\/\/\. I confirmed this by checking timestamp when we receive the data, extracting data from it and pushing the data in to an array. We verified that the input array also has the same data being pushed and in the same order what we receive.
But the charts being generated are different in this case as well. Also, the chart generated should always be in /\/\/\/\/\/\/\ form, but the charts also seem to be distorted.
Attaching screenshots stating the same:
Apart from this, there are few observations that I would like to share:
If we open the charts on multiple devices at the same time, then the charts drawn on different devices are the same. But in case if we open the charts in one device and let's say 2 mins later in another device, then the charts are different.
Following up the first point, we have 2 devices which have two charts opened at the same time. If we stop sending the data and wait for the charts to clear up. And again, send the data after some time has passed. Now both devices are receiving the same set of data at the same time, but charts drawn on different devices are different.
We checked on the FPS part as well, one device has 30-40 FPS and another has 60 FPS, the charts are different. Another case, when two devices have constant 60FPS, in this case as well the charts are different.
When we stopped sending the data into the WebSocket, we verified that the last few objects being received are the same (verified with timestamp). But when the charts end, it does not end with the same figure/pattern on both devices. This is also valid for starting point, but we understand that it takes some time to subscribe to WebSocket, so the initial few data values might be different, so to some extent charts will be different. (Please correct us in this case if our thinking is not aligning with your expertise). Attaching screenshots stating the same.
Lightningcharts JS version used: "@arction/lcjs": "^5.0.5"
, in React.JS application
Need help regarding this. Please guide.
I tried checking timestamps when data received and data being pushed to the array in multiple devices. It turns out to be same.
Upvotes: 0
Views: 21