@bokeh/bokehjs
Version:
Interactive, novel data visualization
724 lines • 22.3 kB
JavaScript
import { Signal0 } from "./signaling";
import { logger } from "./logging";
import * as enums from "./enums";
import { RGBAArray, ColorArray } from "./types";
import { includes, repeat } from "./util/array";
import { mul } from "./util/arrayable";
import { to_radians_coeff } from "./util/math";
import { color2rgba, encode_rgba } from "./util/color";
import { to_big_endian } from "./util/platform";
import { isNumber, isTypedArray, isPlainObject } from "./util/types";
import { isValue, isField, isExpr } from "./vectorization";
import { settings } from "./settings";
import { PrefixedStr } from "./kinds";
import { is_NDArray } from "./util/ndarray";
import { diagnostics } from "./diagnostics";
import { unreachable } from "./util/assert";
import { serialize } from "./serialization";
import { Uniform, UniformScalar, UniformVector, ColorUniformVector } from "./uniforms";
export { Uniform, UniformScalar, UniformVector };
function valueToString(value) {
try {
return JSON.stringify(value);
}
catch {
return value.toString();
}
}
export function isSpec(obj) {
return isPlainObject(obj) &&
((obj.value === undefined ? 0 : 1) +
(obj.field === undefined ? 0 : 1) +
(obj.expr === undefined ? 0 : 1) == 1); // garbage JS XOR
}
let global_theme = null;
export function use_theme(theme = null) {
global_theme = theme;
}
export const unset = Symbol("unset");
export class UnsetValueError extends Error {
static __name__ = "UnsetValueError";
}
export class Property {
obj;
attr;
kind;
default_value;
static __name__ = "Property";
__value__;
get syncable() {
return !this.internal;
}
_value = unset;
get is_unset() {
return this._value === unset;
}
_initialized = false;
get initialized() {
return this._initialized;
}
initialize(initial_value = unset) {
if (this._initialized) {
throw new Error("already initialized");
}
let attr_value = unset;
if (initial_value !== unset) {
attr_value = initial_value;
this._dirty = true;
}
else {
const value = this._default_override();
if (value !== unset) {
attr_value = value;
}
else {
let themed = false;
if (global_theme != null) {
const value = global_theme.get(this.obj, this.attr);
if (value !== undefined) {
attr_value = value;
themed = true;
}
}
if (!themed) {
attr_value = this.default_value(this.obj);
}
}
}
if (attr_value !== unset) {
if (this.kind.coerce != null) {
attr_value = this.kind.coerce(attr_value);
}
this._update(attr_value);
}
else {
this._value = unset;
}
this._initialized = true;
}
get_value() {
if (this._value !== unset) {
return this._value;
}
else {
throw new UnsetValueError(`${this.obj}.${this.attr} is unset`);
}
}
set_value(val) {
if (!this._initialized) {
this.initialize(val);
}
else {
this._update(val);
this._dirty = true;
}
diagnostics.report(this);
}
// abstract _intrinsic_default(): T
_default_override() {
return unset;
}
_dirty = false;
get dirty() {
return this._dirty;
}
may_have_refs;
change;
/*readonly*/ internal;
readonly;
constructor(obj, attr, kind, default_value, options = {}) {
this.obj = obj;
this.attr = attr;
this.kind = kind;
this.default_value = default_value;
this.change = new Signal0(this.obj, "change");
this.internal = options.internal ?? false;
this.readonly = options.readonly ?? false;
this.convert = options.convert;
this.on_update = options.on_update;
this.may_have_refs = kind.may_have_refs();
}
//protected abstract _update(attr_value: T): void
_update(attr_value) {
this.validate(attr_value);
if (this.convert != null) {
const converted = this.convert(attr_value, this.obj);
if (converted !== undefined) {
attr_value = converted;
}
}
this._value = attr_value;
this.on_update?.(attr_value, this.obj);
}
toString() {
/*${this.name}*/
return `Prop(${this.obj}.${this.attr}, value: ${valueToString(this._value)})`;
}
// ----- customizable policies
normalize(values) {
return values;
}
validate(value) {
if (!this.valid(value)) {
throw new Error(`${this.obj}.${this.attr} given invalid value: ${valueToString(value)}`);
}
}
valid(value) {
return this.kind.valid(value);
}
}
export class PropertyAlias {
attr;
static __name__ = "PropertyAlias";
constructor(attr) {
this.attr = attr;
}
}
export function Alias(attr) {
return new PropertyAlias(attr);
}
//
// Primitive Properties
//
export class PrimitiveProperty extends Property {
static __name__ = "PrimitiveProperty";
}
export class Font extends PrimitiveProperty {
static __name__ = "Font";
_default_override() {
return settings.dev ? "Bokeh" : unset;
}
}
//
// DataSpec properties
//
export class ScalarSpec extends Property {
static __name__ = "ScalarSpec";
__scalar__;
_value = unset;
get_value() {
if (this._value !== unset) {
return this._value;
}
else {
throw new Error(`${this.obj}.${this.attr} is unset`);
}
}
_update(attr_value) {
if (isSpec(attr_value)) {
this._value = attr_value;
}
else {
this._value = { value: attr_value }; // Value<T>
}
if (isPlainObject(this._value)) {
const { _value } = this;
this._value[serialize] = (serializer) => {
const { value, field, expr, transform, units } = _value;
return serializer.encode_struct((() => {
if (value !== undefined) {
return { type: "value", value, transform, units };
}
else if (field !== undefined) {
return { type: "field", field, transform, units };
}
else {
return { type: "expr", expr, transform, units };
}
})());
};
}
if (isValue(this._value)) {
this.validate(this._value.value);
}
}
materialize(value) {
return value;
}
scalar(value, n) {
return new UniformScalar(value, n);
}
uniform(source) {
const obj = this.get_value();
const n = source.get_length() ?? 1;
if (isExpr(obj)) {
const { expr, transform } = obj;
let result = expr.compute(source);
if (transform != null) {
result = transform.compute(result);
}
result = this.materialize(result);
return this.scalar(result, n);
}
else {
const { value, transform } = obj;
let result = value;
if (transform != null) {
result = transform.compute(result);
}
result = this.materialize(result);
return this.scalar(result, n);
}
}
}
/** @deprecated */
export class AnyScalar extends ScalarSpec {
static __name__ = "AnyScalar";
}
export class DictScalar extends ScalarSpec {
static __name__ = "DictScalar";
}
export class ColorScalar extends ScalarSpec {
static __name__ = "ColorScalar";
}
export class NumberScalar extends ScalarSpec {
static __name__ = "NumberScalar";
}
export class StringScalar extends ScalarSpec {
static __name__ = "StringScalar";
}
export class NullStringScalar extends ScalarSpec {
static __name__ = "NullStringScalar";
}
export class ArrayScalar extends ScalarSpec {
static __name__ = "ArrayScalar";
}
export class LineJoinScalar extends ScalarSpec {
static __name__ = "LineJoinScalar";
}
export class LineCapScalar extends ScalarSpec {
static __name__ = "LineCapScalar";
}
export class LineDashScalar extends ScalarSpec {
static __name__ = "LineDashScalar";
}
export class FontScalar extends ScalarSpec {
static __name__ = "FontScalar";
_default_override() {
return settings.dev ? "Bokeh" : unset;
}
}
export class FontSizeScalar extends ScalarSpec {
static __name__ = "FontSizeScalar";
}
export class FontStyleScalar extends ScalarSpec {
static __name__ = "FontStyleScalar";
}
export class TextAlignScalar extends ScalarSpec {
static __name__ = "TextAlignScalar";
}
export class TextBaselineScalar extends ScalarSpec {
static __name__ = "TextBaselineScalar";
}
export class VectorSpec extends Property {
static __name__ = "VectorSpec";
__vector__;
_value = unset;
get_value() {
if (this._value !== unset) {
return this._value;
}
else {
throw new Error(`${this.obj}.${this.attr} is unset`);
}
}
_update(attr_value) {
if (isSpec(attr_value)) {
this._value = attr_value;
}
else {
this._value = { value: attr_value };
} // Value<T>
if (isPlainObject(this._value)) {
const { _value } = this;
this._value[serialize] = (serializer) => {
const { value, field, expr, transform, units } = _value;
return serializer.encode_struct((() => {
if (value !== undefined) {
return { type: "value", value, transform, units };
}
else if (field !== undefined) {
return { type: "field", field, transform, units };
}
else {
return { type: "expr", expr, transform, units };
}
})());
};
}
if (isValue(this._value)) {
this.validate(this._value.value);
}
}
materialize(value) {
return value;
}
v_materialize(values) {
return values;
}
scalar(value, n) {
return new UniformScalar(value, n);
}
vector(values) {
return new UniformVector(values);
}
uniform(source) {
const obj = this.get_value();
const n = source.get_length() ?? 1;
if (isField(obj)) {
const { field, transform } = obj;
let array = source.get_column(field);
if (array != null) {
if (transform != null) {
array = transform.v_compute(array);
}
array = this.v_materialize(array);
return this.vector(array);
}
else {
const message = `attempted to retrieve property array for nonexistent field '${field}'`;
if (settings.force_fields) {
throw new Error(message);
}
else {
logger.warn(message);
}
return this.scalar(null, n);
}
}
else if (isExpr(obj)) {
const { expr, transform } = obj;
let array = expr.v_compute(source);
if (transform != null) {
array = transform.v_compute(array);
}
array = this.v_materialize(array);
return this.vector(array);
}
else if (isValue(obj)) {
const { value, transform } = obj;
let result = value;
if (transform != null) {
result = transform.compute(result);
}
result = this.materialize(result);
return this.scalar(result, n);
}
else {
unreachable();
}
}
array(source) {
let array;
const length = source.get_length() ?? 1;
const obj = this.get_value();
if (isField(obj)) {
const { field } = obj;
const column = source.get_column(field);
if (column != null) {
array = this.normalize(column);
}
else {
const message = `attempted to retrieve property array for nonexistent field '${field}'`;
if (settings.force_fields) {
throw new Error(message);
}
else {
logger.warn(message);
}
const missing = new Float64Array(length);
missing.fill(NaN);
array = missing;
}
}
else if (isExpr(obj)) {
const { expr } = obj;
array = this.normalize(expr.v_compute(source));
}
else {
const value = this.normalize([obj.value])[0];
if (isNumber(value)) {
const values = new Float64Array(length);
values.fill(value);
array = values;
}
else {
array = repeat(value, length);
}
}
const { transform } = obj;
if (transform != null) {
array = transform.v_compute(array);
}
return array;
}
}
export class DataSpec extends VectorSpec {
static __name__ = "DataSpec";
}
export class UnitsSpec extends VectorSpec {
static __name__ = "UnitsSpec";
_value = unset;
_update(attr_value) {
super._update(attr_value);
if (this._value !== unset) {
const { units } = this._value;
if (units != null && !includes(this.valid_units, units)) {
throw new Error(`units must be one of ${this.valid_units.join(", ")}; got: ${units}`);
}
}
}
get units() {
return this._value !== unset ? this._value.units ?? this.default_units : this.default_units;
}
set units(units) {
if (this._value !== unset) {
if (units != this.default_units) {
this._value.units = units;
}
else {
delete this._value.units;
}
}
else {
throw new Error(`${this.obj}.${this.attr} is unset`);
}
}
}
export class NumberUnitsSpec extends UnitsSpec {
static __name__ = "NumberUnitsSpec";
array(source) {
return new Float64Array(super.array(source));
}
}
export class BaseCoordinateSpec extends DataSpec {
static __name__ = "BaseCoordinateSpec";
}
export class CoordinateSpec extends BaseCoordinateSpec {
static __name__ = "CoordinateSpec";
}
export class CoordinateSeqSpec extends BaseCoordinateSpec {
static __name__ = "CoordinateSeqSpec";
}
export class CoordinateSeqSeqSeqSpec extends BaseCoordinateSpec {
static __name__ = "CoordinateSeqSeqSeqSpec";
}
export class XCoordinateSpec extends CoordinateSpec {
static __name__ = "XCoordinateSpec";
dimension = "x";
}
export class YCoordinateSpec extends CoordinateSpec {
static __name__ = "YCoordinateSpec";
dimension = "y";
}
export class XCoordinateSeqSpec extends CoordinateSeqSpec {
static __name__ = "XCoordinateSeqSpec";
dimension = "x";
}
export class YCoordinateSeqSpec extends CoordinateSeqSpec {
static __name__ = "YCoordinateSeqSpec";
dimension = "y";
}
export class XCoordinateSeqSeqSeqSpec extends CoordinateSeqSeqSeqSpec {
static __name__ = "XCoordinateSeqSeqSeqSpec";
dimension = "x";
}
export class YCoordinateSeqSeqSeqSpec extends CoordinateSeqSeqSeqSpec {
static __name__ = "YCoordinateSeqSeqSeqSpec";
dimension = "y";
}
export class AngleSpec extends NumberUnitsSpec {
static __name__ = "AngleSpec";
get default_units() {
return "rad";
}
get valid_units() {
return [...enums.AngleUnits];
}
materialize(value) {
const coeff = -to_radians_coeff(this.units);
return value * coeff;
}
v_materialize(values) {
const coeff = -to_radians_coeff(this.units);
const result = new Float32Array(values.length);
mul(values, coeff, result); // TODO: in-place?
return result;
}
array(_source) {
throw new Error("not supported");
}
}
export class DistanceSpec extends NumberUnitsSpec {
static __name__ = "DistanceSpec";
get default_units() {
return "data";
}
get valid_units() {
return [...enums.SpatialUnits];
}
}
export class NullDistanceSpec extends DistanceSpec {
static __name__ = "NullDistanceSpec";
materialize(value) {
return value ?? NaN;
}
}
export class BooleanSpec extends DataSpec {
static __name__ = "BooleanSpec";
v_materialize(values) {
return new Uint8Array(values);
}
array(source) {
return new Uint8Array(super.array(source));
}
}
export class IntSpec extends DataSpec {
static __name__ = "IntSpec";
v_materialize(values) {
return isTypedArray(values) ? values : new Int32Array(values);
}
array(source) {
return new Int32Array(super.array(source));
}
}
export class NumberSpec extends DataSpec {
static __name__ = "NumberSpec";
v_materialize(values) {
return isTypedArray(values) ? values : new Float64Array(values);
}
array(source) {
return new Float64Array(super.array(source));
}
}
export class ScreenSizeSpec extends NumberSpec {
static __name__ = "ScreenSizeSpec";
valid(value) {
return isNumber(value) && value >= 0;
}
}
export class ColorSpec extends DataSpec {
static __name__ = "ColorSpec";
materialize(color) {
return encode_rgba(color2rgba(color));
}
v_materialize(colors) {
if (is_NDArray(colors)) {
if (colors.dtype == "uint32" && colors.dimension == 1) {
return to_big_endian(colors);
}
else if (colors.dtype == "uint8" && colors.dimension == 1) {
const [n] = colors.shape;
const array = new RGBAArray(4 * n);
let j = 0;
for (const gray of colors) {
array[j++] = gray;
array[j++] = gray;
array[j++] = gray;
array[j++] = 255;
}
return new ColorArray(array.buffer);
}
else if (colors.dtype == "uint8" && colors.dimension == 2) {
const [n, d] = colors.shape;
if (d == 4) {
return new ColorArray(colors.buffer);
}
else if (d == 3) {
const array = new RGBAArray(4 * n);
for (let i = 0, j = 0; i < d * n;) {
array[j++] = colors[i++];
array[j++] = colors[i++];
array[j++] = colors[i++];
array[j++] = 255;
}
return new ColorArray(array.buffer);
}
}
else if ((colors.dtype == "float32" || colors.dtype == "float64") && colors.dimension == 2) {
const [n, d] = colors.shape;
if (d == 3 || d == 4) {
const array = new RGBAArray(4 * n);
for (let i = 0, j = 0; i < d * n;) {
array[j++] = colors[i++] * 255;
array[j++] = colors[i++] * 255;
array[j++] = colors[i++] * 255;
array[j++] = (d == 3 ? 1 : colors[i++]) * 255;
}
return new ColorArray(array.buffer);
}
}
else if (colors.dtype == "object" && colors.dimension == 1) {
return this._from_css_array(colors);
}
}
else {
return this._from_css_array(colors);
}
throw new Error("invalid color array");
}
_from_css_array(colors) {
const n = colors.length;
const array = new RGBAArray(4 * n);
let j = 0;
for (const color of colors) {
const [r, g, b, a] = color2rgba(color);
array[j++] = r;
array[j++] = g;
array[j++] = b;
array[j++] = a;
}
return new ColorArray(array.buffer);
}
vector(values) {
return new ColorUniformVector(values);
}
}
export class NDArraySpec extends DataSpec {
static __name__ = "NDArraySpec";
}
/** @deprecated */
export class AnySpec extends DataSpec {
static __name__ = "AnySpec";
}
export class StringSpec extends DataSpec {
static __name__ = "StringSpec";
}
export class NullStringSpec extends DataSpec {
static __name__ = "NullStringSpec";
}
export class ArraySpec extends DataSpec {
static __name__ = "ArraySpec";
}
export const ExtMarkerType = PrefixedStr("@");
export class MarkerSpec extends DataSpec {
static __name__ = "MarkerSpec";
}
export class LineJoinSpec extends DataSpec {
static __name__ = "LineJoinSpec";
}
export class LineCapSpec extends DataSpec {
static __name__ = "LineCapSpec";
}
export class LineDashSpec extends DataSpec {
static __name__ = "LineDashSpec";
}
export class FontSpec extends DataSpec {
static __name__ = "FontSpec";
_default_override() {
return settings.dev ? "Bokeh" : unset;
}
}
export class FontSizeSpec extends DataSpec {
static __name__ = "FontSizeSpec";
}
export class FontStyleSpec extends DataSpec {
static __name__ = "FontStyleSpec";
}
export class TextAlignSpec extends DataSpec {
static __name__ = "TextAlignSpec";
}
export class TextBaselineSpec extends DataSpec {
static __name__ = "TextBaselineSpec";
}
//# sourceMappingURL=properties.js.map