Improves TimeSeriesData interface.
authordsc <dsc@wikimedia.org>
Wed, 18 Apr 2012 22:25:59 +0000 (15:25 -0700)
committerdsc <dsc@wikimedia.org>
Wed, 18 Apr 2012 22:52:21 +0000 (15:52 -0700)
lib/dataset/dataset-model.co
lib/dataset/datasource-model.co
lib/util/timeseries/csv.co
lib/util/timeseries/index.co
lib/util/timeseries/timeseries.co

index c6767a3..5d1e863 100644 (file)
@@ -63,31 +63,54 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{
         this
     
     
-    # TODO: toJSON() must ensure columns in MetricList are ordered by index
-    #   ...in theory, MetricList.comparator now does this
+    /* * * *  TimeSeriesData interface  * * * {{{ */
+    
+    /**
+     * @returns {Array<Array>} The reified dataset, materialized to a list of rows including timestamps.
+     */
+    getData: ->
+        _.zip ...@getColumns()
     
-    getDates: ->
-        dates = @metrics.invoke 'getDates'
+    /**
+     * @returns {Array<Array>} List of all columns (including date column).
+     */
+    getColumns: ->
+        [ @getDateColumn() ].concat @getDataColumns()
+    
+    /**
+     * @returns {Array<Date>} The date column.
+     */
+    getDateColumn: ->
+        dates = @metrics.invoke 'getDateColumn'
         maxLen = _.max _.pluck dates, 'length'
         _.find dates, -> it.length is maxLen
     
     /**
-     * @returns {Array} The reified dataset, materialized to an array of data-series arrays.
+     * @returns {Array<Array>} List of all columns except the date column.
      */
-    getData: ->
-        _.zip ...[ @getDates() ].concat @metrics.invoke 'getData'
+    getDataColumns: ->
+        @metrics.invoke 'getData'
     
+    /**
+     * @returns {Array<String>} List of column labels.
+     */
     getLabels: ->
         ['Date'].concat @metrics.pluck 'label'
     
+    # }}}
+    
+    
     newMetric: ->
         index = @metrics.length
         @metrics.add m = new Metric { index, color:ColorBrewer.Spectral[11][index] }
         m
     
-    
     onMetricChange: ->
         @metrics.reset @get 'metrics'
     
+    # TODO: toJSON() must ensure columns in MetricList are ordered by index
+    #   ...in theory, MetricList.comparator now does this
+    
+    
 # }}}
 
index 4b13667..b5b8674 100644 (file)
@@ -123,7 +123,7 @@ DataSource = exports.DataSource = BaseModel.extend do # {{{
         @trigger 'load-error', this, txtStatus, err
     
     
-    getDates: ->
+    getDateColumn: ->
         @data.dateColumn
     
     getData: ->
index f6ad4f1..8e9409e 100644 (file)
@@ -1,6 +1,8 @@
 _  = require 'kraken/util/underscore'
 op = require 'kraken/util/op'
 
+TimeSeriesData = require 'kraken/util/timeseries/timeseries'
+
 
 DASH_PATTERN       = /-/g
 BLANK_LINE_PATTERN = /^(\s*)$/
@@ -48,7 +50,10 @@ class CSVData extends TimeSeriesData
     
     
     /**
-     * Parses a CSV string
+     * Parses and imports a CSV string.
+     * 
+     * @private
+     * @returns {this}
      */
     parse: (@rawData) ->
         if typeof rawData is not 'string'
index e69de29..6fa58c2 100644 (file)
@@ -0,0 +1,2 @@
+exports.TimeSeriesData = require 'kraken/timeseries/timeseries'
+exports.CSVData        = require 'kraken/timeseries/csv'
index d7f46fe..216bc76 100644 (file)
@@ -36,17 +36,52 @@ class TimeSeriesData
         @rebuildDerived()
     
     
+    /* * * *  TimeSeriesData interface  * * * */
+    
+    
+    /**
+     * @returns {Array<Array>} List of rows, each of which includes all columns.
+     */
+    getData: ->
+        @data
+    
+    /**
+     * @returns {Array<Array>} List of all columns (including date column).
+     */
+    getColumns: ->
+        @columns
+    
+    /**
+     * @returns {Array<Date>} The date column.
+     */
+    getDateColumn: ->
+        @dateColumn
+    
+    /**
+     * @returns {Array<Array>} List of all columns except the date column.
+     */
+    getDataColumns: ->
+        @dataColumns
+    
+    /**
+     * @returns {Array<String>} List of column labels.
+     */
+    getLabels: ->
+        @labels
+    
     
     /* * * *  Parsing  * * * */
     
     /**
-     * Stub. Subclass and override to perform preprocessing of the data.
+     * Subclass and override to perform preprocessing of the data.
+     * @private
      */
     parse : (rawData) ->
         this
     
     /**
      * Rebuilds the row-oriented data matrix from the columns.
+     * @private
      */
     rebuildData: ->
         @rows = _.zip ...@columns
@@ -54,11 +89,15 @@ class TimeSeriesData
     
     /**
      * Rebuilds the column-oriented data matrix from the columns.
+     * @private
      */
     rebuildColumns: ->
         @columns = _.zip ...@rows
         @rebuildDerived()
     
+    /**
+     * @private
+     */
     rebuildDerived: ->
         while @transforms.length < @columns.length
             @transforms.push []
@@ -70,27 +109,39 @@ class TimeSeriesData
     
     /* * * *  Data Transformation  * * * */
     
+    /**
+     * Applies the stack of transforms to the data.
+     * 
+     * TODO: Apply transforms in @getData()?
+     * @private
+     * @returns {this}
+     */
     applyTransforms: ->
         for fns, idx of @transforms
             for fn of fns
                 @columns[idx] .= map fn, ctx
         @rebuildData()
     
+    /**
+     * Clears all transforms and restores the original data.
+     * @returns {this}
+     */
     clearTransforms: ->
         @transforms = []
         @rows = _.merge [], @untransformedRows
         @rebuildColumns()
     
     /**
-     * Map a function across the specified columns, one-by-one (in column-major 
-     * order), replacing the data with the mapped result.
+     * Add a data transform to the specified columns. The function is
+     * applied one-by-one (in column-major order), replacing the data
+     * with the mapped result.
      * 
      * @param {Number|Array} indices List one or more column indices to map. Negative
      *  numbers are offset from the end of the columns list.
      * @param {Function} fn Mapping function of the form:
      *  `(single_value, row_idx, column) -> new_value`
-     * @param {Object} [ctx=this] Execution context.
-     * @returns {this} 
+     * @param {Object} [ctx=this] Execution context for the function.
+     * @returns {this}
      */
     addTransform: (indices, fn, ctx=this) ->
         num_cols = @columns.length
@@ -106,6 +157,16 @@ class TimeSeriesData
             @transforms[idx].push fn
         @applyTransforms()
     
+    /**
+     * Add a data transform to all columns except the date column. The function
+     * is applied one-by-one (in column-major order), replacing the data
+     * with the mapped result.
+     * 
+     * @param {Function} fn Mapping function of the form:
+     *  `(single_value, row_idx, column) -> new_value`
+     * @param {Object} [ctx=this] Execution context for the function.
+     * @returns {this}
+     */
     addDataTransform: (fn, ctx=this) ->
         @addTransform _.range(1, @columns.length), fn, ctx
     
@@ -113,8 +174,11 @@ class TimeSeriesData
     
     /* * * *  Misc  * * * */
     
+    /**
+     * @returns {Array<Array>} Deep copy of the data rows (including all columns).
+     */
     toJSON: ->
-        _.merge [], @rows
+        _.merge [], @getData()
     
     toString: ->
         labels = @labels