UNPKG

@uwdata/mosaic-plot

Version:

A Mosaic-powered plotting framework based on Observable Plot.

51 lines (43 loc) 1.59 kB
import { toDataColumns } from '@uwdata/mosaic-core'; import { avg, count, div, sqrt, stddev } from '@uwdata/mosaic-sql'; import { erfinv } from './util/stats.js'; import { Mark, markPlotSpec, markQuery } from './Mark.js'; import { handleParam } from './util/handle-param.js'; export class ErrorBarMark extends Mark { constructor(type, source, options) { const dim = type.endsWith('X') ? 'y' : 'x'; const { ci = 0.95, ...channels } = options; super(type, source, channels); this.dim = dim; this.field = this.channelField(dim).field; this.channels = this.channels.filter(c => c.channel !== dim); /** @type {number} */ this.ci = handleParam(ci, value => { return (this.ci = value, this.update()); }); } query(filter = []) { const { channels, field } = this; const fields = channels.concat([ { field: avg(field), as: '__avg__' }, { field: div(stddev(field), sqrt(count(field))), as: '__se__', } ]); return markQuery(fields, this.sourceTable()).where(filter); } queryResult(data) { this.data = toDataColumns(data); return this; } plotSpecs() { const { type, dim, detail, data, ci, channels } = this; // compute confidence interval channels const p = Math.SQRT2 * erfinv(ci); // @ts-expect-error Correct the data column type const { columns: { __avg__: u, __se__: s } } = data; const options = { [`${dim}1`]: u.map((u, i) => u - p * s[i]), [`${dim}2`]: u.map((u, i) => u + p * s[i]) }; return markPlotSpec(type, detail, channels, data, options); } }