<commit_before>'use strict';

var _ = require('../underscore_ext');
var multi = require('../multi');
var {colorScale} = require('../colorScales');
var km = require('../km'); // move km down?
var {RGBToHex} = require('../color_helper');
//var {segmentAverage} = require('./segmented');

var MAX = 10; // max number of groups to display.

function average(data) {
	return data[0].map((v, s) => _.meannull(data.map(p => p[s])));
}

// Currently assumes we have only one field. Right now we only
// handle coded phenotype data, and limit it to one-per-column.
function codedVals({heatmap, colors, fields}, {codes}) {
	var groups = _.range(codes.length),
		colorfn = _.first(colors.map(colorScale));

	return {
		groups: groups,
		colors: groups.map(colorfn),
		labels: codes,
		values: heatmap[0]
	};
}

var saveNull = fn => v => v == null ? v : fn(v);

// XXX Here we include samples that might not have tte and ev, when
// picking the range. Ideal would be to partition not including
// samples w/o survival data.
function partitionedVals3(avg, uniq, colorfn) { //eslint-disable-line no-unused-vars
	let vals = _.without(avg, null, undefined).sort((a, b) => a - b),
		min = _.min(vals),
		max = _.max(vals),
		low = vals[Math.round(vals.length / 3)],
		high = vals[Math.round(2 * vals.length / 3)],
		labelLow = low.toPrecision(4),
		labelHigh = high.toPrecision(4);
	return {
		values: _.map(avg, saveNull(v => v < low ? 'low' :
							(v < high ? 'middle' : 'high'))),
		groups: ['low', 'middle', 'high'],
		colors: [colorfn(min), colorfn((min + max) / 2), colorfn(max)],
		labels: [`< ${labelLow}`, `${labelLow} to ${labelHigh}`, `>= ${labelHigh}`]
	};
}

function partitionedVals2(avg, uniq, colorfn) {
	let vals = _.without(avg, null, undefined).sort((a, b) => a - b),
		min = _.min(vals),
		max = _.max(vals),
		mid = vals[Math.round(vals.length / 2)],
		labelMid = mid.toPrecision(4);
	return {
		values: _.map(avg, saveNull(v => v < mid ? 'low' : 'high')),
		groups: ['low', 'high'],
		colors: [colorfn(min), colorfn(max)],
		labels: [`< ${labelMid}`, `>= ${labelMid}`]
	};
}

function floatVals(avg, uniq, colorfn) {
	return {
		values: avg,
		groups: uniq,
		colors: uniq.map(colorfn),
		labels: uniq.map(v => v.toPrecision(6))
	};
}

// We use data.display so the values reflect normalization settings.
// We average 1st, then see how many unique values there are, then decide
// whether to partition or not.
function floatOrPartitionVals({heatmap, colors}, data, index, samples, splits) {
	var warning = heatmap.length > 1 ? 'gene-level average' : undefined,
		avg = average(heatmap),
		uniq = _.without(_.uniq(avg), null, undefined),
		colorfn = _.first(colors.map(colorScale)),
		partFn = splits === 3 ? partitionedVals3 : partitionedVals2,
		maySplit = uniq.length > MAX;
	return {warning, maySplit, ...(maySplit ? partFn : floatVals)(avg, uniq, colorfn)};
}

function mutationVals(column, data, {bySample}, sortedSamples) {
	var mutCode = _.mapObject(bySample, vs => vs.length > 0 ? 1 : 0);
	return {
		values: _.map(sortedSamples, s => mutCode[s]),
		groups: [0, 1],
		colors: [
			"#ffffff", // white
			"#9467bd"  // dark purple
		],
		labels: [
			'No Mutation',
			'Has Mutation'
		]
	};
}

//var avgOrNull = (rows, xzoom) => _.isEmpty(rows) ? null : segmentAverage(rows, xzoom);

function segmentedVals(column, data, index, samples, splits) {
	var {color} = column,
		warning = 'gene-level average',
		avg = _.getIn(data, ['avg', 'geneValues', 0]),
		bySampleSortAvg = samples.map( sample => avg[sample]),  // ordered by current sample sort
		uniq = _.without(_.uniq(avg), null, undefined),
		scale = colorScale(color),
		[,,,, origin] = color,
		colorfn = v => RGBToHex(...v < origin ? scale.lookup(0, origin - v) : scale.lookup(1, v - origin)),
		partFn = splits === 3 ? partitionedVals3 : partitionedVals2;
	return {warning, maySplit: true, ...partFn(bySampleSortAvg, uniq, colorfn)};
}

var toCoded = multi(fs => fs.valueType);
toCoded.add('float', floatOrPartitionVals);
toCoded.add('coded', codedVals);
toCoded.add('mutation', mutationVals);
toCoded.add('segmented', segmentedVals);

var has = (obj, v) => obj[v] != null;

