From 3a927d3447348c2ddff41ce5e1af14d2f6cc7fc2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 05:09:06 +0000 Subject: [PATCH 01/14] Initial plan From 77a253e87494acc8d47bb30619519345f37e4cf9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 05:05:52 +0000 Subject: [PATCH 02/14] Iteration 5: Implement DataFrame Column-oriented 2-D labeled table (pandas.DataFrame) with: - Three factory methods: fromColumns, fromRecords, from2D - Shape/ndim/size/empty properties - Column access: col, get, has - Slicing: head, tail, iloc, loc - Column mutations: assign, drop, select, rename - Missing-value handling: isna, notna, dropna, fillna - Boolean filter - Aggregations: sum, mean, min, max, std, count, describe - Sorting: sortValues (single/multi-column, mixed dirs), sortIndex - apply (axis=0 column-wise, axis=1 row-wise) - Iteration: items, iteritems, iterrows - Conversion: toRecords, toDict, toArray - Index manipulation: resetIndex, setIndex - toString (aligned text table) Full test suite (35+ test cases) and interactive playground page. Run: https://github.com/githubnext/tsessebe/actions/runs/23971604724 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com> --- playground/dataframe.html | 361 +++++++++++++++++ playground/index.html | 10 +- src/core/frame.ts | 804 ++++++++++++++++++++++++++++++++++++++ src/core/index.ts | 2 + src/index.ts | 2 + tests/core/frame.test.ts | 465 ++++++++++++++++++++++ 6 files changed, 1639 insertions(+), 5 deletions(-) create mode 100644 playground/dataframe.html create mode 100644 src/core/frame.ts create mode 100644 tests/core/frame.test.ts diff --git a/playground/dataframe.html b/playground/dataframe.html new file mode 100644 index 00000000..5b21a9a5 --- /dev/null +++ b/playground/dataframe.html @@ -0,0 +1,361 @@ + + + + + + tsb β€” DataFrame Tutorial + + + +
+
+

πŸ—ƒοΈ DataFrame

+
+ ← Back to tsb Playground +
+
+ +

+ DataFrame is the heart of tsb: a two-dimensional, column-oriented + table where every column is a typed Series. It mirrors pandas.DataFrame + with a fully strict TypeScript API. +

+ + +

Construction

+

Three factory methods cover the most common shapes of input data.

+ +
+
+ fromColumns + most common +
+
import { DataFrame } from "tsb";
+
+const df = DataFrame.fromColumns({
+  name:  ["Alice", "Bob", "Carol"],
+  age:   [30, 25, 35],
+  score: [90, 80, 95],
+});
+
+console.log(df.toString());
+
name age score +----------------------- +0 Alice 30 90 +1 Bob 25 80 +2 Carol 35 95
+
+ +
+
+ fromRecords + array of objects +
+
const df = DataFrame.fromRecords([
+  { city: "London", pop: 9_000_000 },
+  { city: "Tokyo",  pop: 14_000_000 },
+  { city: "NYC",    pop: 8_300_000 },
+]);
+
+df.shape;  // [3, 2]
+
+ +
+
+ from2D + matrix +
+
const df = DataFrame.from2D(
+  [[1, 4], [2, 5], [3, 6]],
+  ["a", "b"],
+);
+
+df.col("a").values;  // [1, 2, 3]
+
+ + +

Shape & Properties

+ +
+
shape / ndim / size / empty
+
df.shape;  // [3, 3]  β€” [rows, cols]
+df.ndim;   // 2
+df.size;   // 9  β€” rows Γ— cols
+df.empty;  // false
+
+df.index;    // RangeIndex(0, 1, 2)
+df.columns;  // Index(["name", "age", "score"])
+
+ + +

Column Access

+ +
+
col / get / has
+
df.col("age");         // Series β€” throws if missing
+df.get("age");         // Series | undefined
+df.has("age");         // true
+df.col("age").mean(); // 30
+
+ + +

Slicing

+ +
+
head / tail / iloc / loc
+
df.head(2);               // first 2 rows
+df.tail(1);               // last row
+df.iloc([0, 2]);          // rows at positions 0 and 2
+df.loc(["Alice"]);         // rows where index label = "Alice"
+
+ + +

Column Mutations

+
All mutation methods return a new DataFrame β€” tsb is immutable.
+ +
+
assign / drop / select / rename
+
// Add or replace a column
+const df2 = df.assign({ bonus: [5, 10, 15] });
+
+// Remove columns
+const df3 = df.drop(["score"]);
+
+// Reorder / subset columns
+const df4 = df.select(["age", "name"]);
+
+// Rename a column
+const df5 = df.rename({ age: "years" });
+
+ + +

Missing Values

+ +
+
isna / notna / dropna / fillna
+
const df = DataFrame.fromColumns({
+  a: [1, null, 3],
+  b: [4, 5, null],
+});
+
+df.isna().toRecords();   // [{ a: false, b: false }, ...]
+df.dropna().shape;       // [1, 2] β€” only row 0 has no nulls
+df.fillna(0).toRecords(); // nulls β†’ 0
+
+ + +

Aggregations

