Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ae08860
Iteration 172: Add na_ops — isna/notna/ffill/bfill
github-actions[bot] Apr 11, 2026
ee0368c
Iteration 174: Add pct_change for Series and DataFrame
github-actions[bot] Apr 11, 2026
75f92fb
Iteration 193: Add idxmin/idxmax for Series and DataFrame
github-actions[bot] Apr 11, 2026
8979d02
Iteration 194: Add astype — dtype coercion for Series and DataFrame
github-actions[bot] Apr 11, 2026
f8eb946
Iteration 195: Add replace — value substitution for Series and DataFrame
github-actions[bot] Apr 11, 2026
4bd979c
Iteration 196: Add where/mask — conditional value selection for Serie…
github-actions[bot] Apr 11, 2026
89c6ca2
Iteration 197: Add diff/shift — discrete difference and value shiftin…
github-actions[bot] Apr 11, 2026
208a15b
Iteration 199: Add duplicated/drop_duplicates and sample
github-actions[bot] Apr 11, 2026
e8d849d
Iteration 203: Add clip_advanced and apply/map
github-actions[bot] Apr 11, 2026
47edcff
Iteration 204: Add cut/qcut — binning continuous data into intervals
github-actions[bot] Apr 11, 2026
413d574
Iteration 205: Add Interval/IntervalIndex — pandas interval type and …
github-actions[bot] Apr 11, 2026
8332b31
Iteration 206: Add getDummies/fromDummies — one-hot encoding
github-actions[bot] Apr 11, 2026
32295bf
Iteration 208: Add crosstab — cross-tabulation of categorical factors
github-actions[bot] Apr 11, 2026
5c17339
Iteration 209: Add pivotTableFull — pivot_table with margins support
github-actions[bot] Apr 11, 2026
d5eb41e
Iteration 210: Add explode — DataFrame/Series list-cell expansion
github-actions[bot] Apr 11, 2026
9703dca
Iteration 212: Add factorize and wide_to_long
github-actions[bot] Apr 11, 2026
26ebe07
Iteration 213: Add interpolate — fill NaN via linear/pad/bfill/nearest
github-actions[bot] Apr 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions playground/apply.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tsb — apply / map</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 860px; margin: 2rem auto; padding: 0 1rem; background: #fafafa; color: #1a1a1a; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; margin-top: 2rem; border-bottom: 1px solid #ddd; padding-bottom: 0.3rem; }
pre { background: #f0f0f0; border-radius: 6px; padding: 1rem; overflow-x: auto; font-size: 0.85rem; }
.demo { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 1rem 1.5rem; margin: 1rem 0; }
button { margin-top: 0.5rem; padding: 0.4rem 1rem; cursor: pointer; border-radius: 4px; border: 1px solid #aaa; background: #f5f5f5; }
button:hover { background: #e8e8e8; }
output { display: block; margin-top: 0.5rem; white-space: pre; font-family: monospace; font-size: 0.85rem; color: #333; }
.label { font-weight: 600; font-size: 0.85rem; color: #555; margin-top: 0.8rem; }
textarea { width: 100%; box-sizing: border-box; font-family: monospace; font-size: 0.85rem; border: 1px solid #ccc; border-radius: 4px; padding: 0.5rem; }
.pandas-equiv { background: #fff8e1; border-left: 3px solid #f9a825; padding: 0.4rem 0.8rem; margin-top: 0.5rem; font-size: 0.8rem; border-radius: 0 4px 4px 0; }
</style>
</head>
<body>
<h1>tsb — <code>apply</code> / <code>map</code></h1>
<p>
Apply functions element-wise or per-column/row.
<code>applySeries</code> maps a function over each element.
<code>mapSeries</code> supports function, <code>Map</code>, or plain-object lookup.
<code>applyDataFrame</code> reduces each column or row to a scalar.
<code>applyExpandDataFrame</code> transforms each column/row into a new Series.
<code>mapDataFrame</code> applies a function element-wise across the whole DataFrame.
</p>

<h2>Core concept</h2>
<pre>// Element-wise apply on a Series
applySeries(s, (v) => Math.sqrt(v as number))

// Map via lookup table
mapSeries(s, { a: 1, b: 2, c: 3 })

// Reduce each column to a scalar
applyDataFrame(df, (col) => col.values.reduce((a, b) => a + b, 0))

// Transform each column, return a DataFrame
applyExpandDataFrame(df, (col) => new Series({ data: col.values.map(v => v * 2), index: col.index }))

// Element-wise map on a DataFrame
mapDataFrame(df, (v) => (v as number) ** 2)</pre>

<div class="pandas-equiv">
<strong>pandas equivalent:</strong><br />
<code>s.apply(func)</code> / <code>s.map(func_or_dict)</code><br />
<code>df.apply(func, axis=0)</code> / <code>df.applymap(func)</code> (now <code>df.map(func)</code>)
</div>

<!-- Demo 1: applySeries -->
<h2>Demo 1 — applySeries element-wise</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const s = new Series({ data: [1, 4, 9, 16] });
applySeries(s, (v) => Math.sqrt(v as number)).values;
// → [1, 2, 3, 4]</pre>
<button onclick="demo1()">Run</button>
<output id="out1"></output>
</div>

<!-- Demo 2: mapSeries with lookup -->
<h2>Demo 2 — mapSeries with object lookup</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const s = new Series({ data: ["a", "b", "c", "d"] });
mapSeries(s, { a: 1, b: 2, c: 3 }).values;
// → [1, 2, 3, null] ("d" not in lookup → null)</pre>
<button onclick="demo2()">Run</button>
<output id="out2"></output>
</div>

<!-- Demo 3: applyDataFrame axis=0 -->
<h2>Demo 3 — applyDataFrame: sum of each column (axis=0)</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [10, 20, 30] });
applyDataFrame(df, (col) =>
(col.values as number[]).reduce((acc, v) => acc + v, 0)
).values;
// → [6, 60] (indexed by column names)</pre>
<button onclick="demo3()">Run</button>
<output id="out3"></output>
</div>

<!-- Demo 4: applyDataFrame axis=1 -->
<h2>Demo 4 — applyDataFrame: sum of each row (axis=1)</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
applyDataFrame(df, (row) =>
(row.values as number[]).reduce((acc, v) => acc + v, 0),
{ axis: 1 }
).values;
// → [5, 7, 9]</pre>
<button onclick="demo4()">Run</button>
<output id="out4"></output>
</div>

<!-- Demo 5: applyExpandDataFrame -->
<h2>Demo 5 — applyExpandDataFrame: double each column</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
applyExpandDataFrame(df, (col) =>
new Series({ data: (col.values as number[]).map(v => v * 2), index: col.index })
);
// a: [2, 4, 6] b: [8, 10, 12]</pre>
<button onclick="demo5()">Run</button>
<output id="out5"></output>
</div>

<!-- Demo 6: mapDataFrame -->
<h2>Demo 6 — mapDataFrame: element-wise square</h2>
<div class="demo">
<div class="label">Code</div>
<pre>const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
mapDataFrame(df, (v) => (v as number) ** 2);
// a: [1, 4, 9] b: [16, 25, 36]</pre>
<button onclick="demo6()">Run</button>
<output id="out6"></output>
</div>

<script type="module">
import {
Series,
DataFrame,
applySeries,
mapSeries,
applyDataFrame,
applyExpandDataFrame,
mapDataFrame,
} from "https://esm.sh/tsb@latest";

window.demo1 = () => {
const s = new Series({ data: [1, 4, 9, 16] });
document.getElementById("out1").textContent =
JSON.stringify(applySeries(s, (v) => Math.sqrt(v)).values);
};

window.demo2 = () => {
const s = new Series({ data: ["a", "b", "c", "d"] });
document.getElementById("out2").textContent =
JSON.stringify(mapSeries(s, { a: 1, b: 2, c: 3 }).values);
};

window.demo3 = () => {
const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [10, 20, 30] });
const result = applyDataFrame(df, (col) =>
col.values.reduce((acc, v) => acc + v, 0),
);
document.getElementById("out3").textContent =
`values: ${JSON.stringify(result.values)}\nindex: ${JSON.stringify([result.index.at(0), result.index.at(1)])}`;
};

window.demo4 = () => {
const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
const result = applyDataFrame(
df,
(row) => row.values.reduce((acc, v) => acc + v, 0),
{ axis: 1 },
);
document.getElementById("out4").textContent = JSON.stringify(result.values);
};

window.demo5 = () => {
const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
const result = applyExpandDataFrame(df, (col) =>
new Series({ data: col.values.map((v) => v * 2), index: col.index }),
);
document.getElementById("out5").textContent =
`a: ${JSON.stringify(result.col("a").values)}\nb: ${JSON.stringify(result.col("b").values)}`;
};

window.demo6 = () => {
const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
const result = mapDataFrame(df, (v) => v ** 2);
document.getElementById("out6").textContent =
`a: ${JSON.stringify(result.col("a").values)}\nb: ${JSON.stringify(result.col("b").values)}`;
};
</script>
</body>
</html>
Loading