// Give tte and ev for each subgroup, compute p-value.
// Not sure why we recombine the data after splitting by group.
function pValue(groupsTte, groupsEv) {
	var allTte = _.flatten(groupsTte),<commit_msg>km segmented data window lable change : "gene average" -> "average"<commit_after>'use strict';

var _ = require('../underscore_ext');
var multi = require('../multi');
var {colorScale} = require('../colorScales');
var km = require('../km'); // move km down?
var {RGBToHex} = require('../color_helper');
//var {segmentAverage} = require('./segmented');

var MAX = 10; // max number of groups to display.

function average(data) {
	return data[0].map((v, s) => _.meannull(data.map(p => p[s])));
}

// Currently assumes we have only one field. Right now we only
// handle coded phenotype data, and limit it to one-per-column.
function codedVals({heatmap, colors, fields}, {codes}) {
	var groups = _.range(codes.length),
		colorfn = _.first(colors.map(colorScale));

	return {
		groups: groups,
		colors: groups.map(colorfn),
		labels: codes,
		values: heatmap[0]
	};
}

var saveNull = fn => v => v == null ? v : fn(v);

// XXX Here we include samples that might not have tte and ev, when
// picking the range. Ideal would be to partition not including
// samples w/o survival data.
function partitionedVals3(avg, uniq, colorfn) { //eslint-disable-line no-unused-vars
	let vals = _.without(avg, null, undefined).sort((a, b) => a - b),
		min = _.min(vals),
		max = _.max(vals),
		low = vals[Math.round(vals.length / 3)],
		high = vals[Math.round(2 * vals.length / 3)],
		labelLow = low.toPrecision(4),
		labelHigh = high.toPrecision(4);
	return {
		values: _.map(avg, saveNull(v => v < low ? 'low' :
							(v < high ? 'middle' : 'high'))),
		groups: ['low', 'middle', 'high'],
		colors: [colorfn(min), colorfn((min + max) / 2), colorfn(max)],
		labels: [`< ${labelLow}`, `${labelLow} to ${labelHigh}`, `>= ${labelHigh}`]
	};
}

function partitionedVals2(avg, uniq, colorfn) {
	let vals = _.without(avg, null, undefined).sort((a, b) => a - b),
		min = _.min(vals),
		max = _.max(vals),
		mid = vals[Math.round(vals.length / 2)],
		labelMid = mid.toPrecision(4);
	return {
		values: _.map(avg, saveNull(v => v < mid ? 'low' : 'high')),
		groups: ['low', 'high'],
		colors: [colorfn(min), colorfn(max)],
		labels: [`< ${labelMid}`, `>= ${labelMid}`]
	};
}

function floatVals(avg, uniq, colorfn) {
	return {
		values: avg,
		groups: uniq,
		colors: uniq.map(colorfn),
		labels: uniq.map(v => v.toPrecision(6))
	};
}

// We use data.display so the values reflect normalization settings.
// We average 1st, then see how many unique values there are, then decide
// whether to partition or not.
function floatOrPartitionVals({heatmap, colors}, data, index, samples, splits) {
	var warning = heatmap.length > 1 ? 'gene-level average' : undefined,
		avg = average(heatmap),
		uniq = _.without(_.uniq(avg), null, undefined),
		colorfn = _.first(colors.map(colorScale)),
		partFn = splits === 3 ? partitionedVals3 : partitionedVals2,
		maySplit = uniq.length > MAX;
	return {warning, maySplit, ...(maySplit ? partFn : floatVals)(avg, uniq, colorfn)};
}

function mutationVals(column, data, {bySample}, sortedSamples) {
	var mutCode = _.mapObject(bySample, vs => vs.length > 0 ? 1 : 0);
	return {
		values: _.map(sortedSamples, s => mutCode[s]),
		groups: [0, 1],
		colors: [
			"#ffffff", // white
			"#9467bd"  // dark purple
		],
		labels: [
			'No Mutation',
			'Has Mutation'
		]
	};
}

//var avgOrNull = (rows, xzoom) => _.isEmpty(rows) ? null : segmentAverage(rows, xzoom);

function segmentedVals(column, data, index, samples, splits) {
	var {color} = column,
		warning = 'average',
		avg = _.getIn(data, ['avg', 'geneValues', 0]),
		bySampleSortAvg = samples.map( sample => avg[sample]),  // ordered by current sample sort
		uniq = _.without(_.uniq(avg), null, undefined),
		scale = colorScale(color),
		[,,,, origin] = color,
		colorfn = v => RGBToHex(...v < origin ? scale.lookup(0, origin - v) : scale.lookup(1, v - origin)),
		partFn = splits === 3 ? partitionedVals3 : partitionedVals2;
	return {warning, maySplit: true, ...partFn(bySampleSortAvg, uniq, colorfn)};
}

var toCoded = multi(fs => fs.valueType);
toCoded.add('float', floatOrPartitionVals);
toCoded.add('coded', codedVals);
toCoded.add('mutation', mutationVals);
toCoded.add('segmented', segmentedVals);

var has = (obj, v) => obj[v] != null;

// Give tte and ev for each subgroup, compute p-value.
// Not sure why we recombine the data after splitting by group.
function pValue(groupsTte, groupsEv) {
	var allTte = _.flatten(groupsTte),
{'fraction_non_alphanumeric': 0.1778082504856588, 'fraction_numerical': 0.00799908581876357, 'mean_word_length': 4.012600229095074, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3897766', 'n_tokens_mistral': 3292, 'n_tokens_neox': 3060, 'n_words': 856}