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.
Files changed (271) hide show
  1. package/README.md +757 -342
  2. package/changes.md +11 -0
  3. package/dist/src/app/charts/Chart.d.ts +116 -87
  4. package/dist/src/app/charts/Chart.js +96 -101
  5. package/dist/src/app/charts/Chart.js.map +1 -1
  6. package/dist/src/app/charts/axes/AxesState.d.ts +64 -0
  7. package/dist/src/app/charts/axes/AxesState.js +97 -0
  8. package/dist/src/app/charts/axes/AxesState.js.map +1 -0
  9. package/dist/src/app/charts/axes/AxesState.test.js +30 -0
  10. package/dist/src/app/charts/axes/AxesState.test.js.map +1 -0
  11. package/dist/src/app/charts/axes/AxisInterval.d.ts +92 -0
  12. package/dist/src/app/charts/axes/AxisInterval.js +126 -0
  13. package/dist/src/app/charts/axes/AxisInterval.js.map +1 -0
  14. package/dist/src/app/charts/axes/AxisInterval.test.js +120 -0
  15. package/dist/src/app/charts/axes/AxisInterval.test.js.map +1 -0
  16. package/dist/src/app/charts/axes/BaseAxisRange.d.ts +83 -0
  17. package/dist/src/app/charts/axes/BaseAxisRange.js +58 -0
  18. package/dist/src/app/charts/axes/BaseAxisRange.js.map +1 -0
  19. package/dist/src/app/charts/axes/ContinuousAxis.d.ts +22 -0
  20. package/dist/src/app/charts/axes/ContinuousAxis.js +96 -0
  21. package/dist/src/app/charts/axes/ContinuousAxis.js.map +1 -0
  22. package/dist/src/app/charts/axes/ContinuousAxisRange.d.ts +59 -0
  23. package/dist/src/app/charts/axes/ContinuousAxisRange.js +84 -0
  24. package/dist/src/app/charts/axes/ContinuousAxisRange.js.map +1 -0
  25. package/dist/src/app/charts/axes/ContinuousAxisRange.test.js +47 -0
  26. package/dist/src/app/charts/axes/ContinuousAxisRange.test.js.map +1 -0
  27. package/dist/src/app/charts/axes/OrdinalAxis.d.ts +23 -0
  28. package/dist/src/app/charts/axes/OrdinalAxis.js +124 -0
  29. package/dist/src/app/charts/axes/OrdinalAxis.js.map +1 -0
  30. package/dist/src/app/charts/axes/OrdinalAxisRange.d.ts +69 -0
  31. package/dist/src/app/charts/axes/OrdinalAxisRange.js +100 -0
  32. package/dist/src/app/charts/axes/OrdinalAxisRange.js.map +1 -0
  33. package/dist/src/app/charts/axes/OrdinalAxisRange.test.js +48 -0
  34. package/dist/src/app/charts/axes/OrdinalAxisRange.test.js.map +1 -0
  35. package/dist/src/app/charts/axes/axes.d.ts +391 -0
  36. package/dist/src/app/charts/axes/axes.js +1046 -0
  37. package/dist/src/app/charts/axes/axes.js.map +1 -0
  38. package/dist/src/app/charts/d3types.d.ts +10 -10
  39. package/dist/src/app/charts/filters/regexFilter.d.ts +9 -0
  40. package/dist/src/app/charts/filters/regexFilter.js +18 -0
  41. package/dist/src/app/charts/filters/regexFilter.js.map +1 -0
  42. package/dist/src/app/charts/filters/regexFilter.test.d.ts +1 -0
  43. package/dist/src/app/charts/filters/regexFilter.test.js +11 -0
  44. package/dist/src/app/charts/filters/regexFilter.test.js.map +1 -0
  45. package/dist/src/app/charts/hooks/useAxes.d.ts +144 -0
  46. package/dist/src/app/charts/hooks/useAxes.js +187 -0
  47. package/dist/src/app/charts/hooks/useAxes.js.map +1 -0
  48. package/dist/src/app/charts/hooks/useChart.d.ts +30 -201
  49. package/dist/src/app/charts/hooks/useChart.js +33 -134
  50. package/dist/src/app/charts/hooks/useChart.js.map +1 -1
  51. package/dist/src/app/charts/hooks/useDataObservable.d.ts +74 -0
  52. package/dist/src/app/charts/hooks/useDataObservable.js +76 -0
  53. package/dist/src/app/charts/hooks/useDataObservable.js.map +1 -0
  54. package/dist/src/app/charts/hooks/useInitialData.d.ts +38 -0
  55. package/dist/src/app/charts/hooks/useInitialData.js +29 -0
  56. package/dist/src/app/charts/hooks/useInitialData.js.map +1 -0
  57. package/dist/src/app/charts/hooks/useMouse.d.ts +53 -0
  58. package/dist/src/app/charts/hooks/useMouse.js +65 -0
  59. package/dist/src/app/charts/hooks/useMouse.js.map +1 -0
  60. package/dist/src/app/charts/hooks/usePlotDimensions.d.ts +34 -0
  61. package/dist/src/app/charts/hooks/usePlotDimensions.js +73 -0
  62. package/dist/src/app/charts/hooks/usePlotDimensions.js.map +1 -0
  63. package/dist/src/app/charts/hooks/useTooltip.d.ts +64 -0
  64. package/dist/src/app/charts/hooks/useTooltip.js +52 -0
  65. package/dist/src/app/charts/hooks/useTooltip.js.map +1 -0
  66. package/dist/src/app/charts/observables/ChartData.d.ts +23 -0
  67. package/dist/src/app/charts/observables/ChartData.js +20 -0
  68. package/dist/src/app/charts/observables/ChartData.js.map +1 -0
  69. package/dist/src/app/charts/observables/iterates.d.ts +52 -0
  70. package/dist/src/app/charts/observables/iterates.js +121 -0
  71. package/dist/src/app/charts/observables/iterates.js.map +1 -0
  72. package/dist/src/app/charts/observables/iterates.test.d.ts +1 -0
  73. package/dist/src/app/charts/observables/iterates.test.js +180 -0
  74. package/dist/src/app/charts/observables/iterates.test.js.map +1 -0
  75. package/dist/src/app/charts/observables/ordinals.d.ts +75 -0
  76. package/dist/src/app/charts/observables/ordinals.js +141 -0
  77. package/dist/src/app/charts/observables/ordinals.js.map +1 -0
  78. package/dist/src/app/charts/observables/ordinals.test.d.ts +1 -0
  79. package/dist/src/app/charts/observables/ordinals.test.js +102 -0
  80. package/dist/src/app/charts/observables/ordinals.test.js.map +1 -0
  81. package/dist/src/app/charts/plots/BarPlot.d.ts +81 -0
  82. package/dist/src/app/charts/plots/BarPlot.js +557 -0
  83. package/dist/src/app/charts/plots/BarPlot.js.map +1 -0
  84. package/dist/src/app/charts/plots/PoincarePlot.d.ts +78 -0
  85. package/dist/src/app/charts/plots/PoincarePlot.js +504 -0
  86. package/dist/src/app/charts/plots/PoincarePlot.js.map +1 -0
  87. package/dist/src/app/charts/{RasterPlot.d.ts → plots/RasterPlot.d.ts} +1 -1
  88. package/dist/src/app/charts/{RasterPlot.js → plots/RasterPlot.js} +152 -133
  89. package/dist/src/app/charts/plots/RasterPlot.js.map +1 -0
  90. package/dist/src/app/charts/{ScatterPlot.d.ts → plots/ScatterPlot.d.ts} +10 -8
  91. package/dist/src/app/charts/plots/ScatterPlot.js +379 -0
  92. package/dist/src/app/charts/plots/ScatterPlot.js.map +1 -0
  93. package/dist/src/app/charts/{plot.d.ts → plots/plot.d.ts} +12 -14
  94. package/dist/src/app/charts/{plot.js → plots/plot.js} +19 -17
  95. package/dist/src/app/charts/plots/plot.js.map +1 -0
  96. package/dist/src/app/charts/series/baseSeries.d.ts +38 -0
  97. package/dist/src/app/charts/series/baseSeries.js +36 -0
  98. package/dist/src/app/charts/series/baseSeries.js.map +1 -0
  99. package/dist/src/app/charts/series/datumSeries.test.d.ts +1 -0
  100. package/dist/src/app/charts/series/datumSeries.test.js +50 -0
  101. package/dist/src/app/charts/series/datumSeries.test.js.map +1 -0
  102. package/dist/src/app/charts/series/iterateSeries.d.ts +42 -0
  103. package/dist/src/app/charts/series/iterateSeries.js +34 -0
  104. package/dist/src/app/charts/series/iterateSeries.js.map +1 -0
  105. package/dist/src/app/charts/series/ordinalSeries.d.ts +54 -0
  106. package/dist/src/app/charts/series/ordinalSeries.js +98 -0
  107. package/dist/src/app/charts/series/ordinalSeries.js.map +1 -0
  108. package/dist/src/app/charts/series/timeSeries.d.ts +30 -0
  109. package/dist/src/app/charts/series/timeSeries.js +19 -0
  110. package/dist/src/app/charts/series/timeSeries.js.map +1 -0
  111. package/dist/src/app/charts/{chartData.d.ts → series/timeSeriesChartData.d.ts} +11 -6
  112. package/dist/src/app/charts/series/timeSeriesChartData.js +32 -0
  113. package/dist/src/app/charts/series/timeSeriesChartData.js.map +1 -0
  114. package/dist/src/app/charts/styling/barPlotStyle.d.ts +41 -0
  115. package/dist/src/app/charts/styling/barPlotStyle.js +84 -0
  116. package/dist/src/app/charts/styling/barPlotStyle.js.map +1 -0
  117. package/dist/src/app/charts/{margins.d.ts → styling/margins.d.ts} +7 -5
  118. package/dist/src/app/charts/{margins.js → styling/margins.js} +19 -9
  119. package/dist/src/app/charts/styling/margins.js.map +1 -0
  120. package/dist/src/app/charts/styling/margins.test.d.ts +1 -0
  121. package/dist/src/app/charts/styling/margins.test.js +19 -0
  122. package/dist/src/app/charts/styling/margins.test.js.map +1 -0
  123. package/dist/src/app/charts/styling/svgStyle.d.ts +76 -0
  124. package/dist/src/app/charts/styling/svgStyle.js +84 -0
  125. package/dist/src/app/charts/styling/svgStyle.js.map +1 -0
  126. package/dist/src/app/charts/subscriptions/subscription.test.d.ts +1 -0
  127. package/dist/src/app/charts/subscriptions/subscription.test.js +395 -0
  128. package/dist/src/app/charts/subscriptions/subscription.test.js.map +1 -0
  129. package/dist/src/app/charts/subscriptions/subscriptions.d.ts +100 -0
  130. package/dist/src/app/charts/subscriptions/subscriptions.js +449 -0
  131. package/dist/src/app/charts/subscriptions/subscriptions.js.map +1 -0
  132. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.d.ts +90 -0
  133. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js +302 -0
  134. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js.map +1 -0
  135. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.d.ts +100 -0
  136. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js +190 -0
  137. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js.map +1 -0
  138. package/dist/src/app/charts/{RasterPlotTooltipContent.js → tooltips/RasterPlotTooltipContent.js} +40 -44
  139. package/dist/src/app/charts/tooltips/RasterPlotTooltipContent.js.map +1 -0
  140. package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js +154 -0
  141. package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js.map +1 -0
  142. package/dist/src/app/charts/{Tooltip.d.ts → tooltips/Tooltip.d.ts} +4 -2
  143. package/dist/src/app/charts/{Tooltip.js → tooltips/Tooltip.js} +23 -28
  144. package/dist/src/app/charts/tooltips/Tooltip.js.map +1 -0
  145. package/dist/src/app/charts/{tooltipUtils.d.ts → tooltips/tooltipUtils.d.ts} +11 -6
  146. package/dist/src/app/charts/{tooltipUtils.js → tooltips/tooltipUtils.js} +33 -17
  147. package/dist/src/app/charts/tooltips/tooltipUtils.js.map +1 -0
  148. package/dist/src/app/charts/{Tracker.d.ts → trackers/Tracker.d.ts} +6 -5
  149. package/dist/src/app/charts/trackers/Tracker.js +60 -0
  150. package/dist/src/app/charts/trackers/Tracker.js.map +1 -0
  151. package/dist/src/app/charts/{trackerUtils.d.ts → trackers/trackerUtils.d.ts} +13 -8
  152. package/dist/src/app/charts/trackers/trackerUtils.js +359 -0
  153. package/dist/src/app/charts/trackers/trackerUtils.js.map +1 -0
  154. package/dist/src/app/charts/utils.d.ts +22 -32
  155. package/dist/src/app/charts/utils.js +36 -37
  156. package/dist/src/app/charts/utils.js.map +1 -1
  157. package/dist/src/index.d.ts +48 -15
  158. package/dist/src/index.js +71 -15
  159. package/dist/src/index.js.map +1 -1
  160. package/package.json +30 -20
  161. package/src/app/charts/Chart.tsx +334 -0
  162. package/src/app/charts/axes/AxesState.test.ts +34 -0
  163. package/src/app/charts/axes/AxesState.ts +112 -0
  164. package/src/app/charts/axes/AxisInterval.test.ts +143 -0
  165. package/src/app/charts/axes/AxisInterval.ts +139 -0
  166. package/src/app/charts/axes/BaseAxisRange.ts +113 -0
  167. package/src/app/charts/axes/ContinuousAxis.tsx +192 -0
  168. package/src/app/charts/axes/ContinuousAxisRange.test.ts +55 -0
  169. package/src/app/charts/axes/ContinuousAxisRange.ts +96 -0
  170. package/src/app/charts/axes/OrdinalAxis.tsx +223 -0
  171. package/src/app/charts/axes/OrdinalAxisRange.test.ts +55 -0
  172. package/src/app/charts/axes/OrdinalAxisRange.ts +112 -0
  173. package/src/app/charts/axes/axes.ts +1569 -0
  174. package/src/app/charts/d3types.ts +16 -0
  175. package/src/app/charts/filters/regexFilter.test.ts +13 -0
  176. package/src/app/charts/filters/regexFilter.ts +17 -0
  177. package/src/app/charts/hooks/useAxes.tsx +341 -0
  178. package/src/app/charts/hooks/useChart.tsx +159 -0
  179. package/src/app/charts/hooks/useDataObservable.tsx +175 -0
  180. package/src/app/charts/hooks/useInitialData.tsx +65 -0
  181. package/src/app/charts/hooks/useMouse.tsx +125 -0
  182. package/src/app/charts/hooks/usePlotDimensions.tsx +120 -0
  183. package/src/app/charts/hooks/useTooltip.tsx +112 -0
  184. package/src/app/charts/observables/ChartData.ts +31 -0
  185. package/src/app/charts/observables/iterates.test.ts +201 -0
  186. package/src/app/charts/observables/iterates.ts +203 -0
  187. package/src/app/charts/observables/ordinals.test.ts +135 -0
  188. package/src/app/charts/observables/ordinals.ts +248 -0
  189. package/src/app/charts/plots/BarPlot.tsx +1088 -0
  190. package/src/app/charts/plots/PoincarePlot.tsx +832 -0
  191. package/src/app/charts/plots/RasterPlot.tsx +676 -0
  192. package/src/app/charts/plots/ScatterPlot.tsx +653 -0
  193. package/src/app/charts/plots/plot.ts +75 -0
  194. package/src/app/charts/series/baseSeries.ts +52 -0
  195. package/src/app/charts/series/datumSeries.test.ts +60 -0
  196. package/src/app/charts/series/iterateSeries.ts +56 -0
  197. package/src/app/charts/series/ordinalSeries.ts +164 -0
  198. package/src/app/charts/series/timeSeries.ts +40 -0
  199. package/src/app/charts/series/timeSeriesChartData.ts +68 -0
  200. package/src/app/charts/styling/barPlotStyle.ts +126 -0
  201. package/src/app/charts/styling/margins.test.ts +22 -0
  202. package/src/app/charts/styling/margins.ts +58 -0
  203. package/src/app/charts/styling/svgStyle.ts +118 -0
  204. package/src/app/charts/subscriptions/subscription.test.ts +499 -0
  205. package/src/app/charts/subscriptions/subscriptions.ts +635 -0
  206. package/src/app/charts/tooltips/BarPlotTooltipContent.tsx +440 -0
  207. package/src/app/charts/tooltips/PoincarePlotTooltipContent.tsx +352 -0
  208. package/src/app/charts/tooltips/RasterPlotTooltipContent.tsx +274 -0
  209. package/src/app/charts/tooltips/ScatterPlotTooltipContent.tsx +319 -0
  210. package/src/app/charts/tooltips/Tooltip.tsx +148 -0
  211. package/src/app/charts/tooltips/tooltipUtils.ts +216 -0
  212. package/src/app/charts/trackers/Tracker.tsx +129 -0
  213. package/src/app/charts/trackers/trackerUtils.ts +494 -0
  214. package/src/app/charts/utils.ts +109 -0
  215. package/dist/src/app/charts/CategoryAxis.d.ts +0 -20
  216. package/dist/src/app/charts/CategoryAxis.js +0 -112
  217. package/dist/src/app/charts/CategoryAxis.js.map +0 -1
  218. package/dist/src/app/charts/ContinuousAxis.d.ts +0 -16
  219. package/dist/src/app/charts/ContinuousAxis.js +0 -186
  220. package/dist/src/app/charts/ContinuousAxis.js.map +0 -1
  221. package/dist/src/app/charts/RasterPlot.js.map +0 -1
  222. package/dist/src/app/charts/RasterPlotTooltipContent.js.map +0 -1
  223. package/dist/src/app/charts/ScatterPlot.js +0 -351
  224. package/dist/src/app/charts/ScatterPlot.js.map +0 -1
  225. package/dist/src/app/charts/ScatterPlotTooltipContent.js +0 -163
  226. package/dist/src/app/charts/ScatterPlotTooltipContent.js.map +0 -1
  227. package/dist/src/app/charts/Tooltip.js.map +0 -1
  228. package/dist/src/app/charts/Tracker.js +0 -65
  229. package/dist/src/app/charts/Tracker.js.map +0 -1
  230. package/dist/src/app/charts/axes.d.ts +0 -132
  231. package/dist/src/app/charts/axes.js +0 -265
  232. package/dist/src/app/charts/axes.js.map +0 -1
  233. package/dist/src/app/charts/chartData.js +0 -32
  234. package/dist/src/app/charts/chartData.js.map +0 -1
  235. package/dist/src/app/charts/continuousAxisRangeFor.d.ts +0 -20
  236. package/dist/src/app/charts/continuousAxisRangeFor.js +0 -68
  237. package/dist/src/app/charts/continuousAxisRangeFor.js.map +0 -1
  238. package/dist/src/app/charts/datumSeries.d.ts +0 -59
  239. package/dist/src/app/charts/datumSeries.js +0 -55
  240. package/dist/src/app/charts/datumSeries.js.map +0 -1
  241. package/dist/src/app/charts/datumSeries.test.js +0 -50
  242. package/dist/src/app/charts/datumSeries.test.js.map +0 -1
  243. package/dist/src/app/charts/hooks/AxesState.d.ts +0 -37
  244. package/dist/src/app/charts/hooks/AxesState.js +0 -44
  245. package/dist/src/app/charts/hooks/AxesState.js.map +0 -1
  246. package/dist/src/app/charts/margins.js.map +0 -1
  247. package/dist/src/app/charts/margins.test.js +0 -14
  248. package/dist/src/app/charts/margins.test.js.map +0 -1
  249. package/dist/src/app/charts/plot.js.map +0 -1
  250. package/dist/src/app/charts/regexFilter.d.ts +0 -9
  251. package/dist/src/app/charts/regexFilter.js +0 -17
  252. package/dist/src/app/charts/regexFilter.js.map +0 -1
  253. package/dist/src/app/charts/regexFilter.test.js +0 -11
  254. package/dist/src/app/charts/regexFilter.test.js.map +0 -1
  255. package/dist/src/app/charts/subscriptions.d.ts +0 -43
  256. package/dist/src/app/charts/subscriptions.js +0 -213
  257. package/dist/src/app/charts/subscriptions.js.map +0 -1
  258. package/dist/src/app/charts/svgStyle.d.ts +0 -27
  259. package/dist/src/app/charts/svgStyle.js +0 -32
  260. package/dist/src/app/charts/svgStyle.js.map +0 -1
  261. package/dist/src/app/charts/timeRange.test.js +0 -54
  262. package/dist/src/app/charts/timeRange.test.js.map +0 -1
  263. package/dist/src/app/charts/tooltipUtils.js.map +0 -1
  264. package/dist/src/app/charts/trackerUtils.js +0 -130
  265. package/dist/src/app/charts/trackerUtils.js.map +0 -1
  266. /package/dist/src/app/charts/{datumSeries.test.d.ts → axes/AxesState.test.d.ts} +0 -0
  267. /package/dist/src/app/charts/{margins.test.d.ts → axes/AxisInterval.test.d.ts} +0 -0
  268. /package/dist/src/app/charts/{regexFilter.test.d.ts → axes/ContinuousAxisRange.test.d.ts} +0 -0
  269. /package/dist/src/app/charts/{timeRange.test.d.ts → axes/OrdinalAxisRange.test.d.ts} +0 -0
  270. /package/dist/src/app/charts/{RasterPlotTooltipContent.d.ts → tooltips/RasterPlotTooltipContent.d.ts} +0 -0
  271. /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
+ }