← FastSheet

Macro guide

Macros in FastSheet are Python. Copy this page into ChatGPT or Claude, say what you want, and paste the answer into Tools ▸ Macros. In the app, Tools ▸ AI ▸ Copy Macro Guide does the same with your sheet's headers included, and Tools ▸ AI ▸ Ask AI writes the macro for you.

FastSheet macro guide (Tools > Macros). Macros are Python (fastpy): the
standard library works; math, statistics, datetime, re, json and random are
already imported.

CELLS AND RANGES
  Cell("A1")                one cell            Cells(row, col)    1-based, Cells(1, 1) is A1
  Range("A1:C10")           a block             Range("A1", "C10") the same block
  Range("2:13"), Range("D:D")   whole rows / columns (the used part)
  ActiveCell, Selection     the focused cell and the selected range when the macro starts
  Worksheets("Data").Cell("A1"), Worksheets("Data").Range("A1:B5")   another sheet

TABLES BY HEADER NAME (row 1 holds the headers) - the easy way to read data
  for row in Rows(): ...    each data row as a dict: row["Region"], row["Units"]
                            row["Units"] = 5      writes the cell
                            row["Size"] = "Big"   a new header adds a new column at the right
                            row.cell("Units")     its Cell, to format: .fill("#ffff00")
                            row.delete()          deletes the row (when the macro ends)
                            row["_row"]           its row number
  Column("Units")           the cells under that header, a Range: .sum() .values() ...
  for c in Column("Units"):  if c.value != "" and c.value > 20: c.fill("#ffff00")

CELL PROPERTIES (read and write)
  .value      the value (number or text). Setting it stores a constant.
  .formula    the formula text, e.g. cell.formula = "=SUM(A1:A10)". Excel syntax.
  .row .column (1-based)   .address ("B7")   .offset(dr, dc) -> the cell dr rows down, dc right
  .Value / .Formula        VBA-style aliases

FORMATTING (each returns the cell or range, so calls chain)
  .bold() .italic() .underline() .fill("#e8f5e9") .color("#c00000") .align("center")
  .border() .number("cur" | "pct" | "num") .note("text") .hyperlink("https://...")
  .clear() (value and format)   .clear_contents()

RANGES
  for c in Range("A2:A20"): ...      iterate the cells, row by row
  .value = v     put one value in every cell (or a list, cell by cell)
  .formula = "=D2*E2"   fill a block like Excel: F3 gets =D3*E3, F4 =D4*E4 ...
  .values()      the values as a list        .sum() .avg() .min() .max() .count()
  .sort("Units", descending=True)   sort the rows by a column (header, letter or 1, 2 ...)
  .find(v)       the first cell holding v, or None
  .copy("Sheet2!A1")   copy the block (values, formulas, formats) to a cell, here or on another sheet
  .delete()      delete the block's whole rows (when the macro ends; the rows below move up)
  Reads see what the macro wrote before. Empty cells read as "".
  A date cell reads as a Python date (datetime.date): d.strftime("%A"), d.year, d + datetime.timedelta(days=7).
  Writing a date (or "2026-01-02") back keeps it a date; date functions also read such cells: =WEEKDAY(A2).

OUTPUT AND CHARTS
  log(...) / print(...)              write to the macro output box
  Plot("A2:A50", "B2:B50, C2:C50")   X-Y chart; PlotTitle("..."), PlotXLabel("..."), PlotYLabel("...")
  PlotFx("sin(x)/x", -10, 10)        plot a function       PlotPie("A1:A5")   labels left, values in col B
  PlotSurface("A1:F20")  3D surface   Plot3D("A1:C50") 3D scatter (x, y, z columns)

RULES
  - Formulas use Excel syntax ("=A1*2", "=SUM(B2:B9)", "=IF(C2>0,"yes","no")"); 400+ Excel
    functions work, plus AI("prompt", cells...) when AI is on.
  - Inside a .formula only Excel works: cell ranges (E2:E13) and Excel functions.
    Column(), Range(), Rows(), row[...] and Python are macro names, not Excel.
  - Do not wrap a formula in IFERROR to hide a mistake: FastSheet checks each formula.
  - A new column: write its header in row 1 first, then the data rows.
  - A percent is a fraction: '=D2/SUM($D$2:$D$13)', then .number("pct") on those cells.
    Never multiply by 100. A total is a SUM of the data rows, not the last row.
  - Rows copied to another sheet go one under another: keep a counter for the next free row.
  - The macro runs, then FastSheet recalculates and repaints once.
  - Macros script the sheet only: no windows, files dialogs or app UI.

EXAMPLE: totals by region in H1:I5, bold header
  totals = {}
  for row in Rows():
      totals[row["Region"]] = totals.get(row["Region"], 0) + row["Units"]
  Range("H1").value = "Region"; Range("I1").value = "Units"
  Range("H1:I1").bold().fill("#e8eef7")
  r = 2
  for region, total in sorted(totals.items()):
      Cells(r, 8).value = region; Cells(r, 9).value = total; r += 1
  log("wrote", len(totals), "regions")

EXAMPLE: a formula column (live: it follows the data), numbered rows, a copy to Sheet2
  Range("F1").value = "Size"
  Range("F2:F13").formula = '=IF(D2>=20,"Big","Small")'
  Column("No").value = range(1, 13)
  Range("A1:E1").copy("Sheet2!A1")
  n = 2
  for row in Rows():
      if row["Region"] == "West":
          row.copy("Sheet2!A" + str(n)); n += 1

EXAMPLE: a Revenue column, the rows sorted by it, a chart
  Range("F1").value = "Revenue"
  Range("F2:F13").formula = "=D2*E2"
  Range("A1:F13").sort("Revenue", descending=True)
  Plot("E2:E13", "D2:D13"); PlotTitle("Units against Price")