Migration Guide¶
This guide helps you transition to gaslamp from other approaches: raw GAS sheet operations, plain JavaScript arrays, or Python pandas.
Each section shows the before/after pattern so you can map your existing code to the equivalent gaslamp API.
Coming from Google Sheets (GAS raw API)¶
Before: Manual array processing¶
JavaScript
// Goal: filter rows where price > 1000, then write back to sheet
// Requires: manually tracking header index, looping with index arithmetic
function processData() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
const headers = data[0];
const rows = data.slice(1);
const priceIndex = headers.indexOf("price");
const expensive = [];
for (let i = 0; i < rows.length; i++) {
if (rows[i][priceIndex] > 1000) {
expensive.push(rows[i]);
}
}
sheet.getRange(1, 1, expensive.length + 1, headers.length)
.setValues([headers, ...expensive]);
}
After: BareFrame¶
JavaScript
// Goal: filter rows where price > 1000, then write back to sheet
// Simplified to: load sheet, filter by name, write back
function processData() {
const sheet = SpreadsheetApp.getActiveSheet();
const df = gaslamp.BareFrame.fromSheet(sheet);
const expensive = df.filter(row => row.get("price") > 1000);
expensive.toSheet(sheet);
}
Coming from Raw Arrays / Objects¶
Use the factory that matches your data shape:
JavaScript
// 2D array with header row (e.g. getValues() output)
gaslamp.BareFrame.fromArrays(table);
// Column-oriented object
gaslamp.BareFrame.fromColumns({ name: ['Alice', 'Bob'], age: [25, 30] });
// Row-oriented Maps (converted from plain objects)
const rows = data.map(obj => new Map(Object.entries(obj)));
gaslamp.BareFrame.fromRows(rows);
// GAS Range object (first row as headers)
gaslamp.BareFrame.fromRange(sheet.getRange('A1:C10'));
// GAS Sheet object — reads entire data range
gaslamp.BareFrame.fromSheet(sheet);
Grouping and Data Aggregation¶
Before: Manual extraction¶
JavaScript
// Goal: compute total and average price per category
// Before: manually extract unique categories, loop + reduce per group — twice
function analyzeData(data) {
const categories = [...new Set(data.map(row => row.category))];
const result = {};
categories.forEach(cat => {
const items = data.filter(row => row.category === cat);
const total = items.reduce((sum, row) => sum + row.price, 0);
result[cat] = { sum: total, mean: total / items.length };
});
return result;
}
After: BareFrame.groupBy + agg methods¶
JavaScript
// Goal: compute total and average price per category
// After: groupBy + sum / mean — one call each, no looping
const df = gaslamp.BareFrame.fromColumns({
category: ['Electronics', 'Clothing', 'Electronics'],
price: [500, 80, 1200],
});
const totalByCategory = df.groupBy(['category']).sum(['price']).rename({ price: 'total' });
// category | total
// Electronics | 1700
// Clothing | 80
const avgByCategory = df.groupBy(['category']).mean(['price']).rename({ price: 'mean' });
// category | mean
// Electronics | 850
// Clothing | 80
const summary = totalByCategory.join(avgByCategory, 'category');
// category | total | mean
// Electronics | 1700 | 850
// Clothing | 80 | 80
Coming from Pandas¶
If you are familiar with Python pandas, the API will feel familiar:
Python
# Goal: filter by price, select columns, compute revenue
# Requires: boolean indexing, column assignment, chained operations
import pandas as pd
df = pd.DataFrame({
'product': ['A', 'B', 'C'],
'price': [100, 200, 150],
'quantity': [5, 3, 8],
})
expensive = df[df.price > 120]
summary = expensive[['product', 'price', 'quantity']]
summary['revenue'] = summary.price * summary.quantity
JavaScript
// Goal: filter by price, select columns, compute revenue
// Simplified to: named method chain, no index management
const data = [
['product', 'price', 'quantity'],
['A', 100, 5],
['B', 200, 3],
['C', 150, 8],
];
const df = gaslamp.BareFrame.fromArrays(data);
const expensive = df.filter(row => row.get('price') > 120);
const summary = expensive.select(['product', 'price', 'quantity']);
const withRevenue = summary.withColumn(
'revenue',
row => row.get('price') * row.get('quantity'),
);
Method Equivalents¶
| Operation | Pandas | gaslamp |
|---|---|---|
| Create from 2D array | pd.DataFrame(data, columns=[...]) |
BareFrame.fromArrays(data) |
| Create from dict | pd.DataFrame({'name': [...], 'age': [...]}) |
BareFrame.fromColumns({ name: [...], age: [...] }) |
| Create from records | pd.DataFrame([{'name': 'A', 'age': 1}]) |
BareFrame.fromRows([new Map([['name', 'A'], ['age', 1]])]) |
| Filter rows | df[df.price > 1000] |
df.filter(row => row.get('price') > 1000) |
| Select columns | df[['name', 'price']] |
df.select(['name', 'price']) |
| Remove columns | df.drop(['age'], axis=1) |
df.dropColumns(['age']) |
| Add column | df['total'] = df.a * df.b |
df.withColumn('total', row => row.get('a') * row.get('b')) |
| Sort rows | df.sort_values(['price']) |
df.sortBy(['price']) |
| Sort descending | df.sort_values(['price'], ascending=False) |
df.sortBy(['price'], { ascending: [false] }) |
| Group by | df.groupby('category') |
df.groupBy(['category']) |
| Get column | df['price'].tolist() |
df.getColumn('price') |
| Get row | df.iloc[0] |
df.getRow(0) |
| Row count | len(df) |
df.length |
Common Pitfalls¶
Index-based access¶
JavaScript
// Avoid: manual index management
const nameIndex = headers.indexOf('name');
const name = row[nameIndex];
// Prefer: named access
const name = row.get('name');
Hardcoded column positions¶
JavaScript
// Avoid: brittle column access
const total = row[2] * row[3];
// Prefer: named column access
const total = row.get('price') * row.get('quantity');