Home Reference Source

libr-bridge/RObject.mjs

"use strict";

// import ref from "ref";
// import refArray from "ref-array";
// import R from "./R";
// import {REALSXP} from "./libR";
// import SEXPWrap from "./SEXPWrap";

// import debug_ from "debug";
// const debug = debug_("libr-bridge:RObject");

/**
 * JavaScript class for R Array type.
 * Please use appropriate deriverd class if possible.
 */
export class RArray extends Array{
	// nothing special. It's only an alias.
}
export class RIntArray extends RArray{
}
export class RBoolArray extends RArray{
}
export class RStrArray extends RArray{
}
export class RRealArray extends RArray{
}
export class RComplexArray extends RArray{
}

/**
 * JavaScript class for R Factor type.
 * A factor has numerical(integer) array with keys.
 */
export class RFactor extends RArray{
	/**
	 * Create a factor.
	 *	@param data {string[]}		String array indicate category, like ["male", "female", "male", ...]
	 *	@param levels {Object}		Category item like ["male", "female"]
	 *	@param ordered {boolean}	If true, this factor is ordered factor (nominal)
	 */
	constructor(data, levels=undefined, ordered=false){

		var mylevels;

		if(!Array.isArray(data)){
			super(data);
		}else{
			if(levels === undefined){
				var s = new Set();
				data.forEach((item) => s.add(item));
				mylevels = Array.from(s);
			}else if(Array.isArray(levels)){
				mylevels = levels;
			}else{
				throw new Error("Unknown label of factor.");
			}
			mylevels = mylevels.filter((v) => v !== undefined);

			// RFactor is 1-origin!
			const values = data.map((v) => mylevels.indexOf(v) + 1)
				.map((v) => v === 0 ? undefined : v); 

			super(...values);
		}
		this.levels = mylevels;
		this.ordered = ordered;

	}
}


/**
 * JavaScript class for R Data Frame type.
 * With a data frame, we can perform data analysis.
 */
export class RDataFrame extends Map{
	/**
	 * Create RDataFrame from object.
	 * e.g.:
	 *	{
	 *		"id": [ 12345, 23456, 34567 ],
	 *		"Name": ["apple", "banana", "orange"],
	 *		"Color": ["red", "yellow", "orange"]
	 *	}
	 *	or, use Map.
	 * Please take care that all items in the data frame have same number of items.
	 */
	constructor(data){

		console.assert(typeof(data) === "object");

		if(!(data instanceof Map)){
			// Object -> Map
			data = new Map(Object.entries(data));
		}

		// check if all members have same length.
		let length_of_item = [];
		for(const item in data){
			length_of_item.push(data[item].length);
		}
		if(length_of_item.some((n) => n !== length_of_item[0])){
			console.log(length_of_item);
			throw new Error("Vector size mismatch.");
		}
		
		super(data);
	}
}



/*
 * vim: filetype=javascript
 */