- concat(objs, options?) combines Series or DataFrames along either axis.
- It mirrors pandas.concat.
-
1 · Stack Series vertically axis=0
-The default axis stacks rows. Index labels are preserved and concatenated.
-import { Series, concat } from "tsb"; - -const s1 = new Series({ data: [10, 20], index: ["a", "b"] }); -const s2 = new Series({ data: [30, 40], index: ["c", "d"] }); - -concat([s1, s2]);-
| (index) | value |
|---|---|
| a | 10 |
| b | 20 |
| c | 30 |
| d | 40 |
2 · Stack DataFrames vertically — outer join axis=0
+ ← Back to roadmap +🔗 concat — Interactive Playground
- When DataFrames have different columns, join="outer" (default) fills gaps with
- null.
+ concat(objs, options?) combines Series or DataFrames along
+ either axis — mirroring
+ pandas.concat.
+ Edit any code block below and press ▶ Run
+ (or Ctrl+Enter) to execute it live in your browser.
import { DataFrame, concat } from "tsb"; - -const df1 = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] }); -const df2 = DataFrame.fromColumns({ b: [5], c: [6] }); - -concat([df1, df2]); // join="outer" by default-
| (index) | a | b | c |
|---|---|---|---|
| 0 | 1 | 3 | null |
| 1 | 2 | 4 | null |
| 2 | null | 5 | 6 |
1 · Stack Series vertically (axis=0)
+The default axis stacks rows. Index labels are preserved and concatenated.
+import { Series, concat } from "tsb";
+
+const s1 = new Series({ data: [10, 20], index: ["a", "b"] });
+const s2 = new Series({ data: [30, 40], index: ["c", "d"] });
+
+const result = concat([s1, s2]);
+console.log(result.toString());
+ Click ▶ Run to execute+
3 · Stack DataFrames vertically — inner join axis=0
-
- Pass join="inner" to keep only columns shared by all DataFrames.
-
concat([df1, df2], { join: "inner" });-
| (index) | b |
|---|---|
| 0 | 3 |
| 1 | 4 |
| 2 | 5 |
2 · Stack DataFrames vertically (axis=0)
+When DataFrames share the same columns, rows are stacked with the default join="outer". Missing columns are filled with null.
import { DataFrame, concat } from "tsb";
+
+const df1 = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] });
+const df2 = DataFrame.fromColumns({ b: [5], c: [6] });
+
+// join="outer" by default — fills missing columns with null
+const result = concat([df1, df2]);
+console.log(result.toString());
+ Click ▶ Run to execute+
4 · Reset the index
-
- Set ignoreIndex: true to discard incoming labels and get a clean
- RangeIndex.
-
const a = new Series({ data: [1, 2], index: ["x", "y"] }); -const b = new Series({ data: [3], index: ["z"] }); - -concat([a, b], { ignoreIndex: true });-
| (index) | value |
|---|---|
| 0 | 1 |
| 1 | 2 |
| 2 | 3 |
3 · Column-wise concat (axis=1)
+With axis: 1, each Series becomes a column of the result DataFrame.
+ The Series name is used as the column label.
+ DataFrames are merged side by side.
import { Series, DataFrame, concat } from "tsb";
+
+// Series → DataFrame (each Series becomes a column)
+const age = new Series({ data: [25, 30, 35], name: "age" });
+const score = new Series({ data: [88, 92, 79], name: "score" });
+
+console.log("=== Series axis=1 ===");
+console.log(concat([age, score], { axis: 1 }).toString());
+
+// DataFrame side-by-side
+const left = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] });
+const right = DataFrame.fromColumns({ c: [5, 6], d: [7, 8] });
+
+console.log("\n=== DataFrame axis=1 ===");
+console.log(concat([left, right], { axis: 1 }).toString());
+ Click ▶ Run to execute+
5 · Combine Series as columns axis=1
-
- With axis=1, each Series becomes a column of the result DataFrame.
- Series name is used as the column label.
-
const age = new Series({ data: [25, 30, 35], name: "age" }); -const score = new Series({ data: [88, 92, 79], name: "score" }); - -concat([age, score], { axis: 1 });-
| (index) | age | score |
|---|---|---|
| 0 | 25 | 88 |
| 1 | 30 | 92 |
| 2 | 35 | 79 |
4 · Join modes — outer vs inner
+
+ join="outer" (default) keeps the union of labels and fills gaps with null.
+ join="inner" keeps only the intersection.
+
import { Series, DataFrame, concat } from "tsb";
+
+// axis=0: outer vs inner columns
+const df1 = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] });
+const df2 = DataFrame.fromColumns({ b: [5], c: [6] });
+
+console.log("=== axis=0, join='outer' (default) ===");
+console.log(concat([df1, df2]).toString());
+
+console.log("\n=== axis=0, join='inner' (only shared col 'b') ===");
+console.log(concat([df1, df2], { join: "inner" }).toString());
+
+// axis=1: outer vs inner row indexes
+const s1 = new Series({ data: [1, 2], index: ["a", "b"], name: "s1" });
+const s2 = new Series({ data: [3, 4], index: ["b", "c"], name: "s2" });
+
+console.log("\n=== axis=1, join='outer' (union of row indexes) ===");
+console.log(concat([s1, s2], { axis: 1 }).toString());
+
+console.log("\n=== axis=1, join='inner' (only shared row 'b') ===");
+console.log(concat([s1, s2], { axis: 1, join: "inner" }).toString());
+ Click ▶ Run to execute+
6 · Merge DataFrames side by side axis=1
-
- With axis=1, DataFrames are merged column-wise; rows are aligned on
- the row index.
-
const left = DataFrame.fromColumns({ a: [1, 2], b: [3, 4] }); -const right = DataFrame.fromColumns({ c: [5, 6], d: [7, 8] }); - -concat([left, right], { axis: 1 });-
| (index) | a | b | c | d |
|---|---|---|---|---|
| 0 | 1 | 3 | 5 | 7 |
| 1 | 2 | 4 | 6 | 8 |
5 · ignoreIndex — reset to RangeIndex
+Set ignoreIndex: true to discard incoming labels and get a clean 0, 1, 2, … index.
import { Series, DataFrame, concat } from "tsb";
+
+// Series with string indexes → reset to 0, 1, 2
+const a = new Series({ data: [1, 2], index: ["x", "y"] });
+const b = new Series({ data: [3], index: ["z"] });
+
+console.log("=== Series ignoreIndex ===");
+console.log(concat([a, b], { ignoreIndex: true }).toString());
+
+// DataFrame ignoreIndex
+const df1 = DataFrame.fromColumns({ v: [10, 20] });
+const df2 = DataFrame.fromColumns({ v: [30, 40] });
+
+console.log("\n=== DataFrame ignoreIndex ===");
+console.log(concat([df1, df2], { ignoreIndex: true }).toString());
+ Click ▶ Run to execute+
7 · axis=1 with unaligned row indexes
-
- When Series (or DataFrames) have different row-indexes on axis=1,
- the outer join fills missing values with null.
-
const s1 = new Series({ data: [1, 2], index: ["a", "b"], name: "s1" }); -const s2 = new Series({ data: [3, 4], index: ["b", "c"], name: "s2" }); - -concat([s1, s2], { axis: 1 }); // outer (default)-
| (index) | s1 | s2 |
|---|---|---|
| a | 1 | null |
| b | 2 | 3 |
| c | null | 4 |
🧪 Scratch Pad
+Write your own concat code below. All exports from tsb are available:
+ DataFrame, Series, Index, concat, and more.
import { DataFrame, Series, concat } from "tsb";
+
+// Try it! Combine DataFrames in creative ways.
+const q1 = DataFrame.fromColumns({
+ product: ["Widget", "Gadget"],
+ revenue: [1000, 1500],
+});
+
+const q2 = DataFrame.fromColumns({
+ product: ["Widget", "Gadget"],
+ revenue: [1200, 1800],
+});
+
+console.log("=== Q1 + Q2 stacked ===");
+console.log(concat([q1, q2], { ignoreIndex: true }).toString());
+
+// Side-by-side with axis=1
+const names = new Series({ data: ["Widget", "Gadget"], name: "product" });
+const q1rev = new Series({ data: [1000, 1500], name: "q1_rev" });
+const q2rev = new Series({ data: [1200, 1800], name: "q2_rev" });
+
+console.log("\n=== Side-by-side columns ===");
+console.log(concat([names, q1rev, q2rev], { axis: 1 }).toString());
+ Click ▶ Run to execute+
API Reference
-| Option | Type | Default | Description |
|---|---|---|---|
axis | 0 | 1 | "index" | "columns" | 0 | Stack rows (0) or columns (1) |
join | "outer" | "inner" | "outer" | Union or intersection of labels on the other axis |
ignoreIndex | boolean | false | Reset the concatenation axis to a RangeIndex |
Supported combinations
-| Input type | axis=0 result | axis=1 result |
|---|---|---|
| Series[] | Series | DataFrame |
| DataFrame[] | DataFrame | DataFrame |