0👍
This is slightly out of scope, since the solution below does not use the data structure in my original question. However, as I believe my original method was much flawed in that it used nested API requests, I’m posting this answer that I believe achieves what I’m trying to do in a good manner.
My backend uses MongoDB, and this aggregation yielded a suitable data structure:
Observation.aggregate([{
$group: {
_id: "$location.name",
temperatures: {
$push: { "temperature": "$temperature" },
},
dates: {
$push: { "date": "$date" },
},
}
}]);
(N.B., $location.name
takes unique values so I’m using it as $group._id
to strip a few lines of code.)
With that, it became straightforward to create the chart like so:
ngAfterViewInit() {
this.observationService.getAllGrouped()
.subscribe((locations: any) => {
let datasets = [];
locations.forEach(location => {
let temperatures = location.temperatures.map(t => t.temperature);
let dates = location.dates.map(d => d.date);
let data = [];
temperatures.forEach((temperature, i) => {
data.push({ x: dates[i], y: temperature });
});
datasets.push({ label: location._id, data: data });
});
const data = { datasets: datasets };
const options = {
scales: {
xAxes: [{
type: 'time',
}],
},
};
this.chart = new Chart('canvas', { type: 'scatter', data: data, options: options });
});
}
1👍
Try to create a chart after component’s view is initialized, thus use ngAfterViewInit instead of ngOnInit.
Update:
In the case where you want to plot all the datasets, you have extra subscribe
. Here:
locations.forEach((location: any) => {
this.observationService.getAllByLocation(location)
----> .subscribe(observations => {
datasets.push(this.createDataset(observations));
});
});
which means that line:
this.chart = new Chart('temperatureChart', { type: 'scatter', data: data, options: options });
will be called before datasets
is filled with data.
One possible solution would be to add data series in the subsribe
above like:
locations.forEach((location: any) => {
this.observationService.getAllByLocation(location)
.subscribe(observations => {
this.chart.addSerie({
data: this.createDataset(observations)
},
true,
true);
});
});
however, the resulting plot will be updated few times (you will have to wait until it loads fully)
Second one, you could create a chart once the subsribe
is finished, like:
locations.forEach((location: any) => {
this.observationService.getAllByLocation(location)
.subscribe(observations => {
datasets.push(this.createDataset(observations));
},
() => { /*error handling */},
() => { /*observable is finished your datasets is filled
with data, here you can create a graph*/});
});