mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-28 23:58:11 +08:00
* comment * add histogram functionality to Dataframe; port category occupancy to use it * fix binning and create histogram for continous by catagorical * Remove unnecessary logs * Begin work on KDE * Replace broken KDE with working histogram * Define domain and range based on data from histogram * Fix occupancy * Add continuous obs and switch to canvas * Stop value from always rerendering * clear before render * Clear canvas on render * refactor categorical occupancy to canvas * Remove log * simplify finding max * refactor kde->histogram and occupancy->bins * refactor svg -> canvas * rename to occupancy stack * create popup * add metadata and categorical values to popup * fix overflow * remove zeros info * style graph * fix shouldComponentUpdate to look for world changes * change categorySelected -> categoryValueSelected * refactor out render * remove comment * conditionally have bottom border * remove diff comp * remove comments * remove unnecessary mapping * Add comments describing drawing functions * comments * flip comparison order * remove logging * move default to parameter * move defaults to parameter * disable popover if not showing histogram * fix wording and styling * add line break
136 lines
3.4 KiB
JavaScript
136 lines
3.4 KiB
JavaScript
/*
|
|
Dataframe histogram
|
|
*/
|
|
import { isTypedArray } from "./util";
|
|
|
|
function _histogramContinuous(column, bins, min, max) {
|
|
const valBins = new Array(bins).fill(0);
|
|
if (!column) {
|
|
return valBins;
|
|
}
|
|
const binWidth = (max - min) / (bins - 1);
|
|
const colArray = column.asArray();
|
|
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
|
const val = colArray[r];
|
|
if (val <= max && val >= min) {
|
|
// ensure test excludes NaN values
|
|
const valBin = (val - min) / binWidth;
|
|
valBins[valBin] += 1;
|
|
}
|
|
}
|
|
return valBins;
|
|
}
|
|
|
|
function _histogramContinuousBy(column, bins, min, max, by) {
|
|
const byMap = new Map();
|
|
if (!column || !by) {
|
|
return byMap;
|
|
}
|
|
const binWidth = (max - min) / (bins - 1);
|
|
const byArray = by.asArray();
|
|
const colArray = column.asArray();
|
|
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
|
const byBin = byArray[r];
|
|
let valBins = byMap.get(byBin);
|
|
if (valBins === undefined) {
|
|
valBins = new Array(bins).fill(0);
|
|
byMap.set(byBin, valBins);
|
|
}
|
|
const val = colArray[r];
|
|
if (val <= max && val >= min) {
|
|
// ensure test excludes NaN values
|
|
const valBin = (val - min) / binWidth;
|
|
valBins[Math.floor(valBin)] += 1;
|
|
}
|
|
}
|
|
return byMap;
|
|
}
|
|
|
|
function _histogramCategorical(column) {
|
|
const valMap = new Map();
|
|
if (!column) {
|
|
return valMap;
|
|
}
|
|
const colArray = column.asArray();
|
|
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
|
const valBin = colArray[r];
|
|
let curCount = valMap.get(valBin);
|
|
if (curCount === undefined) {
|
|
curCount = 0;
|
|
}
|
|
valMap.set(valBin, curCount + 1);
|
|
}
|
|
return valMap;
|
|
}
|
|
|
|
function _histogramCategoricalBy(column, by) {
|
|
const byMap = new Map();
|
|
if (!column || !by) {
|
|
return byMap;
|
|
}
|
|
const byArray = by.asArray();
|
|
const colArray = column.asArray();
|
|
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
|
const byBin = byArray[r];
|
|
let valMap = byMap.get(byBin);
|
|
if (valMap === undefined) {
|
|
valMap = new Map();
|
|
byMap.set(byBin, valMap);
|
|
}
|
|
const valBin = colArray[r];
|
|
let curCount = valMap.get(valBin);
|
|
if (curCount === undefined) {
|
|
curCount = 0;
|
|
}
|
|
valMap.set(valBin, curCount + 1);
|
|
}
|
|
return byMap;
|
|
}
|
|
|
|
/*
|
|
Count category occupancy. Optional group-by category.
|
|
*/
|
|
export function histogramCategorical(column, by) {
|
|
if (by && isTypedArray(by)) {
|
|
throw new Error("Group by column must be categorical");
|
|
}
|
|
return by
|
|
? _histogramCategoricalBy(column, by)
|
|
: _histogramCategorical(column);
|
|
}
|
|
|
|
/*
|
|
Memoization hash for histogramCategorical()
|
|
*/
|
|
export function hashCategorical(column, by) {
|
|
if (by) {
|
|
return `${column.__id}:${by.__id}`;
|
|
}
|
|
return `${column.__id}:`;
|
|
}
|
|
|
|
/*
|
|
Bin counts for continuous/scalar values, with optional group-by category.
|
|
Values outside domain are ignored.
|
|
*/
|
|
export function histogramContinuous(column, bins = 40, domain = [0, 1], by) {
|
|
if (by && isTypedArray(by)) {
|
|
throw new Error("Group by column must be categorical");
|
|
}
|
|
const [min, max] = domain;
|
|
return by
|
|
? _histogramContinuousBy(column, bins, min, max, by)
|
|
: _histogramContinuous(column, bins, min, max);
|
|
}
|
|
|
|
/*
|
|
Memoization hash for histogramContinuous
|
|
*/
|
|
export function hashContinuous(column, bins = "", domain = [0, 0], by) {
|
|
const [min, max] = domain;
|
|
if (by) {
|
|
return `${column.__id}:${bins}:${min}:${max}:${by.__id}`;
|
|
}
|
|
return `${column.__id}::${bins}:${min}:${max}`;
|
|
}
|