@bokeh/bokehjs
Version:
Interactive, novel data visualization
155 lines • 5.12 kB
JavaScript
import { isTypedArray, isArray, isNumber } from "./util/types";
import { dict } from "./util/object";
import { union } from "./util/set";
import * as typed_array from "./util/typed_array";
// exported for testing
export function stream_to_column(col, new_col, rollover) {
if (isArray(col) && isArray(new_col)) {
const result = col.concat(new_col);
if (rollover != null && result.length > rollover) {
return result.slice(-rollover);
}
else {
return result;
}
}
const total_len = col.length + new_col.length;
// handle rollover case for typed arrays
if (rollover != null && total_len > rollover) {
const start = total_len - rollover;
const end = col.length;
// resize col if it is shorter than the rollover length
const result = (() => {
if (col.length < rollover) {
const ctor = (() => {
if (isTypedArray(col)) {
return col.constructor;
}
else if (isTypedArray(new_col)) {
return new_col.constructor;
}
else {
throw new Error("unsupported array types");
}
})();
const result = new ctor(rollover);
result.set(col, 0);
return result;
}
else {
return col;
}
})();
// shift values in original col to accommodate new_col
for (let i = start, endi = end; i < endi; i++) {
result[i - start] = result[i];
}
// update end values in col with new_col
for (let i = 0, endi = new_col.length; i < endi; i++) {
result[i + (end - start)] = new_col[i];
}
return result;
}
else {
const col_ = (() => {
if (isTypedArray(col)) {
return col;
}
else if (isTypedArray(new_col)) {
return new new_col.constructor(col);
}
else {
throw new Error("unsupported array types");
}
})();
return typed_array.concat(col_, new_col);
}
}
// exported for testing
export function slice(ind, length) {
let start, step, stop;
if (isNumber(ind)) {
start = ind;
stop = ind + 1;
step = 1;
}
else {
start = ind.start != null ? ind.start : 0;
stop = ind.stop != null ? ind.stop : length;
step = ind.step != null ? ind.step : 1;
}
return [start, stop, step];
}
// exported for testing
export function patch_to_column(col, patch) {
const patched = new Set();
let patched_range = false;
for (const [ind, val] of patch) {
// make the single index case look like the length-3 multi-index case
let shape;
let item;
let index;
let value;
if (isArray(ind)) {
const [i] = ind;
patched.add(i);
shape = col[i].shape;
item = col[i];
value = val;
// this is basically like NumPy's "newaxis", inserting an empty dimension
// makes length 2 and 3 multi-index cases uniform, so that the same code
// can handle both
if (ind.length === 2) {
shape = [1, shape[0]];
index = [ind[0], 0, ind[1]];
}
else {
index = ind;
}
}
else {
if (isNumber(ind)) {
value = [val];
patched.add(ind);
}
else {
value = val;
patched_range = true;
}
index = [0, 0, ind];
shape = [1, col.length];
item = col;
}
// now this one nested loop handles all cases
let flat_index = 0;
const [istart, istop, istep] = slice(index[1], shape[0]);
const [jstart, jstop, jstep] = slice(index[2], shape[1]);
for (let i = istart; i < istop; i += istep) {
for (let j = jstart; j < jstop; j += jstep) {
if (patched_range) {
patched.add(j);
}
item[i * shape[1] + j] = value[flat_index];
flat_index++;
}
}
}
return patched;
}
export function stream_to_columns(old_data, new_data, rollover) {
const data = dict(old_data);
for (const [name, new_column] of dict(new_data)) {
const old_column = data.get(name) ?? [];
data.set(name, stream_to_column(old_column, new_column, rollover));
}
}
export function patch_to_columns(old_data, patches) {
const data = dict(old_data);
let patched = new Set();
for (const [name, patch] of dict(patches)) {
const old_column = data.get(name) ?? [];
patched = union(patched, patch_to_column(old_column, patch)); // XXX: any
}
return patched;
}
//# sourceMappingURL=patching.js.map