+ +
+
sum / mean / min / max / std / count / describe
+
const df = DataFrame.fromColumns({
+  a: [10, 20, 30],
+  b: [1, 2, 3],
+});
+
+df.sum();   // Series { a: 60, b: 6 }
+df.mean();  // Series { a: 20, b: 2 }
+df.min();   // Series { a: 10, b: 1 }
+df.max();   // Series { a: 30, b: 3 }
+
+df.describe();
+// DataFrame with rows: count, mean, std, min, max
+// columns: a, b
+
+ + +

Sorting

+ +
+
sortValues / sortIndex
+
const df = DataFrame.fromColumns({
+  name:  ["Alice", "Bob", "Carol"],
+  score: [90, 80, 95],
+});
+
+// Sort ascending
+df.sortValues("score").col("name").values;
+// ["Bob", "Alice", "Carol"]
+
+// Sort descending
+df.sortValues("score", false).col("name").values;
+// ["Carol", "Alice", "Bob"]
+
+// Multi-column sort
+df.sortValues(["group", "score"], [true, false]);
+
+ + +

Apply

+ +
+
apply(fn, axis)
+
const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] });
+
+// axis=0: apply to each column
+df.apply((s) => s.sum(), 0);
+// Series { a: 6, b: 15 }
+
+// axis=1: apply to each row
+df.apply((s) => s.sum(), 1);
+// Series [5, 7, 9]
+
+ + +

Iteration

+ +
+
items / iterrows
+
// Iterate over (columnName, Series) pairs
+for (const [name, col] of df.items()) {
+  console.log(name, col.sum());
+}
+
+// Iterate over (rowLabel, rowSeries) pairs
+for (const [label, row] of df.iterrows()) {
+  console.log(label, row.toObject());
+}
+
+ + +

Conversion

+ +
+
toRecords / toDict / toArray
+
const df = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] });
+
+df.toRecords();
+// [{ a: 1, b: 3 }, { a: 2, b: 4 }]
+
+df.toDict();
+// { a: [1, 2], b: [3, 4] }
+
+df.toArray();
+// [[1, 3], [2, 4]]
+
+ + +

Index Manipulation

+ +
+
setIndex / resetIndex
+
const df = DataFrame.fromColumns({
+  name:  ["Alice", "Bob"],
+  score: [90, 80],
+});
+
+// Promote "name" to the row index
+const indexed = df.setIndex("name");
+indexed.index.values;  // ["Alice", "Bob"]
+indexed.columns.values; // ["score"]
+
+// Restore a numeric index
+const reset = indexed.resetIndex();
+reset.columns.values; // ["index", "score"]
+
+ +

+ tsb is a TypeScript port of pandas, built from first principles. + — ← Back to Playground +

+ +
+ + diff --git a/playground/index.html b/playground/index.html index 093b646a..306f67ac 100644 --- a/playground/index.html +++ b/playground/index.html @@ -117,7 +117,7 @@

tsb

- 🚧 Under Construction β€” Foundation Phase + πŸ—οΈ Active Development β€” Core Structures Complete

pandas for TypeScript

tsb is a ground-up TypeScript implementation of the pandas data @@ -137,12 +137,12 @@

πŸ“ Project Foundation

πŸ“Š Series

1-D labeled array β€” the core building block of tsb data structures.

-
⏳ Planned
+
βœ… Complete

πŸ—ƒοΈ DataFrame

-

2-D labeled table with heterogeneous columns, the heart of pandas.

-
⏳ Planned
+

2-D labeled table β€” interactive tutorial. Column-oriented storage, full pandas API.

+
βœ… Complete

🏷️ Index

@@ -152,7 +152,7 @@

🏷️ Index

πŸ”’ Dtypes

Rich dtype system: int/float/bool/string/datetime/category.

-
⏳ Planned
+
βœ… Complete

πŸ“₯ I/O

diff --git a/src/core/frame.ts b/src/core/frame.ts new file mode 100644 index 00000000..4e127d48 --- /dev/null +++ b/src/core/frame.ts @@ -0,0 +1,804 @@ +/** + * DataFrame β€” a two-dimensional labeled table with heterogeneous column dtypes. + * + * Mirrors `pandas.DataFrame`: a column-oriented, 2-D data structure where each + * column is a `Series` sharing a common row `Index

πŸ“Š Series

-

1-D labeled array β€” the core building block of tsb data structures.

+

1-D labeled array β€” Interactive Playground.

βœ… Complete

πŸ—ƒοΈ DataFrame

-

2-D labeled table β€” interactive tutorial. Column-oriented storage, full pandas API.

+

2-D labeled table β€” Interactive Playground. Column-oriented storage, full pandas API.

βœ… Complete
@@ -151,7 +151,7 @@

🏷️ Index

πŸ”’ Dtypes

-

Rich dtype system: int/float/bool/string/datetime/category.

+

Rich dtype system β€” Interactive Playground. int/float/bool/string/datetime/category.

βœ… Complete
From 7ae6798103485029129186b17750bf0a7371d42b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:45:17 +0000 Subject: [PATCH 10/14] Convert groupby.html to interactive playground page Replace the static groupby tutorial with a fully interactive playground using the same dark-theme CSS and playground-block pattern as series.html. Sections cover: basic groupby+sum, mean/min/max, count, std, first/last, size/ngroups/groupKeys, agg with named specs, transform, apply, filter, and a scratch pad. All code examples use `import { ... } from "tsb"` syntax and numeric-only value columns where appropriate (sum/mean/std only include numeric cols). Also updated playground-runtime.js to support both