Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add to_csv to view object #149

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 70 additions & 43 deletions packages/perspective/src/js/perspective.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import {Table} from "@apache-arrow/es5-esm/table";
import {TypeVisitor} from "@apache-arrow/es5-esm/visitor";
import {Precision} from "@apache-arrow/es5-esm/type";
import {is_valid_date, DateParser} from "./date_parser.js";

import {formatters} from "./view_formatters";
import {TYPE_AGGREGATES, AGGREGATE_DEFAULTS, TYPE_FILTERS, FILTER_DEFAULTS, SORT_ORDERS} from "./defaults.js";


// IE fix - chrono::steady_clock depends on performance.now() which does not exist in IE workers
if (global.performance === undefined) {
global.performance || {now: Date.now};
Expand Down Expand Up @@ -496,31 +497,7 @@ view.prototype.schema = async function() {
return new_schema;
}

/**
* Serializes this view to JSON data in a standard format.
*
* @async
*
* @param {Object} [options] An optional configuration object.
* @param {number} options.start_row The starting row index from which
* to serialize.
* @param {number} options.end_row The ending row index from which
* to serialize.
* @param {number} options.start_col The starting column index from which
* to serialize.
* @param {number} options.end_col The ending column index from which
* to serialize.
*
* @returns {Promise<Array>} A Promise resolving to An array of Objects
* representing the rows of this {@link view}. If this {@link view} had a
* "row_pivots" config parameter supplied when constructed, each row Object
* will have a "__ROW_PATH__" key, whose value specifies this row's
* aggregated path. If this {@link view} had a "column_pivots" config
* parameter supplied, the keys of this object will be comma-prepended with
* their comma-separated column paths.
*/
view.prototype.to_json = async function(options) {

to_format = async function(options, formatter) {
options = options || {};
let viewport = this.config.viewport ? this.config.viewport : {};
let start_row = options.start_row || (viewport.top ? viewport.top : 0);
Expand All @@ -539,13 +516,7 @@ view.prototype.to_json = async function(options) {
slice = __MODULE__.get_data_two(this.ctx, start_row, end_row, start_col, end_col);
}

let data;

if (options.format && options.format === "table") {
data = {};
} else {
data = [];
}
let data = formatter.initDataValue;

let col_names = [[]].concat(this._column_names());
let row, prev_row;
Expand All @@ -555,38 +526,94 @@ view.prototype.to_json = async function(options) {
let cidx = idx % (end_col - start_col);
if (cidx === 0) {
if (row) {
data.push(row);
formatter.addRow(data, row);
}
row = {};
row = formatter.initRowValue();
ridx ++;
}
if (this.sides() === 0) {
let col_name = col_names[start_col + cidx + 1];
row[col_name] = slice[idx];
formatter.setColumnValue(data, row, col_name, slice[idx])
} else {
if (cidx === 0) {
if (this.config.row_pivot[0] !== 'psp_okey') {
let col_name = "__ROW_PATH__";
let row_path = this.ctx.unity_get_row_path(start_row + ridx);
row[col_name] = [];
formatter.initColumnValue(row, col_name)
for (let i = 0; i < row_path.size(); i++) {
row[col_name].unshift(__MODULE__.scalar_vec_to_val(row_path, i));
const value = __MODULE__.scalar_vec_to_val(row_path, i);
formatter.addColumnValue(data, row, col_name, value);
}
row_path.delete();
}
} else {
let col_name = col_names[start_col + cidx];
row[col_name] = slice[idx];
formatter.setColumnValue(data, row, col_name, slice[idx])
}
}
}

if (row) data.push(row);
if (row) {
formatter.addRow(data, row);
}
if (this.config.row_pivot[0] === 'psp_okey') {
return data.slice(this.config.column_pivot.length);
} else {
return data;
data = data.slice(this.config.column_pivot.length);
}

return formatter.formatData(data)
}
/**
* Serializes this view to JSON data in a standard format.
*
* @async
*
* @param {Object} [options] An optional configuration object.
* @param {number} options.start_row The starting row index from which
* to serialize.
* @param {number} options.end_row The ending row index from which
* to serialize.
* @param {number} options.start_col The starting column index from which
* to serialize.
* @param {number} options.end_col The ending column index from which
* to serialize.
*
* @returns {Promise<Array>} A Promise resolving to An array of Objects
* representing the rows of this {@link view}. If this {@link view} had a
* "row_pivots" config parameter supplied when constructed, each row Object
* will have a "__ROW_PATH__" key, whose value specifies this row's
* aggregated path. If this {@link view} had a "column_pivots" config
* parameter supplied, the keys of this object will be comma-prepended with
* their comma-separated column paths.
*/
view.prototype.to_json = async function(options) {
return to_format(options, formatters.jsonFormatter);
}

/**
* Serializes this view to CSV data in a standard format.
*
* @async
*
* @param {Object} [options] An optional configuration object.
* @param {number} options.start_row The starting row index from which
* to serialize.
* @param {number} options.end_row The ending row index from which
* to serialize.
* @param {number} options.start_col The starting column index from which
* to serialize.
* @param {number} options.end_col The ending column index from which
* to serialize.
*
* @returns {Promise<string>} A Promise resolving to a string in CSV format
* representing the rows of this {@link view}. If this {@link view} had a
* "row_pivots" config parameter supplied when constructed, each row
* will have prepended those values specified by this row's
* aggregated path. If this {@link view} had a "column_pivots" config
* parameter supplied, the keys of this object will be comma-prepended with
* their comma-separated column paths.
*/
view.prototype.to_csv = async function(options) {
return to_format(options, formatters.csvFormatter);
}

/**
Expand Down
32 changes: 32 additions & 0 deletions packages/perspective/src/js/view_formatters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const jsonFormatter = {
initDataValue: () => [],
initRowValue: () => ({}),
initColumnValue: (row, colName) => row[colName] = {},
setColumnValue: (row, colName, value) => row[colName] = [value],
addColumnValue: (row, colName, value) => row[colName].unshift(value),
addRow: (data, row) => data.push(row)
formatData: (data) => data
};

const csvFormatter = {
initDataValue: () => [''],
initRowValue: () => ({}),
initColumnValue: (row, colName) => void,
setColumnValue: (data, row, colName, value) => {
row.push(value);
//append header
data[0] = data[0] + "," + value;
},
addColumnValue: (data, row, colName, value) => {
row.unshift(value);
//prepend header
data[0] = value + "," + data[0];
},
addRow: (data, row) => data.push(row.toString()),
formatData: (data) => data.join('\r\n')
};

export default {
jsonFormatter,
csvFormatter
};