stream-charts 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +757 -342
- package/changes.md +11 -0
- package/dist/src/app/charts/Chart.d.ts +116 -87
- package/dist/src/app/charts/Chart.js +96 -101
- package/dist/src/app/charts/Chart.js.map +1 -1
- package/dist/src/app/charts/axes/AxesState.d.ts +64 -0
- package/dist/src/app/charts/axes/AxesState.js +97 -0
- package/dist/src/app/charts/axes/AxesState.js.map +1 -0
- package/dist/src/app/charts/axes/AxesState.test.js +30 -0
- package/dist/src/app/charts/axes/AxesState.test.js.map +1 -0
- package/dist/src/app/charts/axes/AxisInterval.d.ts +92 -0
- package/dist/src/app/charts/axes/AxisInterval.js +126 -0
- package/dist/src/app/charts/axes/AxisInterval.js.map +1 -0
- package/dist/src/app/charts/axes/AxisInterval.test.js +120 -0
- package/dist/src/app/charts/axes/AxisInterval.test.js.map +1 -0
- package/dist/src/app/charts/axes/BaseAxisRange.d.ts +83 -0
- package/dist/src/app/charts/axes/BaseAxisRange.js +58 -0
- package/dist/src/app/charts/axes/BaseAxisRange.js.map +1 -0
- package/dist/src/app/charts/axes/ContinuousAxis.d.ts +22 -0
- package/dist/src/app/charts/axes/ContinuousAxis.js +96 -0
- package/dist/src/app/charts/axes/ContinuousAxis.js.map +1 -0
- package/dist/src/app/charts/axes/ContinuousAxisRange.d.ts +59 -0
- package/dist/src/app/charts/axes/ContinuousAxisRange.js +84 -0
- package/dist/src/app/charts/axes/ContinuousAxisRange.js.map +1 -0
- package/dist/src/app/charts/axes/ContinuousAxisRange.test.js +47 -0
- package/dist/src/app/charts/axes/ContinuousAxisRange.test.js.map +1 -0
- package/dist/src/app/charts/axes/OrdinalAxis.d.ts +23 -0
- package/dist/src/app/charts/axes/OrdinalAxis.js +124 -0
- package/dist/src/app/charts/axes/OrdinalAxis.js.map +1 -0
- package/dist/src/app/charts/axes/OrdinalAxisRange.d.ts +69 -0
- package/dist/src/app/charts/axes/OrdinalAxisRange.js +100 -0
- package/dist/src/app/charts/axes/OrdinalAxisRange.js.map +1 -0
- package/dist/src/app/charts/axes/OrdinalAxisRange.test.js +48 -0
- package/dist/src/app/charts/axes/OrdinalAxisRange.test.js.map +1 -0
- package/dist/src/app/charts/axes/axes.d.ts +391 -0
- package/dist/src/app/charts/axes/axes.js +1046 -0
- package/dist/src/app/charts/axes/axes.js.map +1 -0
- package/dist/src/app/charts/d3types.d.ts +10 -10
- package/dist/src/app/charts/filters/regexFilter.d.ts +9 -0
- package/dist/src/app/charts/filters/regexFilter.js +18 -0
- package/dist/src/app/charts/filters/regexFilter.js.map +1 -0
- package/dist/src/app/charts/filters/regexFilter.test.d.ts +1 -0
- package/dist/src/app/charts/filters/regexFilter.test.js +11 -0
- package/dist/src/app/charts/filters/regexFilter.test.js.map +1 -0
- package/dist/src/app/charts/hooks/useAxes.d.ts +144 -0
- package/dist/src/app/charts/hooks/useAxes.js +187 -0
- package/dist/src/app/charts/hooks/useAxes.js.map +1 -0
- package/dist/src/app/charts/hooks/useChart.d.ts +30 -201
- package/dist/src/app/charts/hooks/useChart.js +33 -134
- package/dist/src/app/charts/hooks/useChart.js.map +1 -1
- package/dist/src/app/charts/hooks/useDataObservable.d.ts +74 -0
- package/dist/src/app/charts/hooks/useDataObservable.js +76 -0
- package/dist/src/app/charts/hooks/useDataObservable.js.map +1 -0
- package/dist/src/app/charts/hooks/useInitialData.d.ts +38 -0
- package/dist/src/app/charts/hooks/useInitialData.js +29 -0
- package/dist/src/app/charts/hooks/useInitialData.js.map +1 -0
- package/dist/src/app/charts/hooks/useMouse.d.ts +53 -0
- package/dist/src/app/charts/hooks/useMouse.js +65 -0
- package/dist/src/app/charts/hooks/useMouse.js.map +1 -0
- package/dist/src/app/charts/hooks/usePlotDimensions.d.ts +34 -0
- package/dist/src/app/charts/hooks/usePlotDimensions.js +73 -0
- package/dist/src/app/charts/hooks/usePlotDimensions.js.map +1 -0
- package/dist/src/app/charts/hooks/useTooltip.d.ts +64 -0
- package/dist/src/app/charts/hooks/useTooltip.js +52 -0
- package/dist/src/app/charts/hooks/useTooltip.js.map +1 -0
- package/dist/src/app/charts/observables/ChartData.d.ts +23 -0
- package/dist/src/app/charts/observables/ChartData.js +20 -0
- package/dist/src/app/charts/observables/ChartData.js.map +1 -0
- package/dist/src/app/charts/observables/iterates.d.ts +52 -0
- package/dist/src/app/charts/observables/iterates.js +121 -0
- package/dist/src/app/charts/observables/iterates.js.map +1 -0
- package/dist/src/app/charts/observables/iterates.test.d.ts +1 -0
- package/dist/src/app/charts/observables/iterates.test.js +180 -0
- package/dist/src/app/charts/observables/iterates.test.js.map +1 -0
- package/dist/src/app/charts/observables/ordinals.d.ts +75 -0
- package/dist/src/app/charts/observables/ordinals.js +141 -0
- package/dist/src/app/charts/observables/ordinals.js.map +1 -0
- package/dist/src/app/charts/observables/ordinals.test.d.ts +1 -0
- package/dist/src/app/charts/observables/ordinals.test.js +102 -0
- package/dist/src/app/charts/observables/ordinals.test.js.map +1 -0
- package/dist/src/app/charts/plots/BarPlot.d.ts +81 -0
- package/dist/src/app/charts/plots/BarPlot.js +557 -0
- package/dist/src/app/charts/plots/BarPlot.js.map +1 -0
- package/dist/src/app/charts/plots/PoincarePlot.d.ts +78 -0
- package/dist/src/app/charts/plots/PoincarePlot.js +504 -0
- package/dist/src/app/charts/plots/PoincarePlot.js.map +1 -0
- package/dist/src/app/charts/{RasterPlot.d.ts → plots/RasterPlot.d.ts} +1 -1
- package/dist/src/app/charts/{RasterPlot.js → plots/RasterPlot.js} +152 -133
- package/dist/src/app/charts/plots/RasterPlot.js.map +1 -0
- package/dist/src/app/charts/{ScatterPlot.d.ts → plots/ScatterPlot.d.ts} +10 -8
- package/dist/src/app/charts/plots/ScatterPlot.js +379 -0
- package/dist/src/app/charts/plots/ScatterPlot.js.map +1 -0
- package/dist/src/app/charts/{plot.d.ts → plots/plot.d.ts} +12 -14
- package/dist/src/app/charts/{plot.js → plots/plot.js} +19 -17
- package/dist/src/app/charts/plots/plot.js.map +1 -0
- package/dist/src/app/charts/series/baseSeries.d.ts +38 -0
- package/dist/src/app/charts/series/baseSeries.js +36 -0
- package/dist/src/app/charts/series/baseSeries.js.map +1 -0
- package/dist/src/app/charts/series/datumSeries.test.d.ts +1 -0
- package/dist/src/app/charts/series/datumSeries.test.js +50 -0
- package/dist/src/app/charts/series/datumSeries.test.js.map +1 -0
- package/dist/src/app/charts/series/iterateSeries.d.ts +42 -0
- package/dist/src/app/charts/series/iterateSeries.js +34 -0
- package/dist/src/app/charts/series/iterateSeries.js.map +1 -0
- package/dist/src/app/charts/series/ordinalSeries.d.ts +54 -0
- package/dist/src/app/charts/series/ordinalSeries.js +98 -0
- package/dist/src/app/charts/series/ordinalSeries.js.map +1 -0
- package/dist/src/app/charts/series/timeSeries.d.ts +30 -0
- package/dist/src/app/charts/series/timeSeries.js +19 -0
- package/dist/src/app/charts/series/timeSeries.js.map +1 -0
- package/dist/src/app/charts/{chartData.d.ts → series/timeSeriesChartData.d.ts} +11 -6
- package/dist/src/app/charts/series/timeSeriesChartData.js +32 -0
- package/dist/src/app/charts/series/timeSeriesChartData.js.map +1 -0
- package/dist/src/app/charts/styling/barPlotStyle.d.ts +41 -0
- package/dist/src/app/charts/styling/barPlotStyle.js +84 -0
- package/dist/src/app/charts/styling/barPlotStyle.js.map +1 -0
- package/dist/src/app/charts/{margins.d.ts → styling/margins.d.ts} +7 -5
- package/dist/src/app/charts/{margins.js → styling/margins.js} +19 -9
- package/dist/src/app/charts/styling/margins.js.map +1 -0
- package/dist/src/app/charts/styling/margins.test.d.ts +1 -0
- package/dist/src/app/charts/styling/margins.test.js +19 -0
- package/dist/src/app/charts/styling/margins.test.js.map +1 -0
- package/dist/src/app/charts/styling/svgStyle.d.ts +76 -0
- package/dist/src/app/charts/styling/svgStyle.js +84 -0
- package/dist/src/app/charts/styling/svgStyle.js.map +1 -0
- package/dist/src/app/charts/subscriptions/subscription.test.d.ts +1 -0
- package/dist/src/app/charts/subscriptions/subscription.test.js +395 -0
- package/dist/src/app/charts/subscriptions/subscription.test.js.map +1 -0
- package/dist/src/app/charts/subscriptions/subscriptions.d.ts +100 -0
- package/dist/src/app/charts/subscriptions/subscriptions.js +449 -0
- package/dist/src/app/charts/subscriptions/subscriptions.js.map +1 -0
- package/dist/src/app/charts/tooltips/BarPlotTooltipContent.d.ts +90 -0
- package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js +302 -0
- package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js.map +1 -0
- package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.d.ts +100 -0
- package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js +190 -0
- package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js.map +1 -0
- package/dist/src/app/charts/{RasterPlotTooltipContent.js → tooltips/RasterPlotTooltipContent.js} +40 -44
- package/dist/src/app/charts/tooltips/RasterPlotTooltipContent.js.map +1 -0
- package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js +154 -0
- package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js.map +1 -0
- package/dist/src/app/charts/{Tooltip.d.ts → tooltips/Tooltip.d.ts} +4 -2
- package/dist/src/app/charts/{Tooltip.js → tooltips/Tooltip.js} +23 -28
- package/dist/src/app/charts/tooltips/Tooltip.js.map +1 -0
- package/dist/src/app/charts/{tooltipUtils.d.ts → tooltips/tooltipUtils.d.ts} +11 -6
- package/dist/src/app/charts/{tooltipUtils.js → tooltips/tooltipUtils.js} +33 -17
- package/dist/src/app/charts/tooltips/tooltipUtils.js.map +1 -0
- package/dist/src/app/charts/{Tracker.d.ts → trackers/Tracker.d.ts} +6 -5
- package/dist/src/app/charts/trackers/Tracker.js +60 -0
- package/dist/src/app/charts/trackers/Tracker.js.map +1 -0
- package/dist/src/app/charts/{trackerUtils.d.ts → trackers/trackerUtils.d.ts} +13 -8
- package/dist/src/app/charts/trackers/trackerUtils.js +359 -0
- package/dist/src/app/charts/trackers/trackerUtils.js.map +1 -0
- package/dist/src/app/charts/utils.d.ts +22 -32
- package/dist/src/app/charts/utils.js +36 -37
- package/dist/src/app/charts/utils.js.map +1 -1
- package/dist/src/index.d.ts +48 -15
- package/dist/src/index.js +71 -15
- package/dist/src/index.js.map +1 -1
- package/package.json +30 -20
- package/src/app/charts/Chart.tsx +334 -0
- package/src/app/charts/axes/AxesState.test.ts +34 -0
- package/src/app/charts/axes/AxesState.ts +112 -0
- package/src/app/charts/axes/AxisInterval.test.ts +143 -0
- package/src/app/charts/axes/AxisInterval.ts +139 -0
- package/src/app/charts/axes/BaseAxisRange.ts +113 -0
- package/src/app/charts/axes/ContinuousAxis.tsx +192 -0
- package/src/app/charts/axes/ContinuousAxisRange.test.ts +55 -0
- package/src/app/charts/axes/ContinuousAxisRange.ts +96 -0
- package/src/app/charts/axes/OrdinalAxis.tsx +223 -0
- package/src/app/charts/axes/OrdinalAxisRange.test.ts +55 -0
- package/src/app/charts/axes/OrdinalAxisRange.ts +112 -0
- package/src/app/charts/axes/axes.ts +1569 -0
- package/src/app/charts/d3types.ts +16 -0
- package/src/app/charts/filters/regexFilter.test.ts +13 -0
- package/src/app/charts/filters/regexFilter.ts +17 -0
- package/src/app/charts/hooks/useAxes.tsx +341 -0
- package/src/app/charts/hooks/useChart.tsx +159 -0
- package/src/app/charts/hooks/useDataObservable.tsx +175 -0
- package/src/app/charts/hooks/useInitialData.tsx +65 -0
- package/src/app/charts/hooks/useMouse.tsx +125 -0
- package/src/app/charts/hooks/usePlotDimensions.tsx +120 -0
- package/src/app/charts/hooks/useTooltip.tsx +112 -0
- package/src/app/charts/observables/ChartData.ts +31 -0
- package/src/app/charts/observables/iterates.test.ts +201 -0
- package/src/app/charts/observables/iterates.ts +203 -0
- package/src/app/charts/observables/ordinals.test.ts +135 -0
- package/src/app/charts/observables/ordinals.ts +248 -0
- package/src/app/charts/plots/BarPlot.tsx +1088 -0
- package/src/app/charts/plots/PoincarePlot.tsx +832 -0
- package/src/app/charts/plots/RasterPlot.tsx +676 -0
- package/src/app/charts/plots/ScatterPlot.tsx +653 -0
- package/src/app/charts/plots/plot.ts +75 -0
- package/src/app/charts/series/baseSeries.ts +52 -0
- package/src/app/charts/series/datumSeries.test.ts +60 -0
- package/src/app/charts/series/iterateSeries.ts +56 -0
- package/src/app/charts/series/ordinalSeries.ts +164 -0
- package/src/app/charts/series/timeSeries.ts +40 -0
- package/src/app/charts/series/timeSeriesChartData.ts +68 -0
- package/src/app/charts/styling/barPlotStyle.ts +126 -0
- package/src/app/charts/styling/margins.test.ts +22 -0
- package/src/app/charts/styling/margins.ts +58 -0
- package/src/app/charts/styling/svgStyle.ts +118 -0
- package/src/app/charts/subscriptions/subscription.test.ts +499 -0
- package/src/app/charts/subscriptions/subscriptions.ts +635 -0
- package/src/app/charts/tooltips/BarPlotTooltipContent.tsx +440 -0
- package/src/app/charts/tooltips/PoincarePlotTooltipContent.tsx +352 -0
- package/src/app/charts/tooltips/RasterPlotTooltipContent.tsx +274 -0
- package/src/app/charts/tooltips/ScatterPlotTooltipContent.tsx +319 -0
- package/src/app/charts/tooltips/Tooltip.tsx +148 -0
- package/src/app/charts/tooltips/tooltipUtils.ts +216 -0
- package/src/app/charts/trackers/Tracker.tsx +129 -0
- package/src/app/charts/trackers/trackerUtils.ts +494 -0
- package/src/app/charts/utils.ts +109 -0
- package/dist/src/app/charts/CategoryAxis.d.ts +0 -20
- package/dist/src/app/charts/CategoryAxis.js +0 -112
- package/dist/src/app/charts/CategoryAxis.js.map +0 -1
- package/dist/src/app/charts/ContinuousAxis.d.ts +0 -16
- package/dist/src/app/charts/ContinuousAxis.js +0 -186
- package/dist/src/app/charts/ContinuousAxis.js.map +0 -1
- package/dist/src/app/charts/RasterPlot.js.map +0 -1
- package/dist/src/app/charts/RasterPlotTooltipContent.js.map +0 -1
- package/dist/src/app/charts/ScatterPlot.js +0 -351
- package/dist/src/app/charts/ScatterPlot.js.map +0 -1
- package/dist/src/app/charts/ScatterPlotTooltipContent.js +0 -163
- package/dist/src/app/charts/ScatterPlotTooltipContent.js.map +0 -1
- package/dist/src/app/charts/Tooltip.js.map +0 -1
- package/dist/src/app/charts/Tracker.js +0 -65
- package/dist/src/app/charts/Tracker.js.map +0 -1
- package/dist/src/app/charts/axes.d.ts +0 -132
- package/dist/src/app/charts/axes.js +0 -265
- package/dist/src/app/charts/axes.js.map +0 -1
- package/dist/src/app/charts/chartData.js +0 -32
- package/dist/src/app/charts/chartData.js.map +0 -1
- package/dist/src/app/charts/continuousAxisRangeFor.d.ts +0 -20
- package/dist/src/app/charts/continuousAxisRangeFor.js +0 -68
- package/dist/src/app/charts/continuousAxisRangeFor.js.map +0 -1
- package/dist/src/app/charts/datumSeries.d.ts +0 -59
- package/dist/src/app/charts/datumSeries.js +0 -55
- package/dist/src/app/charts/datumSeries.js.map +0 -1
- package/dist/src/app/charts/datumSeries.test.js +0 -50
- package/dist/src/app/charts/datumSeries.test.js.map +0 -1
- package/dist/src/app/charts/hooks/AxesState.d.ts +0 -37
- package/dist/src/app/charts/hooks/AxesState.js +0 -44
- package/dist/src/app/charts/hooks/AxesState.js.map +0 -1
- package/dist/src/app/charts/margins.js.map +0 -1
- package/dist/src/app/charts/margins.test.js +0 -14
- package/dist/src/app/charts/margins.test.js.map +0 -1
- package/dist/src/app/charts/plot.js.map +0 -1
- package/dist/src/app/charts/regexFilter.d.ts +0 -9
- package/dist/src/app/charts/regexFilter.js +0 -17
- package/dist/src/app/charts/regexFilter.js.map +0 -1
- package/dist/src/app/charts/regexFilter.test.js +0 -11
- package/dist/src/app/charts/regexFilter.test.js.map +0 -1
- package/dist/src/app/charts/subscriptions.d.ts +0 -43
- package/dist/src/app/charts/subscriptions.js +0 -213
- package/dist/src/app/charts/subscriptions.js.map +0 -1
- package/dist/src/app/charts/svgStyle.d.ts +0 -27
- package/dist/src/app/charts/svgStyle.js +0 -32
- package/dist/src/app/charts/svgStyle.js.map +0 -1
- package/dist/src/app/charts/timeRange.test.js +0 -54
- package/dist/src/app/charts/timeRange.test.js.map +0 -1
- package/dist/src/app/charts/tooltipUtils.js.map +0 -1
- package/dist/src/app/charts/trackerUtils.js +0 -130
- package/dist/src/app/charts/trackerUtils.js.map +0 -1
- /package/dist/src/app/charts/{datumSeries.test.d.ts → axes/AxesState.test.d.ts} +0 -0
- /package/dist/src/app/charts/{margins.test.d.ts → axes/AxisInterval.test.d.ts} +0 -0
- /package/dist/src/app/charts/{regexFilter.test.d.ts → axes/ContinuousAxisRange.test.d.ts} +0 -0
- /package/dist/src/app/charts/{timeRange.test.d.ts → axes/OrdinalAxisRange.test.d.ts} +0 -0
- /package/dist/src/app/charts/{RasterPlotTooltipContent.d.ts → tooltips/RasterPlotTooltipContent.d.ts} +0 -0
- /package/dist/src/app/charts/{ScatterPlotTooltipContent.d.ts → tooltips/ScatterPlotTooltipContent.d.ts} +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {scan} from 'rxjs/operators';
|
|
2
|
+
import {Observable, range} from 'rxjs';
|
|
3
|
+
import {initialTimeSeriesChartData, TimeSeriesChartData} from "../series/timeSeriesChartData";
|
|
4
|
+
import {Datum, datumOf, TimeSeries} from "../series/timeSeries";
|
|
5
|
+
import {seriesFrom} from "../series/baseSeries";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Higher-order function that forms a closure on the tent-map parameter, mu,
|
|
9
|
+
* and returns a tent-map function that accepts time and an iterate value. The
|
|
10
|
+
* time is only used for chart information, and not in the calculation of the
|
|
11
|
+
* next iterate.
|
|
12
|
+
* <pre>f[n+1](x) = mu * min(f[n](x), 1 - f[n](x))</pre>
|
|
13
|
+
* @param mu The "slope" of the tent function
|
|
14
|
+
* @return A datum, (t, f[n+1](x)) holding the informational time, and the
|
|
15
|
+
* value of the next iterate
|
|
16
|
+
*/
|
|
17
|
+
function tentMapFn(mu: number): (time: number, xn: number) => Datum {
|
|
18
|
+
const cleanMu = Math.max(0, Math.min(mu, 2))
|
|
19
|
+
|
|
20
|
+
// the time is just the data collection time and does not factor int
|
|
21
|
+
// the tent map calculation.
|
|
22
|
+
return (time: number, xn: number): Datum => {
|
|
23
|
+
const xn1 = cleanMu * Math.min(xn, 1 - xn)
|
|
24
|
+
return datumOf(time, xn1)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Higher-order function that forms a closure on the update-period of the incoming data.
|
|
30
|
+
* This function returns an accumulator function that uses the previous iterate (time-series
|
|
31
|
+
* chart-data) to calculate the next iterate (time-series chart-data).
|
|
32
|
+
* @param updatePeriod The update period, in milliseconds, forming the processing
|
|
33
|
+
* windows of the graph
|
|
34
|
+
* @return A function returns an accumulator function that uses the previous iterate (time-series
|
|
35
|
+
* chart-data) to calculate the next iterate (time-series chart-data).
|
|
36
|
+
*/
|
|
37
|
+
function accumulateTentDataAt(updatePeriod: number):
|
|
38
|
+
(previous: TimeSeriesChartData, iterateNum: number, tentMap: (time: number, xn: number) => Datum) => TimeSeriesChartData
|
|
39
|
+
{
|
|
40
|
+
/**
|
|
41
|
+
* Calculates the next iterate, given the previous iterate, by applying the
|
|
42
|
+
* specified `tentMap` function
|
|
43
|
+
* @param previous The previous iterate
|
|
44
|
+
* @param iterateNum The iterate
|
|
45
|
+
* @param tentMap The function to calculate the tent-map
|
|
46
|
+
* @return The next iterate
|
|
47
|
+
*/
|
|
48
|
+
return (
|
|
49
|
+
previous: TimeSeriesChartData,
|
|
50
|
+
iterateNum: number,
|
|
51
|
+
tentMap: (time: number, xn: number) => Datum
|
|
52
|
+
): TimeSeriesChartData => {
|
|
53
|
+
// make a copy of the current max times, which we'll update with new points
|
|
54
|
+
const maxTimes = new Map(previous.maxTimes.entries())
|
|
55
|
+
previous.newPoints.forEach((datum, name) => {
|
|
56
|
+
maxTimes.set(name, (datum[datum.length - 1].time + updatePeriod))
|
|
57
|
+
})
|
|
58
|
+
// deep copy of the previous data points, and calculate the next point
|
|
59
|
+
const newPoints = new Map(Array.from(previous.newPoints.entries())
|
|
60
|
+
.map(([name, data]) => [name, data.slice()]))
|
|
61
|
+
newPoints.forEach((data, _) => {
|
|
62
|
+
const lastDatum = data[data.length - 1]
|
|
63
|
+
const newDatum = tentMap(lastDatum.time + updatePeriod, lastDatum.value)
|
|
64
|
+
data.shift()
|
|
65
|
+
data.push(newDatum)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
seriesNames: new Set<string>(previous.newPoints.keys()),
|
|
70
|
+
maxTime: previous.maxTime + updatePeriod,
|
|
71
|
+
maxTimes,
|
|
72
|
+
newPoints,
|
|
73
|
+
currentTime: (previous.currentTime || 0) + updatePeriod
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Calculates and returns a time-series of iterates of the tent-map function.
|
|
80
|
+
* @param numPoints The number of iterates to calculate
|
|
81
|
+
* @param mu The slope of the tent-map function
|
|
82
|
+
* @param series The initial series
|
|
83
|
+
* @param updatePeriod The update period (chart-window processing)
|
|
84
|
+
* @return An observable of time-series chart-data holding the iterates
|
|
85
|
+
*/
|
|
86
|
+
function tentMapTimeSeriesObservable(
|
|
87
|
+
numPoints: number = 10,
|
|
88
|
+
mu: number,
|
|
89
|
+
series: Array<TimeSeries>,
|
|
90
|
+
updatePeriod: number = 25
|
|
91
|
+
): Observable<TimeSeriesChartData> {
|
|
92
|
+
const maxTime = series
|
|
93
|
+
.map(srs => srs.last().map(datum => datum.time).getOrElse(0))
|
|
94
|
+
.reduce((tMax, tCurr) => (tCurr > tMax) ? tCurr : tMax, -Infinity)
|
|
95
|
+
const initialData = initialTimeSeriesChartData(series, maxTime)
|
|
96
|
+
const tentMap = tentMapFn(mu)
|
|
97
|
+
const accumulateFn = accumulateTentDataAt(updatePeriod);
|
|
98
|
+
return range(series.length, numPoints).pipe(
|
|
99
|
+
scan((prev, sequence) => accumulateFn(prev, sequence + 1, tentMap), initialData)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
describe('when calculating tent-map iterates', () => {
|
|
104
|
+
|
|
105
|
+
const expected: Array<TimeSeriesChartData> = [
|
|
106
|
+
{
|
|
107
|
+
seriesNames: new Set<string>(["test1"]),
|
|
108
|
+
maxTime: 26,
|
|
109
|
+
maxTimes: new Map([["test1", 26]]),
|
|
110
|
+
newPoints: new Map([["test1", [datumOf(26, 0.578)]]]),
|
|
111
|
+
currentTime: 26
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
seriesNames: new Set<string>(["test1"]),
|
|
115
|
+
maxTime: 51,
|
|
116
|
+
maxTimes: new Map([["test1", 51]]),
|
|
117
|
+
newPoints: new Map([["test1", [datumOf(51, 0.7174)]]]),
|
|
118
|
+
currentTime: 51
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
seriesNames: new Set<string>(["test1"]),
|
|
122
|
+
maxTime: 76,
|
|
123
|
+
maxTimes: new Map([["test1", 76]]),
|
|
124
|
+
newPoints: new Map([["test1", [datumOf(76, 0.48042)]]]),
|
|
125
|
+
currentTime: 76
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
seriesNames: new Set<string>(["test1"]),
|
|
129
|
+
maxTime: 101,
|
|
130
|
+
maxTimes: new Map([["test1", 101]]),
|
|
131
|
+
newPoints: new Map([["test1", [datumOf(101, 0.816714)]]]),
|
|
132
|
+
currentTime: 101
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
seriesNames: new Set<string>(["test1"]),
|
|
136
|
+
maxTime: 126,
|
|
137
|
+
maxTimes: new Map([["test1", 126]]),
|
|
138
|
+
newPoints: new Map([["test1", [datumOf(126, 0.3115862)]]]),
|
|
139
|
+
currentTime: 126
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
seriesNames: new Set<string>(["test1"]),
|
|
143
|
+
maxTime: 151,
|
|
144
|
+
maxTimes: new Map([["test1", 151]]),
|
|
145
|
+
newPoints: new Map([["test1", [datumOf(151, 0.52969654)]]]),
|
|
146
|
+
currentTime: 151
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
seriesNames: new Set<string>(["test1"]),
|
|
150
|
+
maxTime: 176,
|
|
151
|
+
maxTimes: new Map([["test1", 176]]),
|
|
152
|
+
newPoints: new Map([["test1", [datumOf(176, 0.799515882)]]]),
|
|
153
|
+
currentTime: 176
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
seriesNames: new Set<string>(["test1"]),
|
|
157
|
+
maxTime: 201,
|
|
158
|
+
maxTimes: new Map([["test1", 201]]),
|
|
159
|
+
newPoints: new Map([["test1", [datumOf(201, 0.3408230006)]]]),
|
|
160
|
+
currentTime: 201
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
seriesNames: new Set<string>(["test1"]),
|
|
164
|
+
maxTime: 226,
|
|
165
|
+
maxTimes: new Map([["test1", 226]]),
|
|
166
|
+
newPoints: new Map([["test1", [datumOf(226, 0.5793991)]]]),
|
|
167
|
+
currentTime: 226
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
seriesNames: new Set<string>(["test1"]),
|
|
171
|
+
maxTime: 251,
|
|
172
|
+
maxTimes: new Map([["test1", 251]]),
|
|
173
|
+
newPoints: new Map([["test1", [datumOf(251, 0.7150215282659962)]]]),
|
|
174
|
+
currentTime: 251
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
function assertChartDataEqual(expected: TimeSeriesChartData, actual: TimeSeriesChartData): void {
|
|
179
|
+
expect(actual.maxTime).toEqual(expected.maxTime);
|
|
180
|
+
expect(actual.maxTimes).toEqual(expected.maxTimes);
|
|
181
|
+
Array.from(actual.newPoints.entries())
|
|
182
|
+
.forEach(([name, data]: [string, Array<Datum>], index: number) => {
|
|
183
|
+
data.forEach(actualDatum => {
|
|
184
|
+
const expectedDatum: Datum = expected.newPoints.get(name)![index]
|
|
185
|
+
expect(actualDatum.time).toEqual(expectedDatum.time)
|
|
186
|
+
expect(actualDatum.value).toBeCloseTo(expectedDatum.value, 6)
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
test('should be able to calculate the tent-map iterates', done => {
|
|
192
|
+
let results: Array<TimeSeriesChartData> = []
|
|
193
|
+
const initialData: Array<TimeSeries> = [seriesFrom("test1", [datumOf(1, 0.66)])]
|
|
194
|
+
tentMapTimeSeriesObservable(10, 1.7, initialData).subscribe(chartData => results.push(chartData))
|
|
195
|
+
done()
|
|
196
|
+
expect(results).toHaveLength(10)
|
|
197
|
+
results.forEach((result, index) => {
|
|
198
|
+
assertChartDataEqual(expected[index], result)
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
})
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for plotting function iterates. For example suppose that f[1](x) = f(x), f[2](x) = f(f(x)),
|
|
3
|
+
* f[3](x) = f(f(f(x))), and f[m](x) = f(f(f....(x))), where the function is applied m times. Given this,
|
|
4
|
+
* then an iterate (Poincare) plot shows points (f[m](x), f[m+1](x)), which is a 1-iterate. Plots of
|
|
5
|
+
* points (f[m](x), f[m+n](x)) are n-iterates.
|
|
6
|
+
*
|
|
7
|
+
* 1. Convert series to chart data observable in the usual way
|
|
8
|
+
* 2. Accepts that chart-data observable and converts that observable to an iterate-chart-data observable
|
|
9
|
+
*/
|
|
10
|
+
import {Observable} from "rxjs";
|
|
11
|
+
import {TimeSeriesChartData} from "../series/timeSeriesChartData";
|
|
12
|
+
import {filter, map, scan} from "rxjs/operators";
|
|
13
|
+
import {Datum, emptyDatum} from "../series/timeSeries";
|
|
14
|
+
import {emptyIterateDatum, IterateDatum, iterateDatumOf, nonEmptyIterateDatum} from "../series/iterateSeries";
|
|
15
|
+
import {ChartData, copyChartData, defaultChartData} from "./ChartData";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export interface IterateChartData extends ChartData {
|
|
19
|
+
/**
|
|
20
|
+
* The min values for (time, iterate n, and iterate n+1) for the data in the newPoints map
|
|
21
|
+
*/
|
|
22
|
+
minIterate: IterateDatum
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The max values for (time, iterate n, and iterate n+1) for the data in the newPoints map
|
|
26
|
+
*/
|
|
27
|
+
maxIterate: IterateDatum
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Holds the association of the series name to the current min time for that series
|
|
31
|
+
*/
|
|
32
|
+
minIterates: Map<string, IterateDatum>
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Holds the association of the series name to the current max time for that series
|
|
36
|
+
*/
|
|
37
|
+
maxIterates: Map<string, IterateDatum>
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Map holding the name of the series (the time-series identifier) and the associated
|
|
41
|
+
* data points for that time-series (`map(series_name -> array(datum))`)
|
|
42
|
+
*/
|
|
43
|
+
newPoints: Map<string, Array<IterateDatum>>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const emptyIterateData = (): IterateChartData => ({
|
|
47
|
+
...defaultChartData(),
|
|
48
|
+
minIterate: emptyIterateDatum,
|
|
49
|
+
maxIterate: emptyIterateDatum,
|
|
50
|
+
minIterates: new Map<string, IterateDatum>(),
|
|
51
|
+
maxIterates: new Map<string, IterateDatum>(),
|
|
52
|
+
newPoints: new Map<string, Array<IterateDatum>>()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Makes a deep copy of the iterate chart data
|
|
57
|
+
* @param data The iterate chart data to copy
|
|
58
|
+
*/
|
|
59
|
+
export const copyIterateDataFrom = (data: IterateChartData): IterateChartData => ({
|
|
60
|
+
...copyChartData(data),
|
|
61
|
+
minIterate: data.minIterate,
|
|
62
|
+
maxIterate: data.maxIterate,
|
|
63
|
+
minIterates: new Map<string, IterateDatum>(data.minIterates),
|
|
64
|
+
maxIterates: new Map<string, IterateDatum>(data.maxIterates),
|
|
65
|
+
newPoints: new Map<string, Array<IterateDatum>>(Array.from(data.newPoints.entries()).map(([name, points]) => [name, points.slice()])),
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
type Accumulator = {
|
|
69
|
+
n: number
|
|
70
|
+
previous: Map<string, Array<Datum>>
|
|
71
|
+
accumulated: IterateChartData
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const initialAccumulate = (n: number): Accumulator => ({n, previous: new Map(), accumulated: emptyIterateData()})
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Accepts a {@link TimeSeriesChartData} observable and converts it to an observable of {@link IterateChartData}
|
|
78
|
+
* for the specified n-iterate. suppose that `f[0](x) = x`, `f[1](x) = f(x)`, `f[2](x) = f(f(x))`,
|
|
79
|
+
* `f[3](x) = f(f(f(x)))`, and `f[m](x) = f(f(f....(x)))`, where the function is applied `m` times. Given this,
|
|
80
|
+
* then an iterate (Poincare) plot shows points `(f[m](x), f[m+1](x))`, which is a 1-iterate. Plots of
|
|
81
|
+
* points `(f[m](x), f[m+n](x))` are n-iterates.
|
|
82
|
+
* @param dataObservable The observable over {@link TimeSeriesChartData}
|
|
83
|
+
* @param [n=1] The iterate distance
|
|
84
|
+
* @return An over {@link IterateChartData} holding the n-iterate for the incoming chart data
|
|
85
|
+
*/
|
|
86
|
+
export function iteratesObservable(dataObservable: Observable<TimeSeriesChartData>, n: number = 1): Observable<IterateChartData> {
|
|
87
|
+
return dataObservable
|
|
88
|
+
.pipe(
|
|
89
|
+
// calculate the iterates for each series in the chart data
|
|
90
|
+
scan(({n, previous, accumulated}: Accumulator, current: TimeSeriesChartData) => {
|
|
91
|
+
// make a deep copy of the accumulated data (because the accumulated data object
|
|
92
|
+
// holds references to maps)
|
|
93
|
+
const accum = copyIterateDataFrom(accumulated)
|
|
94
|
+
|
|
95
|
+
// for each series, add the new points to the accumulated data
|
|
96
|
+
Array
|
|
97
|
+
.from(current.newPoints.entries())
|
|
98
|
+
.forEach(([name, series]) => {
|
|
99
|
+
// grab the points from the previous incoming data and add the new
|
|
100
|
+
// data to its end (when the updated data didn't yet exist, add it
|
|
101
|
+
// to the map holding the previous series)
|
|
102
|
+
const updated = (previous.get(name) || [])
|
|
103
|
+
if (updated.length === 0) {
|
|
104
|
+
previous.set(name, updated)
|
|
105
|
+
}
|
|
106
|
+
updated.push(...series)
|
|
107
|
+
|
|
108
|
+
// we may have multiple new data points for this series, so we may need to
|
|
109
|
+
// calculate multiple iterates
|
|
110
|
+
while (updated.length > n) {
|
|
111
|
+
// grab the start and end of the n-iterate interval
|
|
112
|
+
const last = updated[n]
|
|
113
|
+
const first = updated.shift() || emptyDatum()
|
|
114
|
+
|
|
115
|
+
// set the updated new points for the series for the next
|
|
116
|
+
// iteration of the while-loop
|
|
117
|
+
previous.set(name, updated)
|
|
118
|
+
|
|
119
|
+
// create the new iterate
|
|
120
|
+
const iterate: IterateDatum = iterateDatumOf(first.time, first.value, last.value);
|
|
121
|
+
|
|
122
|
+
// update the min, max values for all the series
|
|
123
|
+
accum.minIterate = minIterateFor(iterate, accum.minIterate)
|
|
124
|
+
accum.maxIterate = maxIterateFor(iterate, accum.maxIterate)
|
|
125
|
+
|
|
126
|
+
// update the min, max values for the current series
|
|
127
|
+
accum.minIterates.set(name, minIterateFor(iterate, accum.minIterates.get(name)))
|
|
128
|
+
accum.maxIterates.set(name, maxIterateFor(iterate, accum.maxIterates.get(name)))
|
|
129
|
+
|
|
130
|
+
// add the newly calculated iterate, and then trim from the
|
|
131
|
+
// head of the array to a size n. For the iterates, we only need
|
|
132
|
+
// to keep enough to create points (x(j), x(j+n))
|
|
133
|
+
const updatedPoints = accum.newPoints.get(name) || []
|
|
134
|
+
if (updatedPoints.length === 0) {
|
|
135
|
+
accum.newPoints.set(name, updatedPoints)
|
|
136
|
+
}
|
|
137
|
+
updatedPoints.push(iterate)
|
|
138
|
+
if (updatedPoints.length > series.length) {
|
|
139
|
+
updatedPoints.shift()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
return {n, previous, accumulated: accum}
|
|
144
|
+
}, initialAccumulate(n)),
|
|
145
|
+
|
|
146
|
+
// remove new points from the map that are empty
|
|
147
|
+
filter(accum => !isNaN(accum.accumulated.minIterate.iterateN) && !isNaN(accum.accumulated.minIterate.iterateN_1)),
|
|
148
|
+
map(accum => removeEmptyNewPoints(accum)),
|
|
149
|
+
map(accum => accum.accumulated === undefined ? emptyIterateData() : accum.accumulated)
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Calculates and returns the minimum values for the specified iterate and the current minimum
|
|
155
|
+
* @param iterate The iterate to compare against the minimum
|
|
156
|
+
* @param minIterate The minimum values for the iterate. Generally, this will be the accumulated
|
|
157
|
+
* values
|
|
158
|
+
* @return the minimum values for the specified iterate and the current minimum
|
|
159
|
+
*/
|
|
160
|
+
function minIterateFor(iterate: IterateDatum, minIterate: IterateDatum = emptyIterateDatum): IterateDatum {
|
|
161
|
+
const minN = isNaN(minIterate.iterateN) ? iterate.iterateN : Math.min(iterate.iterateN, minIterate.iterateN)
|
|
162
|
+
const minN_1 = isNaN(minIterate.iterateN_1) ? iterate.iterateN_1 : Math.min(iterate.iterateN_1, minIterate.iterateN_1)
|
|
163
|
+
const minTime = (iterate.iterateN <= minN || iterate.iterateN_1 <= minN_1) ? iterate.time : minIterate.time
|
|
164
|
+
return {
|
|
165
|
+
time: minTime,
|
|
166
|
+
iterateN: minN,
|
|
167
|
+
iterateN_1: minN_1
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Calculates and returns the maximum values for the specified iterate and the current maximum
|
|
173
|
+
* @param iterate The iterate to compare against the maximum
|
|
174
|
+
* @param maxIterate The maximum values for the iterate. Generally, this will be the accumulated
|
|
175
|
+
* values
|
|
176
|
+
* @return the maximum values for the specified iterate and the current maximum
|
|
177
|
+
*/
|
|
178
|
+
function maxIterateFor(iterate: IterateDatum, maxIterate: IterateDatum = emptyIterateDatum): IterateDatum {
|
|
179
|
+
const maxN = isNaN(maxIterate.iterateN) ? iterate.iterateN : Math.max(iterate.iterateN, maxIterate.iterateN)
|
|
180
|
+
const maxN_1 = isNaN(maxIterate.iterateN_1) ? iterate.iterateN_1 : Math.max(iterate.iterateN_1, maxIterate.iterateN_1)
|
|
181
|
+
const maxTime = (iterate.iterateN >= maxN || iterate.iterateN_1 >= maxN_1) ? iterate.time : maxIterate.time
|
|
182
|
+
return {
|
|
183
|
+
time: maxTime,
|
|
184
|
+
iterateN: maxN,
|
|
185
|
+
iterateN_1: maxN_1
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function removeEmptyNewPoints(accum: Accumulator): Accumulator {
|
|
190
|
+
const newPoints = new Map(
|
|
191
|
+
Array
|
|
192
|
+
.from(accum.accumulated.newPoints.entries())
|
|
193
|
+
.map(([name, points]) => [name, points.filter(point => nonEmptyIterateDatum(point))])
|
|
194
|
+
)
|
|
195
|
+
return {
|
|
196
|
+
n: accum.n,
|
|
197
|
+
previous: accum.previous,
|
|
198
|
+
accumulated: {
|
|
199
|
+
...accum.accumulated,
|
|
200
|
+
newPoints
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {TimeSeriesChartData} from "../series/timeSeriesChartData";
|
|
2
|
+
import {Datum, datumOf, TimeSeries} from "../series/timeSeries";
|
|
3
|
+
import {seriesFrom} from "../series/baseSeries";
|
|
4
|
+
import {Observable, range} from "rxjs";
|
|
5
|
+
import {map} from "rxjs/operators";
|
|
6
|
+
import {OrdinalChartData, ordinalsObservable} from "./ordinals";
|
|
7
|
+
|
|
8
|
+
export function sinFn(x: number, period: number): number {
|
|
9
|
+
return Math.sin(2 * Math.PI * x / period)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('when generating ordinal series', () => {
|
|
13
|
+
const NUM_POINTS = 10
|
|
14
|
+
const UPDATE_PERIOD = 25
|
|
15
|
+
const seriesData: Array<[string, number]> = [["test1", sinFn(0, 250)], ["test2", sinFn(1, 251)], ["test3", sinFn(2, 252)]]
|
|
16
|
+
|
|
17
|
+
const initialData: Array<TimeSeries> = seriesData
|
|
18
|
+
.map(([name, value], index) => seriesFrom(name, [datumOf(index, value)]))
|
|
19
|
+
|
|
20
|
+
test('should be able to generate ordinals', done => {
|
|
21
|
+
let results: Array<OrdinalChartData> = []
|
|
22
|
+
ordinalsObservable(
|
|
23
|
+
sineDataObservable(initialData, NUM_POINTS, UPDATE_PERIOD)
|
|
24
|
+
).subscribe(chartData => results.push(chartData))
|
|
25
|
+
|
|
26
|
+
// blocks until done is called
|
|
27
|
+
done()
|
|
28
|
+
|
|
29
|
+
expect(results).toHaveLength(NUM_POINTS)
|
|
30
|
+
|
|
31
|
+
results.forEach((result, timeIndex) => {
|
|
32
|
+
Array.from(result.newPoints.entries()).forEach(([seriesName, ordinalDatum], index) => {
|
|
33
|
+
expect(seriesName).toEqual(seriesData[index][0])
|
|
34
|
+
|
|
35
|
+
// check the time for the datum (only one new-point datum)
|
|
36
|
+
expect(ordinalDatum).toBeDefined()
|
|
37
|
+
expect(ordinalDatum.length).toBe(1)
|
|
38
|
+
expect(ordinalDatum[0].time).toEqual(index+ timeIndex * UPDATE_PERIOD)
|
|
39
|
+
|
|
40
|
+
// should be bounded (data is bounded)
|
|
41
|
+
expect(ordinalDatum[0].value).toBeLessThanOrEqual(1)
|
|
42
|
+
expect(ordinalDatum[0].value).toBeGreaterThanOrEqual(-1)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// the min time should be 1 and the max time should be (3 + timeIndex + updatePeriod)
|
|
46
|
+
expect(result.stats.minDatum.time.time).toBe(0)
|
|
47
|
+
expect(result.stats.maxDatum.time.time).toBe(2 + timeIndex * UPDATE_PERIOD)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates random data
|
|
56
|
+
* @param sequenceTime The current time
|
|
57
|
+
* @param maxTime The number of points in the series
|
|
58
|
+
* @param series The list of series names (identifiers) to update
|
|
59
|
+
* @param seriesMaxTimes The maximum time for each series
|
|
60
|
+
* @return The random chart data
|
|
61
|
+
*/
|
|
62
|
+
function sineData(
|
|
63
|
+
sequenceTime: number,
|
|
64
|
+
maxTime: number,
|
|
65
|
+
series: Array<string>,
|
|
66
|
+
seriesMaxTimes: Map<string, number>
|
|
67
|
+
): TimeSeriesChartData {
|
|
68
|
+
const maxTimes = new Map(Array.from(
|
|
69
|
+
seriesMaxTimes.entries()).map(([name, maxTime]) => [name, maxTime + sequenceTime])
|
|
70
|
+
)
|
|
71
|
+
return {
|
|
72
|
+
seriesNames: new Set(series),
|
|
73
|
+
maxTime: sequenceTime,
|
|
74
|
+
maxTimes,
|
|
75
|
+
newPoints: new Map(series.map((name, index) => {
|
|
76
|
+
const time = sequenceTime + index
|
|
77
|
+
const value = sinFn(time, maxTime + index)
|
|
78
|
+
return [name, [{time, value}]]
|
|
79
|
+
}))
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Creates an empty chart data object with all the values set to 0
|
|
85
|
+
* @param seriesList The list of series names (identifiers) to update
|
|
86
|
+
* @param currentTime=0] The current time
|
|
87
|
+
* @return An empty chart data object
|
|
88
|
+
*/
|
|
89
|
+
function initialChartData(seriesList: Array<TimeSeries>, currentTime: number = 0): TimeSeriesChartData {
|
|
90
|
+
const maxTime = seriesList.reduce(
|
|
91
|
+
(tMax, series) => Math.max(tMax, series.last().map(datum => datum.time).getOrElse(-Infinity)),
|
|
92
|
+
-Infinity
|
|
93
|
+
)
|
|
94
|
+
return {
|
|
95
|
+
seriesNames: new Set(seriesList.map(series => series.name)),
|
|
96
|
+
maxTime,
|
|
97
|
+
maxTimes: new Map(seriesList.map(series => [series.name, series.last().map(datum => datum.time).getOrElse(0)])),
|
|
98
|
+
newPoints: new Map<string, Array<Datum>>(seriesList.map(series => [
|
|
99
|
+
series.name,
|
|
100
|
+
[{
|
|
101
|
+
time: series.last().map(datum => datum.time).getOrElse(0),
|
|
102
|
+
value: series.last().map(datum => datum.value).getOrElse(0)
|
|
103
|
+
}]
|
|
104
|
+
])),
|
|
105
|
+
currentTime: currentTime
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates random set of time-series data, essentially creating a random walk for each series
|
|
111
|
+
* @param series The number of time-series for which to generate data (i.e. one for each neuron)
|
|
112
|
+
* @param numPoints The number of points to generate
|
|
113
|
+
* @param [updatePeriod=25] The time-interval between the generation of subsequent data points
|
|
114
|
+
* @return An observable that produces data.
|
|
115
|
+
*/
|
|
116
|
+
function sineDataObservable(
|
|
117
|
+
series: Array<TimeSeries>,
|
|
118
|
+
numPoints: number = 10,
|
|
119
|
+
updatePeriod: number = 25,
|
|
120
|
+
): Observable<TimeSeriesChartData> {
|
|
121
|
+
const seriesNames = series.map(series => series.name)
|
|
122
|
+
const initialData = initialChartData(series)
|
|
123
|
+
return range(0, numPoints).pipe(
|
|
124
|
+
// convert the number sequence to a time
|
|
125
|
+
map(sequence => sequence * updatePeriod),
|
|
126
|
+
|
|
127
|
+
// create a new (time, value) for each series
|
|
128
|
+
map(time => {
|
|
129
|
+
if (time <= initialData.maxTime) {
|
|
130
|
+
return initialData
|
|
131
|
+
}
|
|
132
|
+
return sineData(time, numPoints * updatePeriod, seriesNames, initialData.maxTimes)
|
|
133
|
+
}),
|
|
134
|
+
)
|
|
135
|
+
}
|