Guides

Math channels

Formula channels that behave like columns, an editor preview, and persistence in your backend.

What a channel is

A math channel is a named formula over existing columns. It appears in state.numericColumns and can be plotted by any chart. It is evaluated per dataset, so window functions never cross a dataset boundary.

FamilyFunctions
Arithmetic+ − × ÷, abs, sqrt, exp, log, trigonometry, min, max, round, mod
Conditionalif, nullif, clamp
Windowderivative, integral, movavg, lag, lead
FiltersButterworth lowpass and highpass

FUNCTION_REFERENCE lists every function with its signature and description, ready for an editor’s help panel.

Create and edit

TypeScript
const ch = engine.mathChannels.create({ name: 'speed_kmh', formula: 'speed * 3.6', units: 'km/h' })
engine.mathChannels.update(ch.id, { formula: 'lowpass(speed, 5) * 3.6' })
engine.mathChannels.update(ch.id, { enabled: false })
engine.mathChannels.remove(ch.id)

await engine.mathChannels.importMany(channelsFromYourApi)
const { channels, errors } = await engine.mathChannels.importFile(file)   // a JSON export
const blob = engine.mathChannels.exportBlob()

Editor preview

TypeScript
import { newMathChannel, parseFormula } from '@kymoscope/sdk'

const parsed = parseFormula(input.value)
if (!parsed.ok) showError(parsed.message)

const draft = newMathChannel({ name: 'draft', formula: input.value })
const result = engine.mathChannels.preview(draft)   // null when nothing is plotted
// result.status: 'ok' | 'missing-inputs' | 'parse-error' | 'runtime-error' | 'disabled' | 'references-channel'
// result.values: (number | null)[], result.missingCols, result.message

Storing channels

Without a store, channels live in memory for the session. With a MathChannelStoreAdapter, the engine applies each change locally and calls your store; you push the authoritative list back with sync whenever it changes.

TypeScript
const engine = createEngine({
  mathChannels: {
    create: (channel) => api.createChannel(channel),
    update: (id, patch) => api.updateChannel(id, patch),
    remove: (id) => api.deleteChannel(id),
    importMany: (channels) => api.importChannels(channels),
  },
})

engine.mathChannels.sync(await api.listChannels())
api.onChannelsChanged((list) => engine.mathChannels.sync(list))

A rejected create, update or remove is reported as an error event (the engine call itself has already returned). importMany and importFile await the store and reject if it does.