@bokeh/bokehjs
Version:
Interactive, novel data visualization
156 lines • 5.29 kB
JavaScript
import { logger } from "../../core/logging";
import { SelectionManager } from "../../core/selection_manager";
import { Signal, Signal0 } from "../../core/signaling";
import { assert } from "../../core/util/assert";
import { uniq } from "../../core/util/array";
import { is_NDArray } from "../../core/util/ndarray";
import { keys, values, entries, dict, clone } from "../../core/util/object";
import { isBoolean, isNumber, isString, isArray } from "../../core/util/types";
import { SelectionPolicy, UnionRenderers } from "../selections/interaction_policy";
import { Selection } from "../selections/selection";
import { DataSource } from "./data_source";
export class ColumnarDataSource extends DataSource {
static __name__ = "ColumnarDataSource";
get_array(key) {
const data = dict(this.data);
let column = data.get(key);
if (column == null) {
data.set(key, column = []);
}
else if (!isArray(column)) {
data.set(key, column = Array.from(column));
}
return column;
}
_select;
inspect;
selection_manager = new SelectionManager(this);
constructor(attrs) {
super(attrs);
}
static {
this.define(({ Ref, Dict, Unknown }) => ({
default_values: [Dict(Unknown), {}],
selection_policy: [Ref(SelectionPolicy), () => new UnionRenderers()],
}));
this.internal(({ AnyRef }) => ({
inspected: [AnyRef(), () => new Selection()],
}));
}
initialize() {
super.initialize();
this._select = new Signal0(this, "select");
this.inspect = new Signal(this, "inspect");
}
get inferred_defaults() {
const defaults = new Map();
for (const [name, array] of entries(this.data)) {
const value = (() => {
if (is_NDArray(array)) {
switch (array.dtype) {
case "bool":
return false;
case "uint8":
case "int8":
case "uint16":
case "int16":
case "uint32":
case "int32":
case "float32":
case "float64":
return 0;
case "object":
return null;
}
}
else if (isArray(array) && array.length != 0) {
const [item] = array;
if (item === null) {
return null;
}
else if (isBoolean(item)) {
return false;
}
else if (isNumber(item)) {
return 0;
}
else if (isString(item)) {
return "";
}
else if (isArray(item)) {
return [];
}
}
return undefined;
})();
if (value !== undefined) {
defaults.set(name, value);
}
}
return defaults;
}
get(name) {
const column = this.get_column(name);
assert(column != null, `unknown column '${name}' in ${this}`);
return column;
}
set(name, column) {
dict(this.data).set(name, column);
}
get_column(name) {
const data = dict(this.data);
return data.get(name) ?? null;
}
get_row(index) {
const i = isNumber(index) ? index : index.index;
const result = {};
for (const [column, array] of entries(this.data)) {
result[column] = array[i];
}
return result;
}
columns() {
// return the column names in this data source
return keys(this.data);
}
get_length(soft = true) {
const lengths = uniq(values(this.data).map((v) => is_NDArray(v) ? v.shape[0] : v.length));
switch (lengths.length) {
case 0: {
return null; // XXX: don't guess, treat on case-by-case basis
}
case 1: {
return lengths[0];
}
default: {
const msg = "data source has columns of inconsistent lengths";
if (soft) {
logger.warn(msg);
return lengths.sort()[0];
}
else {
throw new Error(msg);
}
}
}
}
get length() {
return this.get_length() ?? 0;
}
clear() {
const data = clone(this.data);
const proxy = dict(data);
for (const [name, column] of proxy) {
const empty = new column.constructor(0);
proxy.set(name, empty);
}
this.data = data;
}
stream(new_data, rollover, { sync } = {}) {
this.stream_to(this.properties.data, new_data, rollover, { sync });
}
patch(patches, { sync } = {}) {
this.patch_to(this.properties.data, patches, { sync });
}
}
//# sourceMappingURL=columnar_data_source.js.map