lumenize
Version:
Illuminating the forest AND the trees in your data.
1 lines • 50.8 kB
JavaScript
Ext.data.JsonP.Lumenize_TimeSeriesCalculator({"tagname":"class","name":"Lumenize.TimeSeriesCalculator","autodetected":{},"files":[{"filename":"TimeSeriesCalculator.coffee.js","href":"TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator"}],"members":[{"name":"deriveFieldsAfterSummary","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-deriveFieldsAfterSummary","meta":{}},{"name":"deriveFieldsOnInput","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-deriveFieldsOnInput","meta":{}},{"name":"deriveFieldsOnOutput","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-deriveFieldsOnOutput","meta":{}},{"name":"endBefore","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-endBefore","meta":{}},{"name":"granularity","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-granularity","meta":{}},{"name":"holidays","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-holidays","meta":{}},{"name":"metrics","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-metrics","meta":{}},{"name":"projectionsConfig","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-projectionsConfig","meta":{}},{"name":"startOn","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-startOn","meta":{}},{"name":"summaryMetricsConfig","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-summaryMetricsConfig","meta":{}},{"name":"tz","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-tz","meta":{}},{"name":"uniqueIDField","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-uniqueIDField","meta":{}},{"name":"validFromField","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-validFromField","meta":{}},{"name":"validToField","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-validToField","meta":{}},{"name":"workDayEndBefore","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-workDayEndBefore","meta":{}},{"name":"workDayStartOn","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-workDayStartOn","meta":{}},{"name":"workDays","tagname":"cfg","owner":"Lumenize.TimeSeriesCalculator","id":"cfg-workDays","meta":{}},{"name":"constructor","tagname":"method","owner":"Lumenize.TimeSeriesCalculator","id":"method-constructor","meta":{}},{"name":"addSnapshots","tagname":"method","owner":"Lumenize.TimeSeriesCalculator","id":"method-addSnapshots","meta":{"chainable":true}},{"name":"getResults","tagname":"method","owner":"Lumenize.TimeSeriesCalculator","id":"method-getResults","meta":{}},{"name":"getStateForSaving","tagname":"method","owner":"Lumenize.TimeSeriesCalculator","id":"method-getStateForSaving","meta":{}},{"name":"newFromSavedState","tagname":"method","owner":"Lumenize.TimeSeriesCalculator","id":"static-method-newFromSavedState","meta":{"static":true}}],"alternateClassNames":[],"aliases":{},"id":"class-Lumenize.TimeSeriesCalculator","short_doc":"This calculator is used to convert snapshot data into time series aggregations. ...","component":false,"superclasses":[],"subclasses":[],"mixedInto":[],"mixins":[],"parentMixins":[],"requires":[],"uses":[],"html":"<div><pre class=\"hierarchy\"><h4>Files</h4><div class='dependency'><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator' target='_blank'>TimeSeriesCalculator.coffee.js</a></div></pre><div class='doc-contents'><p>This calculator is used to convert snapshot data into time series aggregations.</p>\n\n<p>Below are two examples of using the TimeSeriesCalculator. The first is a detailed example showing how you would create\na set of single-metric series (line, spline, or column). The second, is an example of creating a set of group-by series\n(like you would use to create a stacked column or stacked area chart). You can mix and match these on the same chart, but\none type (a set of single-metric series versus a single group-by meta-series) typically dominates.</p>\n\n<h2>Time-series example - a burn chart</h2>\n\n<p>Let's start with a fairly large set of snapshots and create a set of series for a burn (up/down) chart.</p>\n\n<pre><code>lumenize = require('../')\n{TimeSeriesCalculator, Time} = lumenize\n\nsnapshotsCSV = [\n [\"ObjectID\", \"_ValidFrom\", \"_ValidTo\", \"ScheduleState\", \"PlanEstimate\", \"TaskRemainingTotal\", \"TaskEstimateTotal\"],\n\n [1, \"2010-10-10T15:00:00.000Z\", \"2011-01-02T13:00:00.000Z\", \"Ready to pull\", 5 , 15 , 15],\n\n [1, \"2011-01-02T13:00:00.000Z\", \"2011-01-02T15:10:00.000Z\", \"Ready to pull\", 5 , 15 , 15],\n [1, \"2011-01-02T15:10:00.000Z\", \"2011-01-03T15:00:00.000Z\", \"In progress\" , 5 , 20 , 15],\n [2, \"2011-01-02T15:00:00.000Z\", \"2011-01-03T15:00:00.000Z\", \"Ready to pull\", 3 , 5 , 5],\n [3, \"2011-01-02T15:00:00.000Z\", \"2011-01-03T15:00:00.000Z\", \"Ready to pull\", 5 , 12 , 12],\n\n [2, \"2011-01-03T15:00:00.000Z\", \"2011-01-04T15:00:00.000Z\", \"In progress\" , 3 , 5 , 5],\n [3, \"2011-01-03T15:00:00.000Z\", \"2011-01-04T15:00:00.000Z\", \"Ready to pull\", 5 , 12 , 12],\n [4, \"2011-01-03T15:00:00.000Z\", \"2011-01-04T15:00:00.000Z\", \"Ready to pull\", 5 , 15 , 15],\n [1, \"2011-01-03T15:10:00.000Z\", \"2011-01-04T15:00:00.000Z\", \"In progress\" , 5 , 12 , 15],\n\n [1, \"2011-01-04T15:00:00.000Z\", \"2011-01-06T15:00:00.000Z\", \"Accepted\" , 5 , 0 , 15],\n [2, \"2011-01-04T15:00:00.000Z\", \"2011-01-06T15:00:00.000Z\", \"In test\" , 3 , 1 , 5],\n [3, \"2011-01-04T15:00:00.000Z\", \"2011-01-05T15:00:00.000Z\", \"In progress\" , 5 , 10 , 12],\n [4, \"2011-01-04T15:00:00.000Z\", \"2011-01-06T15:00:00.000Z\", \"Ready to pull\", 5 , 15 , 15],\n [5, \"2011-01-04T15:00:00.000Z\", \"2011-01-06T15:00:00.000Z\", \"Ready to pull\", 2 , 4 , 4],\n\n [3, \"2011-01-05T15:00:00.000Z\", \"2011-01-07T15:00:00.000Z\", \"In test\" , 5 , 5 , 12],\n\n [1, \"2011-01-06T15:00:00.000Z\", \"2011-01-07T15:00:00.000Z\", \"Released\" , 5 , 0 , 15],\n [2, \"2011-01-06T15:00:00.000Z\", \"2011-01-07T15:00:00.000Z\", \"Accepted\" , 3 , 0 , 5],\n [4, \"2011-01-06T15:00:00.000Z\", \"2011-01-07T15:00:00.000Z\", \"In progress\" , 5 , 7 , 15],\n [5, \"2011-01-06T15:00:00.000Z\", \"2011-01-07T15:00:00.000Z\", \"Ready to pull\", 2 , 4 , 4],\n\n [1, \"2011-01-07T15:00:00.000Z\", \"9999-01-01T00:00:00.000Z\", \"Released\" , 5 , 0 , 15],\n [2, \"2011-01-07T15:00:00.000Z\", \"9999-01-01T00:00:00.000Z\", \"Released\" , 3 , 0 , 5],\n [3, \"2011-01-07T15:00:00.000Z\", \"9999-01-01T00:00:00.000Z\", \"Accepted\" , 5 , 0 , 12],\n [4, \"2011-01-07T15:00:00.000Z\", \"9999-01-01T00:00:00.000Z\", \"In test\" , 5 , 3 , 15] # Note: ObjectID 5 deleted\n]\n\nsnapshots = lumenize.csvStyleArray_To_ArrayOfMaps(snapshotsCSV)\n</code></pre>\n\n<p>Let's add our first aggregation specification. You can add virtual fields to the input rows by providing your own callback function.</p>\n\n<pre><code>deriveFieldsOnInput = [\n {as: 'PercentRemaining', f: (row) -> 100 * row.TaskRemainingTotal / row.TaskEstimateTotal }\n]\n</code></pre>\n\n<p>You can have as many of these derived fields as you wish. They are calculated in order to it's OK to use an earlier\nderived field when calculating a later one.</p>\n\n<p>Next, we use the native fields in the snapshots, plus our derived field above to calculate most of the chart\nseries. Sums and counts are bread and butter, but all <a href=\"#!/api/Lumenize.functions\" rel=\"Lumenize.functions\" class=\"docClass\">Lumenize.functions</a> functions are supported (standardDeviation,\nmedian, percentile coverage, etc.) and Lumenize includes some functions specifically well suited to burn chart\ncalculations (filteredSum, and filteredCount) as we shall now demonstrate.</p>\n\n<pre><code>acceptedValues = ['Accepted', 'Released']\n\nmetrics = [\n {as: 'StoryCountBurnUp', f: 'filteredCount', filterField: 'ScheduleState', filterValues: acceptedValues},\n {as: 'StoryUnitBurnUp', field: 'PlanEstimate', f: 'filteredSum', filterField: 'ScheduleState', filterValues: acceptedValues},\n {as: 'StoryUnitScope', field: 'PlanEstimate', f: 'sum'},\n {as: 'StoryCountScope', f: 'count'},\n {as: 'TaskUnitBurnDown', field: 'TaskRemainingTotal', f: 'sum'},\n {as: 'TaskUnitScope', field: 'TaskEstimateTotal', f: 'sum'},\n {as: 'MedianPercentRemaining', field: 'PercentRemaining', f: 'median'}\n]\n</code></pre>\n\n<p>Let's break this down. The first series uses a <code>filteredCount</code> function. What this says is \"count the number of items\nwhere the ScheduleState is either 'Accepted' or 'Released' and store that in a series named 'StoryCountBurnUp'. The\nsecond series is very similar but instead of counting, we are summing the PlanEstimate field and sticking it in\nthe StoryUnitBurnUp series. The next four series are simple sums or counts (no filtering) and the final series\nis a gratuitous use of the 'median' function least you forget that it can do more than counts and sums.</p>\n\n<p>Next, we specify the summary metrics for the chart. We're not really interested in displaying any summary metrics for\nthis chart but we need to calculate the max values of two of the existing series in order to add the two ideal line series.\nNotice how the summary metric for TaskUnitBurnDown_max_index uses an earlier summary metric. They are calculated\nin order and made avalable in the scope of the callback function to enable this.</p>\n\n<pre><code>summaryMetricsConfig = [\n {field: 'TaskUnitScope', f: 'max'},\n {field: 'TaskUnitBurnDown', f: 'max'},\n {as: 'TaskUnitBurnDown_max_index', f: (seriesData, summaryMetrics) ->\n for row, index in seriesData\n if row.TaskUnitBurnDown is summaryMetrics.TaskUnitBurnDown_max\n return index\n }\n]\n</code></pre>\n\n<p>The calculations from the summary metrics above are passed into the calculations for 'deriveFieldsAfterSummary'.\nHere is where we calculate two alternatives for the burn down ideal line.</p>\n\n<pre><code>deriveFieldsAfterSummary = [\n {as: 'Ideal', f: (row, index, summaryMetrics, seriesData) ->\n max = summaryMetrics.TaskUnitScope_max\n increments = seriesData.length - 1\n incrementAmount = max / increments\n return Math.floor(100 * (max - index * incrementAmount)) / 100\n },\n {as: 'Ideal2', f: (row, index, summaryMetrics, seriesData) ->\n if index < summaryMetrics.TaskUnitBurnDown_max_index\n return null\n else\n max = summaryMetrics.TaskUnitBurnDown_max\n increments = seriesData.length - 1 - summaryMetrics.TaskUnitBurnDown_max_index\n incrementAmount = max / increments\n return Math.floor(100 * (max - (index - summaryMetrics.TaskUnitBurnDown_max_index) * incrementAmount)) / 100\n }\n]\n</code></pre>\n\n<p>The two above series ignore the row values and simply key off of the index and summaryMetrics, but you could have\nused the row values to, for instance, add two existing series to create a third.</p>\n\n<p>Notice how the entire seriesData is available inside of your provided callback. This would allow you to derive a metric\noff of rows other than the current row like you would for a sliding-window calculation (Shewarts method).</p>\n\n<p>Just like all Lumenize Calculators, we can set holidays to be knocked out of the results.</p>\n\n<pre><code>holidays = [\n {year: 2011, month: 1, day: 5} # Made up holiday to test knockout\n]\n</code></pre>\n\n<p>Let's build the config Object from the above specifications and instantiate the calculator.</p>\n\n<pre><code>config =\n uniqueIDField: \"ObjectID\"\n deriveFieldsOnInput: deriveFieldsOnInput\n metrics: metrics\n summaryMetricsConfig: summaryMetricsConfig\n deriveFieldsAfterSummary: deriveFieldsAfterSummary\n granularity: lumenize.Time.DAY\n tz: 'America/Chicago'\n holidays: holidays\n workDays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday' # They work on Sundays\n\ncalculator = new TimeSeriesCalculator(config)\n</code></pre>\n\n<p>We can now send our snapshots into the calculator.</p>\n\n<pre><code>startOnISOString = new Time('2011-01-02').getISOStringInTZ(config.tz)\nupToDateISOString = new Time('2011-01-10').getISOStringInTZ(config.tz)\ncalculator.addSnapshots(snapshots, startOnISOString, upToDateISOString)\n</code></pre>\n\n<p>Note, you must specify a startOnISOString and upToDateISOString. If you send in another round of snapshots, the new startOnISOString must match\nthe upToDateISOString of the prior call to addSnapshots(). This is the key to making sure that incremental calculations don't\nskip or double count anything. You can even send in the same snapshots in a later round and they won't be double\ncounted. This idempotency property is also accomplished by the precise startOnISOString (current) upToDateISOString (prior) alignment.\nIf you restore the calculator from a saved state, the upToDate property will contain the prior upToDateISOString. You can use\nthis to compose a query that gets all of the snapshots necessary for the update. Just query with\n<code>_ValidTo: {$gte: upToDate}</code>. Note, this will refetch all the snapshots that were still active the last time\nyou updated the calculator. This is expected and necessary.</p>\n\n<p>Let's print out our results and see what we have.</p>\n\n<pre><code>keys = ['label', 'StoryUnitScope', 'StoryCountScope', 'StoryCountBurnUp',\n 'StoryUnitBurnUp', 'TaskUnitBurnDown', 'TaskUnitScope', 'Ideal', 'Ideal2', 'MedianPercentRemaining']\n\ncsv = lumenize.arrayOfMaps_To_CSVStyleArray(calculator.getResults().seriesData, keys)\n\nconsole.log(csv.slice(1))\n# [ [ '2011-01-02', 13, 3, 0, 0, 37, 32, 51, null, 100 ],\n# [ '2011-01-03', 18, 4, 0, 0, 44, 47, 42.5, 44, 100 ],\n# [ '2011-01-04', 20, 5, 1, 5, 25, 51, 34, 35.2, 41.666666666666664 ],\n# [ '2011-01-06', 20, 5, 2, 8, 16, 51, 25.5, 26.4, 41.666666666666664 ],\n# [ '2011-01-07', 18, 4, 3, 13, 3, 47, 17, 17.59, 0 ],\n# [ '2011-01-09', 18, 4, 3, 13, 3, 47, 8.5, 8.79, 0 ],\n# [ '2011-01-10', 18, 4, 3, 13, 3, 47, 0, 0, 0 ] ]\n</code></pre>\n\n<h2>Time-series group-by example</h2>\n\n<pre><code>allowedValues = ['Ready to pull', 'In progress', 'In test', 'Accepted', 'Released']\n</code></pre>\n\n<p>It supports both count and sum for group-by metrics</p>\n\n<pre><code>metrics = [\n {f: 'groupBySum', field: 'PlanEstimate', groupByField: 'ScheduleState', allowedValues: allowedValues},\n {f: 'groupByCount', groupByField: 'ScheduleState', allowedValues: allowedValues, prefix: 'Count '},\n {as: 'MedianTaskRemainingTotal', field: 'TaskRemainingTotal', f: 'median'} # An example of how you might overlay a line series\n]\n\nholidays = [\n {year: 2011, month: 1, day: 5} # Made up holiday to test knockout\n]\n\nconfig = # default workDays\n uniqueIDField: \"ObjectID\"\n metrics: metrics\n granularity: Time.DAY\n tz: 'America/Chicago'\n holidays: holidays\n workDays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday' # They work on Sundays\n\ncalculator = new TimeSeriesCalculator(config)\n\nstartOnISOString = new Time('2010-12-31').getISOStringInTZ(config.tz)\nupToDateISOString = new Time('2011-01-09').getISOStringInTZ(config.tz)\ncalculator.addSnapshots(snapshots, startOnISOString, upToDateISOString)\n</code></pre>\n\n<p>Here is the output of the sum metrics</p>\n\n<pre><code>keys = ['label'].concat(allowedValues)\ncsv = lumenize.arrayOfMaps_To_CSVStyleArray(calculator.getResults().seriesData, keys)\nconsole.log(csv.slice(1))\n# [ [ '2010-12-31', 5, 0, 0, 0, 0 ],\n# [ '2011-01-02', 8, 5, 0, 0, 0 ],\n# [ '2011-01-03', 10, 8, 0, 0, 0 ],\n# [ '2011-01-04', 7, 0, 8, 5, 0 ],\n# [ '2011-01-06', 2, 5, 5, 3, 5 ],\n# [ '2011-01-07', 0, 0, 5, 5, 8 ],\n# [ '2011-01-09', 0, 0, 5, 5, 8 ] ]\n</code></pre>\n\n<p>Here is the output of the count metrics</p>\n\n<pre><code>keys = ['label'].concat('Count ' + a for a in allowedValues)\ncsv = lumenize.arrayOfMaps_To_CSVStyleArray(calculator.getResults().seriesData, keys)\nconsole.log(csv.slice(1))\n# [ [ '2010-12-31', 1, 0, 0, 0, 0 ],\n# [ '2011-01-02', 2, 1, 0, 0, 0 ],\n# [ '2011-01-03', 2, 2, 0, 0, 0 ],\n# [ '2011-01-04', 2, 0, 2, 1, 0 ],\n# [ '2011-01-06', 1, 1, 1, 1, 1 ],\n# [ '2011-01-07', 0, 0, 1, 1, 2 ],\n# [ '2011-01-09', 0, 0, 1, 1, 2 ] ]\n</code></pre>\n\n<p>We didn't output the MedianTaskRemainingTotal metric but it's in there. I included it to demonstrate that you can\ncalculate non-group-by series along side group-by series.</p>\n\n<p>The order of execution of all of the configurations that modify or augment the results is as follows:</p>\n\n<ol>\n<li><strong>deriveFieldsOnInput</strong> operate on the snapshots by adding virtual fields to them. This is done when addSnapshots() is\ncalled before any time series calculations are run your metrics config can refer to them as if they were real fields\non the snapshots.</li>\n<li><strong>metrics</strong> which defines the seriesData.</li>\n<li><strong>deriveFieldsOnOutput</strong> operates on the output seriesData table that has one row per tick. It is also done when you call\naddSnapshots() but after the seriesData calculations are completed.</li>\n<li><strong>summaryMetricsConfig</strong> also operates on the seriesData table but rather than augmenting the rows in that table, it creates\na new table (summaryMetrics) that just contains summary information. An example usage would be to find the max scope to be\nused by deriveFieldsAfterSummary to create an ideal line that burned down from that max. Note, this is run\nevery time you call getResults(), so it can potentially be expensive if you fetch the results often with getResults().</li>\n<li><strong>deriveFieldsAfterSummary</strong> is used next. It's essentially the same as deriveFieldsOnOutput and also creates new columns\nin the seriesData table whose rows are made up of ticks. However, it allows you to use the summary table. Only use this\nif the field calculation needs something from the summary (like an ideal line) because it is potentially more\nexpensive since it's done every time you call getResults().</li>\n<li><strong>projectionsConfig</strong> is the last augmentation config used.</li>\n</ol>\n\n</div><div class='members'><div class='members-section'><div class='definedBy'>Defined By</div><h3 class='members-title icon-cfg'>Config options</h3><div class='subsection'><div id='cfg-deriveFieldsAfterSummary' class='member first-child not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-deriveFieldsAfterSummary' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-deriveFieldsAfterSummary' class='name expandable'>deriveFieldsAfterSummary</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>same format at deriveFieldsOnInput, except the callback is in the form f(row, index, summaryMetrics, seriesData)\n Th...</div><div class='long'><p>same format at deriveFieldsOnInput, except the callback is in the form <code>f(row, index, summaryMetrics, seriesData)</code>\n This is called on all rows every time you call getResults() so it's less efficient than deriveFieldsOnOutput. Only use it if you need\n the summaryMetrics in your calculation.</p>\n</div></div></div><div id='cfg-deriveFieldsOnInput' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-deriveFieldsOnInput' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-deriveFieldsOnInput' class='name expandable'>deriveFieldsOnInput</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'><p>An Array of Maps in the form <code>{field:'myField', f:(fact)->...}</code></p>\n</div><div class='long'><p>An Array of Maps in the form <code>{field:'myField', f:(fact)->...}</code></p>\n</div></div></div><div id='cfg-deriveFieldsOnOutput' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-deriveFieldsOnOutput' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-deriveFieldsOnOutput' class='name expandable'>deriveFieldsOnOutput</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>same format at deriveFieldsOnInput, except the callback is in the form f(row)\n This is only called for dirty rows th...</div><div class='long'><p>same format at deriveFieldsOnInput, except the callback is in the form <code>f(row)</code>\n This is only called for dirty rows that were effected by the latest round of additions in an incremental calculation.</p>\n</div></div></div><div id='cfg-endBefore' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-endBefore' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-endBefore' class='name expandable'>endBefore</a> : String/ISOString/Date/Lumenize.Time<span class=\"signature\"></span></div><div class='description'><div class='short'>This becomes the master endBefore for the entire calculator\n limiting the calculator to only emit ticks before this. ...</div><div class='long'><p>This becomes the master endBefore for the entire calculator\n limiting the calculator to only emit ticks before this.</p>\n<p>Defaults to: <code>infinity</code></p></div></div></div><div id='cfg-granularity' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-granularity' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-granularity' class='name expandable'>granularity</a> : String<span class=\"signature\"></span></div><div class='description'><div class='short'>'month', 'week', 'quarter', 'day', etc. ...</div><div class='long'><p>'month', 'week', 'quarter', 'day', etc. Use Time.MONTH, Time.WEEK, etc.</p>\n</div></div></div><div id='cfg-holidays' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-holidays' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-holidays' class='name expandable'>holidays</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>An optional Array containing rows that are either ISOStrings or JavaScript Objects\n (mix and match). ...</div><div class='long'><p>An optional Array containing rows that are either ISOStrings or JavaScript Objects\n (mix and match). Example: <code>[{month: 12, day: 25}, {year: 2011, month: 11, day: 24}, \"2012-12-24\"]</code>\n Notice how you can leave off the year if the holiday falls on the same day every year.</p>\n</div></div></div><div id='cfg-metrics' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-metrics' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-metrics' class='name expandable'>metrics</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>Array which specifies the metrics to calculate for tick in time. ...</div><div class='long'><p>Array which specifies the metrics to calculate for tick in time.</p>\n\n<p> Example:</p>\n\n<pre><code>config = {}\nconfig.metrics = [\n {field: 'field3'}, # defaults to metrics: ['sum']\n {field: 'field4', metrics: [\n {f: 'sum'}, # will add a metric named field4_sum\n {as: 'median4', f: 'p50'}, # renamed p50 to median4 from default of field4_p50\n {as: 'myCount', f: (values) -> return values.length} # user-supplied function\n ]}\n]\n</code></pre>\n\n<p> If you specify a field without any metrics, it will assume you want the sum but it will not automatically\n add the sum metric to fields with a metrics specification. User-supplied aggregation functions are also supported as\n shown in the 'myCount' metric above.</p>\n\n<p> Note, if the metric has dependencies (e.g. average depends upon count and sum) it will automatically add those to\n your metric definition. If you've already added a dependency but put it under a different \"as\", it's not smart\n enough to sense that and it will add it again. Either live with the duplication or leave\n dependency metrics named their default by not providing an \"as\" field.</p>\n<p>Defaults to: <code>[]</code></p></div></div></div><div id='cfg-projectionsConfig' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-projectionsConfig' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-projectionsConfig' class='name expandable'>projectionsConfig</a> : Object<span class=\"signature\"></span></div><div class='description'><div class='short'>Allows you to project series into the future\n\n Example:\n\nprojectionsConfig = {\n limit: 100 # optional, defaults to...</div><div class='long'><p>Allows you to project series into the future</p>\n\n<p> Example:</p>\n\n<pre><code>projectionsConfig = {\n limit: 100 # optional, defaults to 300\n continueWhile: (point) -> # Optional but recommended\n return point.StoryCountScope_projection > point.StoryCountBurnUp_projection\n minFractionToConsider: 1.0 / 2.0 # optional, defaults to 1/3\n minCountToConsider: 3 # optional, defaults to 15\n series: [\n {as: 'ScopeProjection', field: 'StoryUnitScope', slope: 0.5},\n {field: 'StoryCountScope', slope: 0}, # 0 slope is a level projection\n {field: 'StoryCountBurnUp'}, # Will use v-Optimal (least squares of difference in angle / count)\n {field: 'field5', startIndex: 0} # 0 will use entire series. Add grab-handle to allow user to specify some other index\n ]\n}\n</code></pre>\n\n<p> When a projectionsConfig is provided, the TimeSeriesCalculator will add points to the output seriesData showing\n the series being projected. These projected series will always start at the last point of the series and go out from there.\n By default, they are named the same as the series (field) they are projecting with '_projection' concatenated onto the end.\n However, this name can be overridden by using the <code>as</code> field of the series configuration.</p>\n\n<p> In addition to adding to the dataSeries, a summary of the projection is provided in the <code>projections</code> sub-field\n returned when you call <code>getResults()</code>. The format of this sub-field is something like this:</p>\n\n<pre><code>projections = {\n \"limit\": 100,\n \"series\": [\n {\"as\": \"ScopeProjection\", \"field\": \"StoryUnitScope\", \"slope\": 0.5},\n {\"field\": \"StoryCountScope\", \"slope\": 0},\n {\"field\": \"StoryCountBurnUp\", \"startIndex\": 0, \"slope\": 0.6},\n {\"field\": \"field5\", \"startIndex\": 0, \"slope\": 0.123259838293}\n ],\n \"minFractionToConsider\": 0.5,\n \"minCountToConsider\": 3,\n \"pointsAddedCount\": 6,\n \"lastPoint\": {\n \"tick\": \"2011-01-17T06:00:00.000Z\",\n \"label\": \"2011-01-16\",\n \"ScopeProjection\": 21,\n \"StoryCountScope_projection\": 4,\n \"StoryCountBurnUp_projection\": 6.6\n }\n}\n</code></pre>\n\n<p> You can inspect this returned Object to see what slope it used for each series. Also, if you were not\n rendering a chart but just wanted to use this calculator to make a holiday-knockout-precise forecast, you could\n inspect the <code>lastPoint.tick</code> field to identify when this work is forecast to finish.</p>\n\n<p> One thing to keep in mind when using this functionality is that these calculators in general and these projections\n in particular, is that the x-axis is a complex Timeline of ticks rather than simple linear calander time.\n So, these projections will take into account any holidays specified in the future.</p>\n\n<p> The <code>projectionsConfig</code> is a fairly complicated configuration in its own right. It is embedded in the config object\n for the overall TimeSeriesCalculator but it has a bunch of sub-configuration also. The five top level items are:\n <code>limit</code>, <code>continueWhile</code>, <code>minFractionToConsider</code>, <code>minCountToConsider</code>, and <code>series</code>.</p>\n\n<p> <code>limit</code> and <code>continueWhile</code>\n are used to control how far in the future the projection will go. It will stop at <code>limit</code> even if the <code>continueWhile</code>\n is always met. This will prevent the projection from becoming an infinite loop. The <code>continueWhile</code> predicate\n is technically not required but in almost all cases you will not know how far into the future you want to go\n so you will have to use it.</p>\n\n<p> <code>minFractionToConsider</code> and <code>minCountToConsider</code> are used for series where you allow the calculator to find\n the optimal starting point for the projection (the default behavior). It's very common for projects to start out slowly and then ramp up.\n The optimal algorithm is designed to find this knee where the difference in angle of the projection is the minimum\n of the square of the difference between the overall angle and all the sub-angles between this starting point going up to the point before\n the last point. This minimum is also divided by the number of points so using more data points for the projection\n is favored over using fewer. These two configuration parameters, <code>minFractionToConsider</code>, and <code>minCountToConsider</code>\n tell the v-optimal algorthim the minimum number or portion of points to consider. This prevents the algorithm\n from just using the angle of the last few points if they happen to be v-optimal. They currently default to the max of 1/3rd of the project or\n 15 (3 work weeks if granularity is 'days'). Note, that the <code>minCountToConsider</code> default is optimized for\n granularity of 'days'. If you were to use granularity of weeks, I would suggest a much lower number like 3 to 5.\n If you were to use granularity of 'months' then maybe 2-3 months would suffice.</p>\n\n<p> The <code>series</code> sub-config is similar to the main series config, with a required <code>field</code> field and an optional\n <code>as</code> field. The remaining two possible fields (<code>startIndex</code> and <code>slope</code>) are both optional. They are also mutually\n exclusive with the <code>slope</code> trumping the <code>startIndex</code> in cases where both are mistakenly provided.\n If both are ommitted, then the projection will attempt to find the optimal starting point for the projection using the\n algorithm described above.</p>\n\n<p> If the <code>slope</code> is specified, it will override any <code>startingIndex</code> specification. You will commonly set this\n to 0 for scope series where you want the projection to only consider the current scope. If you set this manually,\n be sure to remember that the \"run\" (slope = rise / run) is ticks along the x-axis (holidays and weekends knocked out),\n not true calendar time. Also, note that in the output\n (<code>getResults().projections.series</code>), the slope will always be set even if you did not specify one in your original\n configuration. The startIndex or optimal (default) behaviors operate by setting this slope.</p>\n\n<p> The <code>startingIndex</code> is specified if you want to tell the projection from what point in time, the projection should\n start. Maybe the project doubled staff 3 months into the project and you want the projection to start from there.\n The common usage for this functionality is to provide a grab-handle on the chart and allow the user to use his\n insight combined with the visualization of the data series to pick his own optimal starting point. Note, if you\n specify a <code>startingIndex</code> you should not specify a <code>slope</code> and vice-versa.</p>\n\n<p> Note, that if you specify a <code>startIndex</code> or one is derived for you using the optimal algorithm, then the projection\n series will reach back into the seriesData to this startIndex. If you are using HighCharts, you will want to set\n connectNulls to true for projection series that have a startIndex. Projection series where you specify a <code>slope</code>\n start at the end of the dataSeries and only project into the future.</p>\n</div></div></div><div id='cfg-startOn' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-startOn' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-startOn' class='name expandable'>startOn</a> : String/ISOString/Date/Lumenize.Time<span class=\"signature\"></span></div><div class='description'><div class='short'>This becomes the master startOn for the entire calculator limiting\n the calculator to only emit ticks equal to this ...</div><div class='long'><p>This becomes the master startOn for the entire calculator limiting\n the calculator to only emit ticks equal to this or later.</p>\n<p>Defaults to: <code>-infinity</code></p></div></div></div><div id='cfg-summaryMetricsConfig' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-summaryMetricsConfig' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-summaryMetricsConfig' class='name expandable'>summaryMetricsConfig</a> : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>Allows you to specify a list of metrics to calculate on the results before returning. ...</div><div class='long'><p>Allows you to specify a list of metrics to calculate on the results before returning.\n These can either be in the form of <code>{as: 'myMetric', field: 'field4', f:'sum'}</code> which would extract all of the values\n for field <code>field4</code> and pass it as the values parameter to the <code>f</code> (<code>sum</code> in this example) function (from <a href=\"#!/api/Lumenize.functions\" rel=\"Lumenize.functions\" class=\"docClass\">Lumenize.functions</a>), or\n it can be in the form of <code>{as: 'myMetric', f:(seriesData, summaryMetrics) -> ...}</code>. Note, they are calculated\n in order, so you can use the result of an earlier summaryMetric to calculate a later one.</p>\n</div></div></div><div id='cfg-tz' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-tz' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-tz' class='name expandable'>tz</a> : String<span class=\"signature\"></span></div><div class='description'><div class='short'><p>The timezone for analysis</p>\n</div><div class='long'><p>The timezone for analysis</p>\n</div></div></div><div id='cfg-uniqueIDField' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-uniqueIDField' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-uniqueIDField' class='name expandable'>uniqueIDField</a> : String<span class=\"signature\"></span></div><div class='description'><div class='short'> ...</div><div class='long'>\n<p>Defaults to: <code>"_EntityID"</code></p></div></div></div><div id='cfg-validFromField' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-validFromField' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-validFromField' class='name expandable'>validFromField</a> : String<span class=\"signature\"></span></div><div class='description'><div class='short'> ...</div><div class='long'>\n<p>Defaults to: <code>"_ValidFrom"</code></p></div></div></div><div id='cfg-validToField' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-validToField' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-validToField' class='name expandable'>validToField</a> : String<span class=\"signature\"></span></div><div class='description'><div class='short'> ...</div><div class='long'>\n<p>Defaults to: <code>"_ValidTo"</code></p></div></div></div><div id='cfg-workDayEndBefore' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-workDayEndBefore' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-workDayEndBefore' class='name expandable'>workDayEndBefore</a> : Object<span class=\"signature\"></span></div><div class='description'><div class='short'>An optional object in the form {hour: 17, minute: 0}. ...</div><div class='long'><p>An optional object in the form {hour: 17, minute: 0}. If minute is zero it can be omitted.\n The use of workDayStartOn and workDayEndBefore only make sense when the granularity is \"hour\" or finer.\n Note: If the business closes at 5:00pm, you'll want to leave workDayEndBefore to 17:00, rather\n than 17:01. Think about it, you'll be open 4:59:59.999pm, but you'll be closed at 5:00pm. This also makes all of\n the math work. 9am to 5pm means 17 - 9 = an 8 hour work day.</p>\n</div></div></div><div id='cfg-workDayStartOn' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-workDayStartOn' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-workDayStartOn' class='name expandable'>workDayStartOn</a> : Object<span class=\"signature\"></span></div><div class='description'><div class='short'>An optional object in the form {hour: 8, minute: 15}. ...</div><div class='long'><p>An optional object in the form {hour: 8, minute: 15}. If minute is zero it can be omitted.\n If workDayStartOn is later than workDayEndBefore, then it assumes that you work the night shift and your work\n hours span midnight. If tickGranularity is \"hour\" or finer, you probably want to set this; if tickGranularity is\n \"day\" or coarser, probably not.</p>\n</div></div></div><div id='cfg-workDays' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-cfg-workDays' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-cfg-workDays' class='name expandable'>workDays</a> : String[]/String<span class=\"signature\"></span></div><div class='description'><div class='short'>List of days of the week that you work on. ...</div><div class='long'><p>List of days of the week that you work on. You can specify this as an Array of Strings\n (['Monday', 'Tuesday', ...]) or a single comma seperated String (\"Monday,Tuesday,...\").</p>\n<p>Defaults to: <code>['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']</code></p></div></div></div></div></div><div class='members-section'><h3 class='members-title icon-method'>Methods</h3><div class='subsection'><div class='definedBy'>Defined By</div><h4 class='members-subtitle'>Instance methods</h3><div id='method-constructor' class='member first-child not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-method-constructor' target='_blank' class='view-source'>view source</a></div><strong class='new-keyword'>new</strong><a href='#!/api/Lumenize.TimeSeriesCalculator-method-constructor' class='name expandable'>Lumenize.TimeSeriesCalculator</a>( <span class='pre'>config</span> ) : <a href=\"#!/api/Lumenize.TimeSeriesCalculator\" rel=\"Lumenize.TimeSeriesCalculator\" class=\"docClass\">Lumenize.TimeSeriesCalculator</a><span class=\"signature\"></span></div><div class='description'><div class='short'> ...</div><div class='long'>\n<h3 class=\"pa\">Parameters</h3><ul><li><span class='pre'>config</span> : Object<div class='sub-desc'>\n</div></li></ul><h3 class='pa'>Returns</h3><ul><li><span class='pre'><a href=\"#!/api/Lumenize.TimeSeriesCalculator\" rel=\"Lumenize.TimeSeriesCalculator\" class=\"docClass\">Lumenize.TimeSeriesCalculator</a></span><div class='sub-desc'>\n</div></li></ul></div></div></div><div id='method-addSnapshots' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-method-addSnapshots' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-method-addSnapshots' class='name expandable'>addSnapshots</a>( <span class='pre'>snapshots, startOnISOString, upToDateISOString</span> ) : TimeInStateCalculator<span class=\"signature\"><span class='chainable' >chainable</span></span></div><div class='description'><div class='short'>Allows you to incrementally add snapshots to this calculator. ...</div><div class='long'><p>Allows you to incrementally add snapshots to this calculator.</p>\n<h3 class=\"pa\">Parameters</h3><ul><li><span class='pre'>snapshots</span> : Object[]<div class='sub-desc'><p>An array of temporal data model snapshots.</p>\n</div></li><li><span class='pre'>startOnISOString</span> : String<div class='sub-desc'><p>A ISOString (e.g. '2012-01-01T12:34:56.789Z') indicating the time start of the period of\n interest. On the second through nth call, this should equal the previous upToDateISOString.</p>\n</div></li><li><span class='pre'>upToDateISOString</span> : String<div class='sub-desc'><p>A ISOString (e.g. '2012-01-01T12:34:56.789Z') indicating the moment just past the time\n period of interest.</p>\n</div></li></ul><h3 class='pa'>Returns</h3><ul><li><span class='pre'>TimeInStateCalculator</span><div class='sub-desc'>\n</div></li></ul></div></div></div><div id='method-getResults' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-method-getResults' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-method-getResults' class='name expandable'>getResults</a>( <span class='pre'></span> ) : Object[]<span class=\"signature\"></span></div><div class='description'><div class='short'>Returns the current state of the calculator ...</div><div class='long'><p>Returns the current state of the calculator</p>\n<h3 class='pa'>Returns</h3><ul><li><span class='pre'>Object[]</span><div class='sub-desc'><p>Returns an Array of Maps like <code>{<uniqueIDField>: <id>, ticks: <ticks>, lastValidTo: <lastValidTo>}</code></p>\n</div></li></ul></div></div></div><div id='method-getStateForSaving' class='member not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-method-getStateForSaving' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSeriesCalculator-method-getStateForSaving' class='name expandable'>getStateForSaving</a>( <span class='pre'>[meta]</span> ) : Object<span class=\"signature\"></span></div><div class='description'><div class='short'>Enables saving the state of this calculator. ...</div><div class='long'><p>Enables saving the state of this calculator. See class documentation for a detailed example.</p>\n<h3 class=\"pa\">Parameters</h3><ul><li><span class='pre'>meta</span> : Object (optional)<div class='sub-desc'><p>An optional parameter that will be added to the serialized output and added to the meta field\n within the deserialized calculator.</p>\n</div></li></ul><h3 class='pa'>Returns</h3><ul><li><span class='pre'>Object</span><div class='sub-desc'><p>Returns an Ojbect representing the state of the calculator. This Object is suitable for saving to\n to an object store. Use the static method <code>newFromSavedState()</code> with this Object as the parameter to reconstitute\n the calculator.</p>\n</div></li></ul></div></div></div></div><div class='subsection'><div class='definedBy'>Defined By</div><h4 class='members-subtitle'>Static methods</h3><div id='static-method-newFromSavedState' class='member first-child not-inherited'><a href='#' class='side expandable'><span> </span></a><div class='title'><div class='meta'><span class='defined-in' rel='Lumenize.TimeSeriesCalculator'>Lumenize.TimeSeriesCalculator</span><br/><a href='source/TimeSeriesCalculator.coffee.html#Lumenize-TimeSeriesCalculator-static-method-newFromSavedState' target='_blank' class='view-source'>view source</a></div><a href='#!/api/Lumenize.TimeSer