Initializing playground…
← Back to roadmap
pipe_apply: functional pipeline & apply utilities
← tsb playground
pipe — functional pipeline
TypeScript
▶ Run
↺ Reset
import { pipe } from "tsb"; import { DataFrame } from "tsb"; // Type-safe pipeline with up to 8 steps (return type inferred at each step) const result = pipe( rawData, (df) => df.dropna(), // DataFrame → DataFrame (df) => df.assign({ z: df.col("x").add(df.col("y")).values }), // DataFrame → DataFrame (df) => df.head(10), // DataFrame → DataFrame (df) => df.sum(), // DataFrame → Series ); // Works on any value — not just DataFrames const n = pipe( 3, (x) => x + 1, // 4 (x) => x * x, // 16 (x) => x - 1, // 15 ); // n === 15 console.log(n);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
seriesApply — element-wise apply
TypeScript
▶ Run
↺ Reset
import { seriesApply, seriesTransform } from "tsb"; import { Series } from "tsb"; const temps = new Series({ data: [22.1, 23.5, null, 21.8], name: "temp_C" }); // Element-wise with (value, label, position) context const fahrenheit = seriesApply(temps, (v) => v === null ? null : (v as number) * 9/5 + 32); // [71.78, 74.3, null, 71.24] // Simple scalar transform (no label/position needed) const rounded = seriesTransform(temps, (v) => v === null ? null : Math.round(v as number)); // [22, 24, null, 22] // Using position to build cumulative logic const withPos = seriesApply( new Series({ data: [10, 20, 30] }), (v, _label, pos) => (v as number) + pos * 100, ); // [10, 120, 230] console.log(withPos);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
dataFrameApply — column/row aggregation
TypeScript
▶ Run
↺ Reset
import { dataFrameApply } from "tsb"; import { DataFrame } from "tsb"; const df = DataFrame.fromColumns({ score: [85, 92, 78, 95], weight: [1.0, 1.2, 0.8, 1.5], }); // axis=0 (default): apply fn to each column → Series indexed by column names const colMax = dataFrameApply(df, (col) => col.max() ?? null); // colMax.at("score") === 95 // colMax.at("weight") === 1.5 // axis=1: apply fn to each row → Series indexed by row labels const weightedScore = dataFrameApply( df, (row) => (row.at("score") as number) * (row.at("weight") as number), 1, ); // [85, 110.4, 62.4, 142.5] console.log(weightedScore);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
dataFrameApplyMap — element-wise cell transform
TypeScript
▶ Run
↺ Reset
import { dataFrameApplyMap } from "tsb"; import { DataFrame } from "tsb"; const df = DataFrame.fromColumns({ a: [1, -2, 3], b: [-4, 5, -6], }); // Zero out all negative values (like pandas df.applymap(lambda x: max(x, 0))) const clipped = dataFrameApplyMap(df, (v) => { return typeof v === "number" && v < 0 ? 0 : v; }); // a: [1, 0, 3] // b: [0, 5, 0] // fn receives full context: (value, rowLabel, colName) const tagged = dataFrameApplyMap(df, (v, row, col) => `${col}[${row}]=${v}`); // a: ["a[0]=1", "a[1]=-2", "a[2]=3"] // b: ["b[0]=-4", "b[1]=5", "b[2]=-6"] console.log(tagged);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
dataFrameTransform — column-wise transform
TypeScript
▶ Run
↺ Reset
import { dataFrameTransform, seriesTransform } from "tsb"; import { DataFrame } from "tsb"; const df = DataFrame.fromColumns({ x: [1, 2, 3, 4, 5], y: [10, 20, 30, 40, 50], }); // Z-score normalize each column const normalized = dataFrameTransform(df, (col) => { const mu = col.mean(); const sd = col.std(); return seriesTransform(col, (v) => typeof v === "number" && sd > 0 ? (v - mu) / sd : v ); }); // Bin each column into quartiles const binned = dataFrameTransform(df, (col) => { const q1 = col.quantile(0.25); const q2 = col.quantile(0.5); const q3 = col.quantile(0.75); return seriesTransform(col, (v) => { const n = v as number; if (n <= q1) return "Q1"; if (n <= q2) return "Q2"; if (n <= q3) return "Q3"; return "Q4"; }); }); console.log(binned);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
dataFrameTransformRows — row-wise transform
TypeScript
▶ Run
↺ Reset
import { dataFrameTransformRows } from "tsb"; import { DataFrame } from "tsb"; const df = DataFrame.fromColumns({ first: ["alice", "bob", "carol"], last: ["smith", "jones", "white"], score: [88, 75, 92], }); // Normalise scores relative to the row's position (illustrative) const updated = dataFrameTransformRows(df, (row, _label, pos) => ({ // Only return keys you want to change — others are preserved as-is score: (row["score"] as number) + pos, })); // scores become [88, 76, 94] // first and last columns are unchanged // Full row transformation (compute full name) const withFull = dataFrameTransformRows(df, (row) => ({ first: row["first"], last: row["last"], score: row["score"], full: `${row["first"]} ${row["last"]}`, })); console.log(withFull);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent
Combining pipe + apply
TypeScript
▶ Run
↺ Reset
import { pipe, dataFrameApplyMap, dataFrameTransform, seriesTransform } from "tsb"; import { DataFrame } from "tsb"; const raw = DataFrame.fromColumns({ price: [9.99, -1, 24.5, null, 49.0], quantity: [3, 5, null, 2, 1], }); // Clean → impute → normalise in one readable pipeline const clean = pipe( raw, // 1. zero out invalid prices/quantities (df) => dataFrameApplyMap(df, (v) => v === null || (typeof v === "number" && v < 0) ? 0 : v ), // 2. add derived revenue column (df) => df.assign({ revenue: df.col("price").mul(df.col("quantity")).values, }), // 3. round everything to 2 dp (df) => dataFrameTransform(df, (col) => seriesTransform(col, (v) => typeof v === "number" ? Math.round(v * 100) / 100 : v ) ), ); console.log(clean);
Click ▶ Run to execute
Ctrl+Enter to run · Tab to indent