Agent API (window.midas)
A JavaScript API for controlling MIDAS programmatically from AI agents, Playwright, or other external tools.
- Overview
- Usage
- Response Format
- Data Model
- Method Reference: status / project / datasets / enums / tabs / models / reports / layout
- Error Codes
Overview
window.midas provides access to MIDAS features from the browser DevTools console or automation tools like Playwright. Use it to manage datasets, tabs, statistical models, reports, and layout.
Availability
- Project screen: All methods are available
- Launcher screen:
help()and the project open/create methods (project.openFile(),project.openUrl(),project.createFromCsv(),project.createFromCsvUrl(),project.openSample(),project.listSamples()) are available. Other methods return aNO_PROJECTerror
When automating with Playwright, open or create a project with one of these methods first, then use the other API methods.
Quick Start for AI Agents
- Call
status()to check the current project state (datasets, tabs, models) - Call
datasets.list()anddatasets.describe(id)to understand the available data - Read Data Model to understand persistence, dataset types, and graph specification
- Refer to Method Reference for the specific operation you need
Usage
From DevTools Console
Open the browser DevTools and call methods directly in the console.
// Check project status
const result = await window.midas.status();
console.log(result.data);
// { datasets: 3, tabs: 2, models: 1, ... }
From Playwright
const result = await page.evaluate(async () => {
return await window.midas.datasets.list();
});
console.log(result.data);
// [{ id: '...', name: 'Iris', rows: 150, columns: 5, type: 'primary' }, ...]
Viewing Help
Call help() to see the list of available method names. Pass a method name to get the description, signature, and example for that method. The returned object also includes a documentation field with the URL of this page for detailed parameter schemas and configuration options.
const help = window.midas.help();
console.log(help.methods); // ["help(methodName?)", "status()", ...]
console.log(help.documentation); // "https://midas-app.org/docs/en/agent-api.md"
const detail = window.midas.help('datasets.query');
console.log(detail.signature);
Response Format
All methods except help() are async and return a unified APIResult<T> response. help() is synchronous and directly returns the method name index, or the detail of the method you name.
// Success
{
success: true,
message: "Found 3 datasets",
data: [...]
}
// Failure
{
success: false,
message: "Dataset not found",
error: {
code: "DATASET_NOT_FOUND",
message: "No dataset with ID 'abc'",
suggestion: "Use datasets.list() to see available datasets"
}
}
A warnings field may be included when the operation succeeds but there are points to note. For example, models.run() stores data preparation warnings in the top-level warnings and model execution warnings in data.warnings.
// Example response with warnings
{
success: true,
message: "Model run completed",
warnings: ["3 rows with missing values were excluded from analysis"],
data: {
runId: '...',
warnings: ["Convergence achieved but Hessian is nearly singular"],
...
}
}
Data Model
Understanding how MIDAS manages data helps you use the API effectively.
Persistence
API operations modify the in-memory project state. Nothing is written to browser storage until you call project.save(). If you reload the page without saving, all changes from that session are lost.
// Modify a dataset's schema
await window.midas.datasets.setColumnSchema('ds_001', { ... });
// At this point, the change exists only in memory
await window.midas.project.save();
// Now written to browser storage
Dataset Types
datasets.list() returns two types of datasets.
Primary — Original data imported from CSV or other files. The data itself is stored in the project file.
Derived — Data created by a transformation such as SQL or cross-tabulation. The project file stores the operation definition (e.g., which SQL was executed) rather than the data itself. The data is a cache and is not included in the project file. Each time the project is opened, derived datasets are recomputed by re-running their operation; those that reference a parent reflect the current parent data. Use parentIds to inspect dependency relationships.
const result = await window.midas.datasets.list();
// [
// { id: 'ds_001', name: 'Sales', type: 'primary', ... },
// { id: 'derived_001', name: 'Monthly Total', type: 'derived', parentIds: ['ds_001'], ... }
// ]
MIDAS also creates temporary Ephemeral Datasets for internal rendering, but these are not included in datasets.list(). Passing an ephemeral dataset by its ID to an API that takes a dataset (such as models.run, datasets.describe/fetch, tabs.open/setDataset, and reports.addDataTable/addGraph) returns an INVALID_INPUT error.
Report Element Lifecycle
A report consists of two parts: Markdown text called content, and elements such as graphs and model summaries. Writing a reference like {{graph_builder:element_001}} in the content renders the corresponding element at that position.
reports.addGraph() and reports.addModelSummary() create an element and insert a reference into the content in one step. reports.removeElement() removes both the element and its content reference.
When a model or dataset is deleted, any report elements that depend on it are automatically removed. No manual cleanup is needed.
Graph Specification
Custom Graph configuration has two layers.
Graph level — Settings that apply to the entire graph: data source, coordinate system (coordinates), faceting (facets), and axis scales (scales). Specified via tabs.configureGraph() or reports.addGraph().
Layer level — A drawing unit that combines a geometric element (geom: points, lines, bars, etc.), statistical transformations (stats), and aesthetic mapping (aes: which columns map to the x-axis, color, size, etc.). Multiple layers can be stacked on a single graph. Add layers with tabs.addGraphLayer(). Each layer can configure its own scale for each aesthetic via scales.
The graph-level globalAes serves as the default for all layers, and each layer's aes can override it.
For full configuration details, see Custom Graph and Custom Graph Reference.
Method Reference
status()
Get the current project status.
const result = await window.midas.status();
// result.data:
// {
// datasets: 3,
// derivedDatasets: 1,
// tabs: 2,
// models: 1,
// reports: 1,
// activeDatasetId: 'ds_001',
// activeTabId: 'tab_001'
// }
activeTabId is the tab at the front of the active pane. It is null when that pane holds no tabs.
project
project.save()
Save the project to browser storage. See Privacy and Security for details on storage.
await window.midas.project.save();
Returns a SANDBOX_MODE error in sandbox mode (projects where persistence is disabled, such as demos or trials).
project.exportMds()
Export the project as an MDS (MIDAS project file format) binary. The exported data is returned as an ArrayBuffer. Exporting requires a signing key. If no key is configured, this returns a NO_SIGNING_KEY error; create a key under Settings > Signing Keys.
const result = await window.midas.project.exportMds();
// result.data: { data: ArrayBuffer, size: 12345, suggestedFilename: 'MyProject.mds' }
project.downloadMds()
Download the project as an MDS file through the browser. Like exportMds(), this returns a NO_SIGNING_KEY error if no signing key is configured.
const result = await window.midas.project.downloadMds();
// result.data: { filename: 'MyProject.mds' }
project.openFile(data, options?)
Open a project from MDS binary data (Uint8Array). Also available on the launcher screen.
const buf = await fetch('/project.mds').then(r => r.arrayBuffer());
const result = await window.midas.project.openFile(new Uint8Array(buf));
// result.data: { projectId: 'project-xxx' }
Options:
sandbox(boolean, default:false) — Whentrue, assigns a new ID and skips saving to browser storageonDuplicate('overwrite'|'copy', default:'overwrite') — Behavior when a project with the same ID already exists in browser storage.'overwrite'replaces the existing project;'copy'assigns a new ID only when a duplicate exists
If the current project has unsaved changes, a confirmation dialog is shown. Returns USER_CANCELLED if the user declines. Signature warnings are not shown as a dialog; they are reported via the warnings array in the response.
project.openUrl(url, options?)
Fetch an MDS file from a URL and open it. Always opens in sandbox mode (not saved to browser storage). Also available on the launcher screen.
const result = await window.midas.project.openUrl('https://example.com/project.mds');
// result.data: { projectId: 'project-xxx' }
Options:
signal(AbortSignal) — Used to abort the fetch
If the current project has unsaved changes, a confirmation dialog is shown. Returns USER_CANCELLED if the user declines. Signature warnings are not shown as a dialog; they are reported via the warnings array in the response.
The same URL validation and security restrictions as datasets.importFromURL() apply. Only HTTP/HTTPS protocols are allowed, and access to cloud metadata endpoints is blocked. Blocked URLs return an INVALID_INPUT error. Warnings are included in warnings for URLs not in the trusted URL list; if "Block connections to untrusted domains" is enabled in settings, untrusted URLs result in an error. See Privacy and Security for details. Returns FETCH_ERROR on both network failures and timeouts.
project.createFromCsv(data, options?)
Create a new project from CSV/TSV binary data (ArrayBuffer or a TypedArray such as Uint8Array). The data is parsed, column types are detected, and the project is saved to browser storage and opened. Also available on the launcher screen.
const csv = new TextEncoder().encode('x,y\n1,2\n3,4');
const result = await window.midas.project.createFromCsv(csv, { name: 'My Data' });
// result.data: { projectId: 'project-xxx' }
Options:
name(string, default:"Untitled") — Dataset name. Also becomes the project namehasHeader(boolean, default:true) — Whether the first row is a headerencoding("utf-8"|"shift_jis"|"euc-jp") — Character encoding. When omitted, encoding is auto-detected from the byte sequence
If the current project has unsaved changes, a confirmation dialog is shown. Returns USER_CANCELLED if the user declines.
project.createFromCsvUrl(url, options?)
Fetch a CSV/TSV file from a URL and create a new project from it. The project is saved to browser storage and opened. Also available on the launcher screen.
const result = await window.midas.project.createFromCsvUrl('https://example.com/data.csv');
// result.data: { projectId: 'project-xxx' }
Options:
name(string) — Dataset name. When omitted, the name is inferred from the URL. Also becomes the project namehasHeader(boolean, default:true) — Whether the first row is a headerencoding("utf-8"|"shift_jis"|"euc-jp") — Character encoding. When omitted, encoding is auto-detected from the byte sequencesignal(AbortSignal) — Used to abort the fetch
If the current project has unsaved changes, a confirmation dialog is shown. Returns USER_CANCELLED if the user declines. The same URL validation and security restrictions as datasets.importFromURL() apply. Returns FETCH_ERROR on network failures and timeouts.
project.openSample(sampleId)
Create a new project from a built-in sample dataset. The project is named Sample: {name}, saved to browser storage, and opened. Also available on the launcher screen.
const result = await window.midas.project.openSample('penguins');
// result.data: { projectId: 'project-xxx' }
Unknown sample ids return an INVALID_INPUT error listing the valid ids. If the current project has unsaved changes, a confirmation dialog is shown. Returns USER_CANCELLED if the user declines, and FETCH_ERROR when fetching the sample data fails.
project.listSamples()
List the built-in sample datasets available to project.openSample(). Also available on the launcher screen.
const result = await window.midas.project.listSamples();
// result.data: { samples: [{ id: 'penguins', name: 'Palmer Penguins', rows: 344, columns: 8,
// purpose: 'Classification, visualization', recommended: true }, ...] }
datasets
datasets.list()
List all datasets in the project.
const result = await window.midas.datasets.list();
// result.data: [{ id, name, rows, columns, type, parentIds? }, ...]
type is either 'primary' (imported data) or 'derived' (created by SQL or other operations). parentIds lists the source dataset IDs a derived dataset depends on; it is empty for a derived dataset created from SQL that references no dataset (such as generate_series). Temporary internal datasets (ephemeral) are not included in the list.
datasets.describe(id)
Get detailed information about a dataset. Accepts a dataset ID or name (case-insensitive).
const result = await window.midas.datasets.describe('Iris');
// result.data:
// {
// id: 'ds_001',
// name: 'Iris',
// type: 'primary',
// rowCount: 150,
// columns: [
// { id: 'col_001', name: 'sepal_length', type: 'float64', scale: 'ratio' },
// { id: 'col_002', name: 'species', type: 'enum', scale: 'nominal', enumName: 'species_enum' },
// ...
// ]
// }
Each column entry contains id, name, and type. scale and enumName are optional. enumName is present when the column type is enum, indicating the associated enum definition name. The internal row number column (Row#) added by MIDAS is not included in columns. The number of columns matches that of datasets.list().
datasets.profile(id)
Get column-level summary statistics for a dataset. Accepts a dataset ID or name (case-insensitive). Returns a NO_DATA error for derived datasets that have not been evaluated yet — such as right after opening a saved project, or right after overwriting a dataset they depend on. Open the dataset in a Data Table tab to evaluate it, or read its rows directly with datasets.query().
const result = await window.midas.datasets.profile('Iris');
// result.data:
// {
// id: 'ds_001',
// name: 'Iris',
// rowCount: 150,
// columns: [
// {
// name: 'sepal_length', type: 'float64', scale: 'ratio',
// nullCount: 0, uniqueCount: 35, nonFiniteCount: 0,
// min: 4.3, max: 7.9, mean: 5.843, median: 5.8, sd: 0.828
// },
// {
// name: 'species', type: 'string', scale: 'nominal',
// nullCount: 0, uniqueCount: 3,
// topValues: [
// { value: 'setosa', count: 50 },
// { value: 'versicolor', count: 50 },
// { value: 'virginica', count: 50 }
// ]
// },
// ...
// ]
// }
Every column includes nullCount and uniqueCount. uniqueCount counts all distinct non-null values, including non-finite values (Infinity, NaN). Numeric columns (int64, float64) additionally include nonFiniteCount (number of Infinity/NaN values), min, max, mean, median, and sd (sample standard deviation, Bessel-corrected with n-1 divisor). Non-finite values are excluded from statistical computations. min through sd are null when no valid numeric values exist. sd is also null when only one valid value exists (n < 2). String and enum columns include topValues (up to 5 most frequent values). The internal row number column (Row#) added by MIDAS is not included in the results.
datasets.query(sql, options?)
Execute a SQL query and return rows (read-only, no dataset creation). SQL follows DuckDB syntax.
const result = await window.midas.datasets.query(
'SELECT species, AVG(sepal_length) as avg_sl FROM Iris GROUP BY species'
);
// result.data: { columns: ['species', 'avg_sl'], totalRows: 3, returnedRows: 3, rows: [...] }
Table names are automatically resolved from dataset names (case-insensitive). For dataset names containing spaces or non-ASCII characters, use double quotes in SQL (e.g., SELECT * FROM "My Dataset"). Use options.limit and options.offset for pagination. When limit is omitted, all rows are returned. Even with SELECT *, the internal row number column (Row#) added by MIDAS is not included in the results. To include row numbers, create an explicit column such as SELECT ROW_NUMBER() OVER ().
If the SQL produces an output column whose name starts with the reserved prefix __midas_ (reserved for MIDAS internal columns), the query returns an INVALID_INPUT error; alias such columns to a non-reserved name.
Only single SELECT statements are accepted; multiple statements separated by semicolons and DML/DDL statements are rejected.
datasets.derive(sql, name, options?)
Execute a SQL query and save the result as a new derived dataset. SQL follows DuckDB syntax.
const result = await window.midas.datasets.derive(
'SELECT species, AVG(sepal_length) as avg_sl FROM Iris GROUP BY species',
'Species Averages'
);
// result.data: { id: 'derived_...', name: 'Species Averages', rowCount: 3, columnCount: 2, overwrote: false }
Table names are automatically resolved from dataset names (case-insensitive). For dataset names containing spaces or non-ASCII characters, use double quotes in SQL (e.g., SELECT * FROM "My Dataset"). The result data is evaluated and held in memory when derive() completes, so it can be read immediately with datasets.fetch() or datasets.profile(). By default, if a derived dataset with the same name exists, it is updated in place. The existing dataset ID is preserved, so references from tabs and dependent datasets remain valid. Caches of derived datasets that depend on the overwritten dataset, along with estimates of dependent models, are invalidated and re-evaluated with the new data on next access. Set options.overwrite to false to prevent overwriting; if a derived dataset with the same name already exists, an error is returned.
If the output name resolves to the same dataset ID as any table referenced in the SQL's FROM / JOIN clauses, or to any ancestor of those referenced tables (a dataset that one of the referenced tables was derived from), the operation would create a dependency cycle and is rejected with a SELF_REFERENCE error (e.g., derive('SELECT species, COUNT(*) FROM Iris GROUP BY species', 'Iris'), or, given a chain Iris → A → B, derive('SELECT * FROM B', 'A')). If the output name matches an existing primary dataset, a NAME_CONFLICT error is returned (primary datasets cannot be overwritten by derived methods). If a derived dataset with the same name was created by a different method (e.g., trying to overwrite an addColumns dataset with derive), an OPERATION_TYPE_MISMATCH error is returned. If a referenced table name or the output name matches multiple existing datasets case-insensitively, an AMBIGUOUS_TABLE_NAME error is returned. If the SQL produces an output column whose name starts with the reserved prefix __midas_ (reserved for MIDAS internal columns), the operation returns an INVALID_INPUT error; alias such columns to a non-reserved name.
When the SQL references multiple tables (via JOIN or subqueries), all referenced datasets are stored as the derived dataset's parentIds. You can inspect them via datasets.list() — each derived dataset entry includes a parentIds array. The Project Lineage tab shows edges from each parent to the derived dataset.
Only single SELECT statements are accepted; multiple statements separated by semicolons and DML/DDL statements are rejected. To bring external data in, use datasets.importFromURL or datasets.importFromBuffer.
datasets.importFromURL(url, options?)
Fetch a CSV/TSV file from an external URL and import it as a dataset. The file is read as a primary dataset with all columns as text, and when type detection finds non-string columns, a derived dataset with column type conversion applied is created automatically. The derived dataset inherits the requested name, and the primary dataset gets a (raw) suffix. If no column needs conversion, only the primary dataset is created.
const result = await window.midas.datasets.importFromURL(
'https://example.com/data.csv'
);
// result.data: { id: 'converted_...', name: 'data', rowCount: 100, columnCount: 5,
// sourceDatasetId: 'dataset_...', sourceDatasetName: 'data (raw)' }
The returned id and name point to the converted dataset — the one to analyze. The raw side is reported as sourceDatasetId and sourceDatasetName (included only when a converted dataset was created). Use the returned name for subsequent datasets.query, graphs, and models.
The options properties are:
name: Dataset name after import. When omitted, the name is inferred from the URL.hasHeader: Whether to treat the first row as a header. Defaults totrue. Whenfalse, columns are namedColumn1,Column2, and so on.encoding: Character encoding ("utf-8","shift_jis","euc-jp"). When omitted, the data is decoded asutf-8; URL imports do not auto-detect encoding.overwrite: Whether to replace an existing dataset with the same name. Defaults tofalse.
If a dataset with the same name (case-insensitive) already exists, the method returns a DATASET_ALREADY_EXISTS error. Set options.overwrite to true to replace the existing dataset in place (ID preserved). When overwriting a pair created by a previous import (converted + raw), both datasets are updated. When the name matches an existing primary dataset and the new data would create a converted dataset, the overwrite is rejected with a NAME_CONFLICT error. The returned columnCount matches the number of columns in the source file. The internal row number column (Row#) added by MIDAS is not included in the count. Column headers that start with the reserved prefix __midas_ (reserved for MIDAS internal columns) are automatically renamed to non-reserved names, and a warning for each renamed header is included in result.warnings.
Parse failures (empty data, empty header row, column count mismatch between rows, URL validation errors, invalid content type, etc.) return an INVALID_INPUT error. Network failures and timeouts return EXECUTION_ERROR. Files exceeding the size warning threshold (default 10 MB, configurable in Settings) are still imported, but a size warning is included in result.warnings.
URL validation and security restrictions apply. Only HTTP/HTTPS protocols are allowed, and access to cloud metadata endpoints is blocked. Warnings are issued for URLs not in the trusted URL list. If "Block connections to untrusted domains" is enabled in settings, untrusted URLs result in an error. See Privacy and Security for details.
datasets.importFromBuffer(data, options?)
Import CSV/TSV data from an ArrayBuffer or TypedArray (Uint8Array, Node.js Buffer, etc.) as a dataset. Use this when you want to load a local CSV from a Playwright test without spinning up an HTTP server.
// Playwright: load a local CSV via page.evaluate
import { readFileSync } from 'fs';
const csvBytes = Array.from(readFileSync('fixtures/sales.csv'));
const result = await page.evaluate(async (bytes) => {
const buffer = new Uint8Array(bytes).buffer;
return await window.midas.datasets.importFromBuffer(buffer, {
name: 'Sales',
});
}, csvBytes);
// result.data: { id: 'converted_...', name: 'Sales', rowCount: 500, columnCount: 7,
// sourceDatasetId: 'dataset_...', sourceDatasetName: 'Sales (raw)' }
data accepts an ArrayBuffer or any ArrayBufferView (Uint8Array, DataView, Node.js Buffer, etc.). The options properties are:
name: Dataset name after import. Defaults to"Untitled".hasHeader: Whether to treat the first row as a header. Defaults totrue.encoding: Character encoding ("utf-8","shift_jis","euc-jp"). When omitted, encoding is auto-detected from the byte sequence.overwrite: Whether to replace an existing dataset with the same name. Defaults tofalse.
The delimiter is auto-detected by PapaParse, so both CSV and TSV can be passed. The returned columnCount matches the number of columns in the source file. The internal row number column (Row#) added by MIDAS is not included in the count.
Datasets are created the same way as importFromURL: a primary dataset with all columns as text (named with a (raw) suffix) and a derived dataset with the detected type conversion applied (inheriting the requested name). The returned id and name point to the converted dataset. If a dataset with the same name (case-insensitive) already exists, the method returns a DATASET_ALREADY_EXISTS error. Set overwrite: true to replace the existing dataset in place (ID preserved). When overwriting a pair created by a previous import, both datasets are updated; when the name matches an existing primary dataset and the new data would create a converted dataset, the overwrite is rejected with a NAME_CONFLICT error. Column headers that start with the reserved prefix __midas_ (reserved for MIDAS internal columns) are automatically renamed to non-reserved names, and a warning for each renamed header is included in result.warnings. Parse failures (empty data, empty header row, column count mismatch between rows, etc.) return an INVALID_INPUT error.
datasets.generateSynthetic(spec, options)
Generate a synthetic dataset from a data generating process (DGP). This is the same feature as the Synthetic Data Generator tab; the tab's page explains the meaning of distributions, expressions, factors, By, and presets. This section covers the API-specific format: the spec JSON, the options, and the error codes. listSyntheticPresets returns ready-made specs for common designs.
// Generate linear-regression data: y = 1 + 2x + noise (error sd = 0.5)
const result = await window.midas.datasets.generateSynthetic(
{
nodes: [
{ name: 'x', dist: { kind: 'normal', mean: { type: 'const', value: 0 }, sd: { type: 'const', value: 1 } } },
{
name: 'y',
dist: {
kind: 'normal',
mean: {
type: 'binary', op: '+',
left: { type: 'const', value: 1 },
right: { type: 'binary', op: '*', left: { type: 'const', value: 2 }, right: { type: 'ref', name: 'x' } },
},
sd: { type: 'const', value: 0.5 },
},
},
],
},
{ name: 'Linear', rows: 200, seed: 42 }
);
// result.data: { id: 'ds_...', name: 'Linear', rowCount: 200, columnCount: 2 }
Each element of spec.nodes is one column of the output dataset. Choose a distribution with dist.kind:
normal(mean, sd) /uniform(min, max) /gamma(shape, scale) /weibull(shape, scale): continuous values (float64 columns)poisson(lambda) /bernoulli(p): non-negative integers (int64 columns)categorical(levels, weights?): string labels (string column).weightsare relative; sampling is uniform whenweightsis omitteddeterministic(value): a noise-free transformed column. When the top level of the expression is a comparison, the column is a 0/1 indicator and becomes an int64 column; otherwise it is float64
The row structure is declared with spec.factors (an array of factors, each { name, levels }), spec.rowsPerCell (the rows per cell, 1 when omitted), and spec.time (the time column, { name, length }). These correspond to the Factors section, Rows per cell, and Time column of the tab; when declared, the row count is implied by them and options.rows can be omitted. A node's by (an array of column names) corresponds to the By field of the tab and samples the column once per group. See the tab's page for the meaning of factors and By.
Distribution parameters are expressions (Expr) in JSON, combining the following nodes.
- Constant:
{ type: 'const', value } - Reference to another column:
{ type: 'ref', name } - Binary operation:
{ type: 'binary', op, left, right }.opis one of the arithmetic operators+-*/and the comparisons<<=>>= - Unary minus:
{ type: 'unary', op: '-', operand } - Function:
{ type: 'call', fn, args }.argsis an array of argument expressions;exp,log,sqrt,logistic, andabstake one argument,pow,min, andmaxtake two - Categorical branch:
{ type: 'cases', over, map, default? } - Past reference:
{ type: 'lag', name, k }.kis a positive integer, usable only with atimedimension
The vocabulary is the same as the tab's text expressions. See Expression Syntax and the survival data example for the values comparisons return, the rules of cases and lag, and how to compose survival data.
The options properties are:
name: Dataset name (required).rows: Number of rows to generate (1 or more, up to 10,000,000). Whenspec.factorsorspec.timeis present, this can be omitted and the row count implied by them is used; when given, it must match that row count. Required when the spec has neither.seed: Random seed (required), a signed 32-bit integer. The samespec,rows, andseedreproduce the same data.overwrite: Whether to replace an existing synthetic dataset with the same name. Defaults tofalse.
The generated data is not saved to the MDS file; the spec and seed are kept in the generation operation, and the data is regenerated from that operation on reload. See Editing a Saved Dataset for the scope of reproducibility and how to freeze values.
If a parameter expression evaluates to a value outside its domain during generation, the method returns INVALID_INPUT at that point and fails. This includes an sd of 0 or below, or a p outside [0, 1]. A linear predictor can be mapped into the range 0 to 1 with logistic and to positive values with exp. With a linear predictor extreme enough to exceed the limits of floating-point arithmetic, however, exp evaluates to 0 or infinity and generation fails.
An invalid spec returns INVALID_INPUT. This covers the following cases.
- Cyclic references or references to undefined columns
- Parameters outside their domain, such as an
sdof 0 or below - A
casesthat covers neither every level nor provides adefault - A
bycolumn whose expression references a column that varies within its groups - A
rowsorseedout of range
If a dataset with the same name already exists and overwrite is false, the method returns DATASET_ALREADY_EXISTS. Only a synthetic dataset created the same way can be replaced with overwrite: true: a name clash with a primary dataset returns NAME_CONFLICT, and a clash with a dataset created by a different method returns OPERATION_TYPE_MISMATCH.
datasets.listSyntheticPresets()
List the built-in synthetic data presets. There are three: multilevel (random intercept), repeated measures (subject × time), and correlated random intercept and slope. They are the same presets the Preset selector of the Synthetic Data Generator tab offers.
const presets = await window.midas.datasets.listSyntheticPresets();
// presets.data: [{ id, label, description, spec, rowCount }, ...]
await window.midas.datasets.generateSynthetic(presets.data[0].spec, { name: 'Schools', seed: 42 });
Each entry carries the following fields.
id: the identifier of the presetlabel: the name shown in the UIdescription: a description of the designspec: the DGP specrowCount: the row count implied by the factors
Pass the spec to generateSynthetic as is, or edit it first. Every preset has factors, so the row count is implied by the spec and options.rows is not needed. See Presets for what each preset generates and the constraints on which models MIDAS can fit to it.
datasets.reloadFromURL(options?)
Re-fetch datasets that were originally imported from a URL and update them with the latest data.
// Re-fetch all URL-sourced datasets
const result = await window.midas.datasets.reloadFromURL();
// result.data: { reloaded: [{ datasetId, name, rowCount, previousRowCount }], failed: [] }
// Re-fetch a specific dataset only
const result = await window.midas.datasets.reloadFromURL({
datasetId: 'primary_abc123',
});
When options.datasetId is specified, only that dataset is re-fetched. When omitted, all primary datasets that were imported from a URL are targeted. If the specified dataset ID does not exist, the method returns a DATASET_NOT_FOUND error. If the dataset exists but was not imported from a URL, it returns an INVALID_INPUT error.
Reload preserves the dataset ID, name, derived datasets, and model bindings. Excluded rows and row comments are cleared. A reload fails if the CSV at the source URL is missing any existing column (removed or renamed) or changes a column's data type. Added columns and reordering are allowed.
result.data.reloaded contains information about successfully re-fetched datasets (datasetId, name, updated rowCount, and previousRowCount). result.data.failed contains information about failed datasets (datasetId, name, sourceUrl, and error). When some datasets fail, success is still true. success is false only when all reloads fail.
datasets.addColumns(datasetId, input)
Add computed columns to a dataset. datasetId accepts a dataset ID or name (case-insensitive). The result is created as a new derived dataset. expression follows DuckDB SQL expression syntax. SQL functions such as CASE WHEN and CAST are supported.
const result = await window.midas.datasets.addColumns('Iris', {
columns: [
{ name: 'bmi', expression: 'weight / (height * height)' }
]
});
// result.data: { id: 'derived_...', name: '...', rowCount: 150, columnCount: 6 }
A column name that starts with the reserved prefix __midas_ (reserved for MIDAS internal columns) returns an INVALID_INPUT error. Use outputName to specify the output dataset name. If a derived dataset with the same name exists, it is updated in place, preserving the existing dataset ID. If outputName resolves to the source datasetId or any of its ancestors (datasets it was derived from), a SELF_REFERENCE error is returned to prevent a dependency cycle; if it collides with an existing primary dataset, a NAME_CONFLICT error is returned. If the existing dataset was created by a different method, an OPERATION_TYPE_MISMATCH error is returned. If outputName matches multiple existing datasets case-insensitively, an AMBIGUOUS_TABLE_NAME error is returned.
datasets.addOrthogonalPolynomials(datasetId, input)
Add orthogonal polynomial columns to a dataset. datasetId accepts a dataset ID or name (case-insensitive). Used as explanatory variables in polynomial regression.
const result = await window.midas.datasets.addOrthogonalPolynomials('Iris', {
column: 'temperature',
degree: 3
});
// result.data: { id: 'derived_...', name: '...', rowCount: 150, columnCount: 8, columnNames: ['temperature_poly1', 'temperature_poly2', 'temperature_poly3'] }
Maximum degree is 30. Use outputName to specify the output dataset name. If outputName resolves to the source datasetId or any of its ancestors (datasets it was derived from), a SELF_REFERENCE error is returned to prevent a dependency cycle; if it collides with an existing primary dataset, a NAME_CONFLICT error is returned. If the existing dataset was created by a different method, an OPERATION_TYPE_MISMATCH error is returned. If outputName matches multiple existing datasets case-insensitively, an AMBIGUOUS_TABLE_NAME error is returned.
datasets.reshapeWideToLong(datasetId, input)
Unpivot (melt) a dataset from wide to long format. datasetId accepts a dataset ID or name (case-insensitive). idColumns/valueColumns accept column names or IDs. Same transformation as the Reshape tab's Wide to Long mode; the result is created as a new derived dataset.
const result = await window.midas.datasets.reshapeWideToLong('Scores', {
idColumns: ['subject'],
valueColumns: ['test1', 'test2', 'test3'],
variableName: 'test',
valueName: 'score'
});
// result.data: { id: 'derived_...', name: 'Scores (Long)', rowCount: 30, columnCount: 3 }
Columns listed in idColumns are copied as-is; each column in valueColumns is expanded into its own row. Row count becomes the source row count times the number of value columns. variableName (default variable) names the column that holds the original column name; valueName (default value) names the column that holds the value. An empty valueColumns, or a variableName/valueName starting with the reserved prefix __midas_ (reserved for MIDAS internal columns), returns an INVALID_INPUT error. Use outputName to specify the output dataset name. If a derived dataset with the same name exists, it is updated in place, preserving the existing dataset ID. If outputName resolves to the source datasetId or any of its ancestors, a SELF_REFERENCE error is returned; if it collides with an existing primary dataset, NAME_CONFLICT; if the existing dataset was created by a different method, OPERATION_TYPE_MISMATCH; if outputName matches multiple existing datasets case-insensitively, AMBIGUOUS_TABLE_NAME.
datasets.reshapeLongToWide(datasetId, input)
Pivot a dataset from long to wide format. datasetId accepts a dataset ID or name (case-insensitive). idColumns/variableColumn/valueColumn accept column names or IDs. Same transformation as the Reshape tab's Long to Wide mode; the result is created as a new derived dataset.
const result = await window.midas.datasets.reshapeLongToWide('Scores', {
idColumns: ['subject'],
variableColumn: 'test',
valueColumn: 'score'
});
// result.data: { id: 'derived_...', name: 'Scores (Wide)', rowCount: 10, columnCount: 4 }
Rows are grouped by the combination of idColumns values; each distinct value of variableColumn becomes a new column, populated from valueColumn. An INVALID_INPUT error is returned if the combination of idColumns values and variableColumn value is not unique (duplicate entries). Use outputName to specify the output dataset name. If a derived dataset with the same name exists, it is updated in place, preserving the existing dataset ID. If outputName resolves to the source datasetId or any of its ancestors, a SELF_REFERENCE error is returned; if it collides with an existing primary dataset, NAME_CONFLICT; if the existing dataset was created by a different method, OPERATION_TYPE_MISMATCH; if outputName matches multiple existing datasets case-insensitively, AMBIGUOUS_TABLE_NAME.
datasets.dummyCode(datasetId, input)
Convert categorical columns to 0/1 dummy variables (treatment coding). datasetId accepts a dataset ID or name (case-insensitive). columns/includedColumns/keepOriginalColumns accept column names or IDs. Same transformation as the Dummy Coding tab; the result is created as a new derived dataset.
const result = await window.midas.datasets.dummyCode('Iris', {
columns: ['species'],
referenceCategories: { species: 'setosa' }
});
// result.data: { id: 'derived_...', name: 'Iris (Dummy Coded)', rowCount: 150, columnCount: 6,
// encodedColumns: [{ column: 'species', referenceCategory: 'setosa', dummyVariableCount: 2 }] }
Each column in columns is converted from k categories into k-1 dummy variables, omitting a reference category (the alphabetically first category by default). Use referenceCategories to set the reference category per column. includedColumns controls which columns pass through to the output (in addition to the dummy-coded columns); when omitted, all source columns except Row # are included, and columns not listed there are dropped. keepOriginalColumns (a subset of columns) keeps the source column in the output alongside its dummy variables. scaleOverrides sets the measurement scale recorded on pass-through columns in the output; the dummy variable columns themselves are always recorded as ratio scale. An INVALID_INPUT error is returned if a column in columns is not a nominal or ordinal, non-boolean column; has fewer than 2 unique values (including when the dataset has no rows); a referenceCategories entry names a category absent from the data; or keepOriginalColumns includes a column not in columns. Use outputName to specify the output dataset name. If a derived dataset with the same name exists, it is updated in place, preserving the existing dataset ID. If outputName resolves to the source datasetId or any of its ancestors, a SELF_REFERENCE error is returned; if it collides with an existing primary dataset, NAME_CONFLICT; if the existing dataset was created by a different method, OPERATION_TYPE_MISMATCH; if outputName matches multiple existing datasets case-insensitively, AMBIGUOUS_TABLE_NAME.
datasets.filter(datasetId, input)
Filter a dataset's rows by an expression, creating a new derived dataset. datasetId accepts a dataset ID or name (case-insensitive). Same transformation as the Filtered Data tab's Save as Dataset; the filter is re-evaluated whenever the source data changes.
const result = await window.midas.datasets.filter('Iris', {
expression: "species = 'setosa' AND sepal_length > 5"
});
// result.data: { id: 'derived_...', name: 'Iris (Filtered)', rowCount: 22, columnCount: 5 }
expression uses the same syntax as the Filtered Data tab's filter input. An empty expression, invalid syntax, or a reference to a column not in the dataset returns an INVALID_INPUT error. Use outputName to specify the output dataset name. If a derived dataset with the same name exists, it is updated in place, preserving the existing dataset ID. If outputName resolves to the source datasetId or any of its ancestors, a SELF_REFERENCE error is returned; if it collides with an existing primary dataset, NAME_CONFLICT; if the existing dataset was created by a different method, OPERATION_TYPE_MISMATCH; if outputName matches multiple existing datasets case-insensitively, AMBIGUOUS_TABLE_NAME.
datasets.setColumnSchema(datasetId, columnId, schema)
Change a column's data type, measurement scale, or enum definition. datasetId accepts a dataset ID or name (case-insensitive).
const result = await window.midas.datasets.setColumnSchema('Iris', 'col_002', {
type: 'enum',
scale: 'nominal',
enumName: 'species_enum'
});
// result.data: { datasetId: 'ds_001', columnId: 'col_002', createdDerived: true, derivedDatasetId: 'derived_...', overwrote: false }
schema accepts type, scale, and enumName. At least one is required. Changing the data type involves SQL type conversion, which creates a new derived dataset. If a derived dataset with the same output name already exists, it is updated in place, preserving the existing dataset ID. If outputName points to the source dataset itself or any of its ancestors (datasets it was derived from), a SELF_REFERENCE error is returned to prevent a dependency cycle; if it collides with an existing primary dataset, a NAME_CONFLICT error is returned. If the existing dataset was created by a different method, an OPERATION_TYPE_MISMATCH error is returned. If outputName matches multiple existing datasets case-insensitively, an AMBIGUOUS_TABLE_NAME error is returned. Changing only the measurement scale updates metadata in place without creating a derived dataset.
When converting to enum type, all column values must be in the enum definition or NULL. If out-of-range values are present, the call is rejected with ENUM_VALUE_MISMATCH. Use Convert Column Types first to null-out or exclude unwanted values, or use enums.update to add the missing values to the enum definition.
datasets.rename(id, newName)
Renames a dataset. Accepts a dataset ID or a dataset name (case-insensitive).
const result = await window.midas.datasets.rename('Iris', 'Iris (raw)');
// result.data: { datasetId: 'ds_001', previousName: 'Iris', name: 'Iris (raw)' }
SQL queries of derived datasets that reference this dataset are rewritten to the new name. Dataset names are compared without case, so iris is rejected while Iris exists.
datasets.renameColumn(datasetId, columnId, newName)
Renames a column. datasetId accepts a dataset ID or name, and columnId accepts a column ID or name.
const result = await window.midas.datasets.renameColumn('Iris', 'sepal_length', 'sepal length (cm)');
// result.data: { datasetId: 'ds_001', columnId: 'col_001', previousName: 'sepal_length', name: 'sepal length (cm)' }
A column name is also its SQL identifier. SQL queries written against the old name stop matching, so update them yourself after renaming. Renaming invalidates the caches of derived datasets, models, and report elements that depend on this dataset, and they are recomputed.
Column names of a derived dataset are rebuilt from its operation on every evaluation. Renaming a column of a derived dataset therefore reverts once the project is reopened. The typed dataset that a CSV import creates is one of these, so rename the <name> (raw) side, which holds the imported values, when the new name has to survive.
datasets.download(id, options)
Downloads a dataset as a CSV, TSV, or JSON file, the same way the Export button in the data table does. Accepts a dataset ID or a dataset name (case-insensitive).
const result = await window.midas.datasets.download('Iris', {
format: 'csv',
fileName: 'iris-export',
encoding: 'shift_jis'
});
// result.data: {
// datasetId: 'ds_001', fileName: 'iris-export.csv', format: 'csv',
// rowCount: 150, unrepresentableCharacters: []
// }
format is required. When fileName is omitted the dataset name is used, and the extension is replaced to match the format. includeHeaders defaults to true and is ignored for JSON. CSV and TSV accept encoding (utf-8, shift_jis, euc-jp) and, for UTF-8, bom. JSON is always UTF-8. Characters the encoding cannot represent are replaced with HTML character references (such as é). Replaced characters are listed in unrepresentableCharacters, at most the first 10 distinct ones, and the warning text carries the total count.
Filters, sorting, and row selection applied in a data table tab are view state rather than part of the dataset, so they cannot be passed here. Narrow the rows with datasets.derive() first when you need a subset.
datasets.create(name, options)
Creates a dataset with the given columns. Every cell starts as a missing value.
const result = await window.midas.datasets.create('Measurements', {
columns: [
{ name: 'subject', type: 'string' },
{ name: 'score', type: 'float64', scale: 'ratio' }
],
rowCount: 3
});
// result.data: { datasetId: 'manual_...', name: 'Measurements', columnIds: ['col_0_...', 'col_1_...'], rowCount: 3 }
When scale is omitted the measurement scale is inferred from the column type. Write values with datasets.setCellValues(). A column type is one of string, int64, float64, boolean, date, and datetime. Create an enum column as string, then convert it with datasets.setColumnSchema(), passing enumName.
datasets.setCellValues(id, values)
Sets individual cell values in a dataset that holds its own values. Accepts a dataset ID or a dataset name (case-insensitive).
const result = await window.midas.datasets.setCellValues('Measurements', [
{ row: 0, column: 'subject', value: 'A' },
{ row: 0, column: 'score', value: 12.5 }
]);
// result.data: { datasetId: 'manual_...', updatedCells: 2 }
row is a 0-based row position and column is a column ID or name. Written values cannot be undone. The dataset keeps no record of the previous values, so the original data is no longer recoverable from the project. Derived datasets, models, and report elements that depend on this dataset are invalidated and recomputed.
Editing cells in the data table converts the text you type into the column type, but this API does not convert values. value has to match the data type of the column. null writes a missing value into a column of any type. All input is validated before anything is written, so a single invalid entry leaves the dataset untouched.
Values in a derived dataset come from its operation, so they cannot be set cell by cell. The typed dataset that a CSV import creates is one of these, so address the <name> (raw) side, which holds the raw values, to correct an imported value.
datasets.remove(id)
Remove a dataset from the project. Accepts a dataset ID or name (case-insensitive). Closes any open tabs that reference the dataset, then cascade-deletes all dependent derived datasets and models.
await window.midas.datasets.remove('Iris');
datasets.fetch(id, options?)
Fetch row data from a dataset without side effects. Accepts a dataset ID or name (case-insensitive).
const result = await window.midas.datasets.fetch('Iris', { limit: 5, offset: 0 });
// result.data: {
// datasetId: 'ds_001', name: 'Iris', totalRows: 150, returnedRows: 5,
// columns: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species'],
// rows: [{ sepal_length: 5.1, sepal_width: 3.5, ... }, ...]
// }
Use limit and offset to control the range of rows returned. When omitted, all rows are returned. The internal row number column (Row#) added by MIDAS is not included in the results. Returns a NO_DATA error for derived datasets that have not been evaluated yet — such as right after opening a saved project, or right after overwriting a dataset they depend on. Open the dataset in a Data Table tab to evaluate it, or read its rows directly with datasets.query().
datasets.buildMapping(datasetId, columnId, input)
Generate a value → canonical mapping dataset from unique values in a string or enum column.
// Key Collision: fullwidth normalize → lowercase
const result = await window.midas.datasets.buildMapping('ds_001', 'city', {
method: { type: 'key_collision', normalizers: ['fullwidth', 'case'] }
});
// result.data: { id: 'primary_...', changedCount: 3, valueCount: 7 }
// Nearest Neighbor: edit distance
const result2 = await window.midas.datasets.buildMapping('ds_001', 'city', {
method: { type: 'nearest_neighbor', method: 'levenshtein', threshold: 2 }
});
method.type must be 'key_collision' or 'nearest_neighbor'.
Key Collision applies deterministic normalizer functions in order to produce the initial canonical value. Specify the application order in normalizers. Available normalizers: 'trim' (strip surrounding whitespace), 'fullwidth' (NFKC normalization), 'kana' (katakana → hiragana), 'case' (lowercase), 'fingerprint' (lowercase, strip punctuation, deduplicate tokens, sort tokens).
Nearest Neighbor groups nearby values by distance and sets the most frequent value in each cluster as the initial canonical. method must be 'levenshtein' (edit distance). threshold (default: 2) sets the distance cutoff. Maximum unique values: 10,000.
Use overrides to override the canonical for specific values. Use name to set the dataset name (default: {source}_{column}_mapping).
The result is a Primary DataSet with value and canonical columns.
datasets.normalize(datasetId, columnId, mappingDatasetId, input?)
Normalize source data using a mapping dataset. Applies the value → canonical transformation via SQL JOIN.
const result = await window.midas.datasets.normalize('ds_001', 'city', mp.data.datasetId, {
mode: 'replace'
});
// result.data: { id: 'derived_...', name: 'sales_normalized', rowCount: 100, columnCount: 5 }
mode is 'add' (default) to append a {column}_normalized column, or 'replace' to replace the original column with COALESCE(canonical, original_value). Use name to set the output dataset name (default: {source}_normalized). Any dataset with value and canonical columns can be used as the mapping dataset.
datasets.traceRowLineage(datasetId, rowIndices)
Trace one hop of row-level lineage: find the parent dataset rows that contributed to the given rows of a derived dataset. For SQL-query datasets, it re-runs the derive query with the top-level aggregation removed and the parent Row # projected, then matches parent rows by the values of the requested rows. Datasets created by Convert Column Types are traced the same way, using an equivalent query rebuilt from the current conversion settings. Datasets built by filter (Save Filtered Data), crosstab, or reshape (wide/long) are traced by matching the parent rows by value, without a probe.
const result = await window.midas.datasets.traceRowLineage('sales_by_region', [0]);
// result.data: { traceable: true, contributions: [{ datasetId: 'ds_001', datasetName: 'sales', rowIndices: [0, 3, 7] }] }
rowIndices are 0-based row indices within the target dataset. Only non-negative integers are accepted; an empty array, a non-integer, or a negative value returns an INVALID_INPUT error. Out-of-range integers are ignored. The returned contributions lists the contributing rows per parent dataset, so a JOIN yields multiple entries. Each rowIndices is sorted and deduplicated. Passing several rows returns their contributions combined, without a per-row breakdown; call once per row to attribute rows individually.
Traceable SQL shapes: GROUP BY aggregations (including expression keys and GROUP BY by ordinal or output alias), JOIN, FROM subquery and CTE, plain projection and WHERE filter, DISTINCT, and whole-table aggregation (all parent rows contribute). Datasets created by Convert Column Types are traceable the same way. Datasets built by filter, crosstab, or reshape (wide/long) are also traceable, matched by parent column values.
When a query cannot be traced, it returns traceable: false with a reason.
window-function: contains a window function or a QUALIFY clauseset-operation: contains a set operation such as UNIONnondeterministic: contains TABLESAMPLE or a LIMIT without ORDER BYnested-aggregation: a FROM subquery or CTE aggregates on its ownambiguous-group-keys: a GROUP BY key is not in the output, so its value cannot be read per rowno-parent-table: the FROM cannot be resolved to a registered parent datasetno-parent-dataset: the dataset is derived but has no parent dataset to trace (for example a query with no dataset in its FROM, such asSELECT 1)not-derived: the target is not a derived datasetunsupported-operation: the derived dataset was built by an unsupported operation (other than a SQL query, Convert Column Types, filter, crosstab, or reshape)parse-failed: the query's structure could not be analyzed
Some reasons include a detail string with specifics: the table name that could not be resolved (no-parent-table), the original operation type (unsupported-operation), or TABLESAMPLE.
datasets.openContributingRows(datasetId, rowIndices, targetDatasetId?)
Drill down from a derived dataset to its contributing rows: trace row-level lineage with the same rules as traceRowLineage, then open the contributing parent rows in a Contributing rows tab. For a JOIN, one tab is opened per contributing parent.
Pass targetDatasetId (a dataset ID or name) to jump straight to a specific ancestor: the hops are composed internally and only that ancestor's contributing-rows view is opened (no intermediate tabs). targetDatasetId must be one of the traceable ancestors of the dataset; otherwise an INVALID_INPUT error is returned. Omitting it drills one hop to the immediate parent(s).
Calling it again on the rows of an opened Contributing rows view drills one more hop up the parent chain (toward the original data). The chain stops when it reaches a primary dataset or a derived dataset with no parent to trace, returning traceable: false with reason: 'no-parent-dataset'. Repeating this walks step by step from an aggregate table back to the original data.
const result = await window.midas.datasets.openContributingRows('sales_by_region', [0]);
// result.data: { traceable: true, opened: [{ datasetId: 'dataset-ephemeral-...', parentDatasetId: 'ds_001', parentName: 'sales', rowCount: 12 }] }
// Drill one more hop up from the opened Contributing rows view
const next = await window.midas.datasets.openContributingRows(result.data.opened[0].datasetId, [0]);
// Jump straight to a specific ancestor (opens only that ancestor's view, no intermediate tabs)
const jumped = await window.midas.datasets.openContributingRows('sales_by_region', [0], 'sales_raw');
The handling of rowIndices (0-based integers; an empty array, a non-integer, or a negative value returns an INVALID_INPUT error, and out-of-range integers are ignored) and the traceable/untraceable decision rules are the same as traceRowLineage. When the rows cannot be traced, nothing is opened and the result is traceable: false with a reason. Because this opens a tab, it returns a NO_CONTAINER error when no tab container is active (for example, when called outside a project view).
The opened ephemeral datasets carry their lineage. "Save as Dataset" on the tab promotes one to a persistent dataset (a RowLineageOperation) that re-traces the contributing rows on each re-evaluation.
enums
enums.create(name, values)
Create an enum definition. Up to 50 values can be specified.
const result = await window.midas.enums.create('color', ['red', 'green', 'blue']);
// result.data: { name: 'color', valueCount: 3 }
enums.list()
List all enum definitions.
const result = await window.midas.enums.list();
// result.data: [{ name: 'color', values: ['red', 'green', 'blue'] }, ...]
enums.update(name, values)
Update the values of an existing enum definition.
await window.midas.enums.update('color', ['red', 'green', 'blue', 'yellow']);
Up to 50 values can be specified. Removing values is rejected with ENUM_VALUE_MISMATCH if any dataset still contains the removed values in a column of this enum type. This preserves the invariant that enum column values are always in the definition or NULL. Use Convert Column Types first to null-out or exclude those values, or keep the values in the enum definition.
enums.remove(name)
Remove an enum definition. Returns an ENUM_IN_USE error if columns still reference this enum.
await window.midas.enums.remove('color');
tabs
tabs.list()
List all open tabs.
const result = await window.midas.tabs.list();
// result.data: [{ id, type, title, paneId, isActive }, ...]
paneId is the ID of the pane holding the tab. isActive is true for the tab shown at the front of that pane. One tab is at the front of each pane, so with several panes open, several tabs have isActive: true. Use layout.get() to see how the panes are arranged.
tabs.activate(tabId)
Bring an open tab to the front, as clicking the tab does. The pane holding the tab becomes the active pane, so later calls to tabs.open() put their new tab there.
await window.midas.tabs.activate('tab_001');
tabs.open(config)
Open a new tab. datasetId accepts a dataset ID or name (case-insensitive). For a graph-builder tab, the dataset is bound to the tab, so it shows in the dataset selector and in tabs.getGraphBuilder().
// Open Graph Builder
const result = await window.midas.tabs.open({
type: 'graph-builder',
title: 'My Graph',
datasetId: 'ds_001'
});
// result.data: { tabId: 'tab_...', type: 'graph-builder', title: 'My Graph' }
// Open SQL Query Editor
const result2 = await window.midas.tabs.open({
type: 'sql-editor',
initialQuery: 'SELECT * FROM Iris LIMIT 10',
initialOutputName: 'Preview'
});
Available tab types:
| Type | Description |
|---|---|
graph-builder | Graph Builder |
sql-editor | SQL Query Editor |
synthetic-data-generator | Synthetic Data Generator |
glm | GLM |
glmm | GLMM |
random-forest | Random Forest |
linear-regression | Linear Regression |
pca | PCA |
statistics | Descriptive Statistics |
crosstab | Crosstab |
anova | ANOVA |
kaplan-meier | Kaplan-Meier |
cox-regression | Cox Regression |
doe-analysis | DOE Analysis |
arima | ARIMA |
data-table | Data Table |
report | Report (requires reportId) |
computed-column | Computed Column |
dummy-coding | Dummy Coding |
orthogonal-polynomials | Orthogonal Polynomials |
reshape | Reshape |
column-type-conversion | Type Conversion |
enum-definition | Enum Definition |
project-overview | Project Overview |
project-lineage | Project Lineage |
selected-rows | Selected Rows |
excluded-rows | Excluded Rows |
filtered-data | Filtered Data |
model-detail | Model Detail (requires modelId) |
glm-diagnostics | GLM Diagnostics (requires modelId) |
glm-prediction | GLM Prediction (requires modelId) |
sql-query-viewer | SQL Query Viewer |
variant-normalization | Normalize Variants |
apply-mapping | Apply Mapping |
project-diff | Project Diff |
help | Help |
report tabs require reportId, and model-detail, glm-diagnostics, and glm-prediction tabs require modelId. Set modelId to the ID of a saved model obtained from models.list(). Omitting it returns an INVALID_INPUT error.
// Open a Model Detail tab
const result3 = await window.midas.tabs.open({
type: 'model-detail',
modelId: 'model_001'
});
The glm-diagnostics tab opens both GLM and linear regression (linear_regression) models. For a linear regression model, it hides the Deviance/Pearson residual toggle and changes the heading to Residual Diagnostics.
models.run() supports nine model types: glm, glmm, random_forest, arima, linear_regression, anova, pca, kaplan_meier, and cox_regression. The corresponding tabs (glm, glmm, random-forest, arima, linear-regression, anova, pca, kaplan-meier, cox-regression) plus other analysis tabs (doe-analysis, crosstab, statistics) can all be opened with tabs.open(), but only the nine types above can be run programmatically — the rest must be configured and run through the GUI.
tabs.duplicate(tabId)
Duplicate an analysis tab, opening an independent copy next to it. The copy keeps the current settings (predictors, orders, response, and so on) but not the run results or the saved-model state, so you can change a parameter and re-run to compare fits side by side. Only analysis tabs can be duplicated: glm, glmm, anova, doe-analysis, linear-regression, cox-regression, kaplan-meier, pca, random-forest, and arima. Other tab types return an INVALID_TAB_TYPE_FOR_OPERATION error. In the UI, the same action is available by right-clicking a tab and choosing Duplicate Tab.
const result = await window.midas.tabs.duplicate('arima_001');
// result.data: { tabId, type, title }
tabs.close(id)
Close a tab.
await window.midas.tabs.close('tab_001');
tabs.closeOthers(keepTabId)
Close all tabs except the specified one.
const result = await window.midas.tabs.closeOthers('tab_001');
// result.data: { closedCount: 3 }
tabs.getGraphBuilder(tabId)
Get Graph Builder tab configuration.
const result = await window.midas.tabs.getGraphBuilder('tab_001');
// result.data: { tabId, graphType, datasetId, config, aspectRatio,
// availableColumns, lineageTargetDatasetId, availableLineageTargets, renderWarnings? }
renderWarnings holds the diagnostics shown above the Graph Builder preview for the current configuration, one message per element. Examples are points dropped because they could not be computed, non-finite values dropped at the input stage of an aggregation, duplicate X values within a group, a shape or linetype aesthetic with more categories than distinct assigned marker shapes or line styles, and an area layer with position stack or fill whose series has both positive and negative values. The diagnostics listed above do not prevent rendering. The one exception is the facet panel limit: when a warning reports that the panel count exceeds the limit configured in Settings (Max Facet Panels), the graph is not rendered. The field is omitted when there is no diagnostic. It is evaluated only when graphType is 'custom' and a dataset is selected. For a graph with facets, diagnostics are evaluated per panel and arrive in the same form as the preview warning strip: each line is prefixed with the title of the panel that reported it, and a warning common to all panels is merged into a single All panels: line.
tabs.addGraphLayer(tabId, layer)
Add a layer to a custom graph. Only works when graphType is 'custom'.
const result = await window.midas.tabs.addGraphLayer('tab_001', {
geom: { type: 'point' },
aes: { x: 'sepal_length', y: 'sepal_width', color: 'species' }
});
// result.data: { layerIndex: 0 }
Aesthetic mappings (aes) accept column names or column IDs. Column names are resolved case-insensitively. Available properties are x, y, color, fill, stroke, size, shape, alpha, linetype, ymin, ymax, label, and group. Not all properties apply to every geom type — for example, Point and Line do not support fill. aes accepts column references only; set a fixed color, size, or opacity in geom.defaults, not in aes. Passing a fixed value through aes (such as { fixedColor: '#FF0000' } or a number) returns an INVALID_INPUT error. When stats is omitted, identity is used by default. When position is omitted, bar geom defaults to { type: "stack" } (stacked); other geoms default to identity. Each geom allows only specific position types (e.g. line allows only identity); specifying a disallowed position returns an INVALID_INPUT error. Use scales to configure per-layer scales (color, fill, shape, linetype, size, alpha). See configureGraph for details.
When using the Label geom ({ type: 'label' }) with aggregating stats (summary, count, bin, etc.), the column mapped via aes.label is lost during aggregation. Use geom.defaults.labelContent to reference stat output variables instead.
await window.midas.tabs.addGraphLayer(tabId, {
geom: {
type: 'label',
defaults: {
labelContent: { field: '$y', format: '.1f', prefix: 'Mean: ' }
}
},
stats: [{ type: 'summary', params: { fun: 'mean' } }],
});
labelContent properties:
| Property | Type | Description |
|---|---|---|
field | string | Field to display. Stat variables ($x, $y, $n, etc.) or a column name |
format | string | d3-format specifier (e.g. .2f, ,.0f) |
prefix | string | String prepended to the formatted value |
suffix | string | String appended to the formatted value |
When labelContent is set, aes.label is not required.
The Text geom ({ type: 'text' }) requires aes.label. Only the Label geom reads labelContent; setting it on a Text geom does not change the displayed text.
Layers also accept these optional properties:
| Property | Type | Description |
|---|---|---|
name | string | Display name for the layer |
filter | string | Filter expression that narrows this layer's data. Uses the same syntax as the Data Table filter input (see The Data Table Tab) and is validated by the same rules, so an expression with a syntax error, an unknown column, or a value that does not match the column's type returns INVALID_INPUT |
visible | boolean | Show or hide the layer (default true) |
yAxis | 'primary' | 'secondary' | Which Y axis to use |
showLegend | 'auto' | 'show' | 'hide' | Legend visibility for this layer |
clickSelection | boolean | Enable click-to-select on data points |
tooltip | array | { content: 'encoding' } | Content shown when hovering a data point. See below |
Set tooltip to an array of field definitions to show specific values on hover, or to { content: 'encoding' } to auto-generate fields from the layer's aes. Omitting tooltip shows no tooltip.
await window.midas.tabs.addGraphLayer(tabId, {
geom: { type: 'point' },
aes: { x: 'sepal_length', y: 'sepal_width' },
tooltip: [
{ field: '$x', label: 'Sepal Length' },
{ field: 'species' }
]
});
Tooltip field properties:
| Property | Type | Description |
|---|---|---|
field | string | Stat variable ($x, $y, $n, etc.) or a column name or ID |
label | string | Custom label (omit for no label, value only) |
format | string | d3-format specifier (e.g. .2f, ,.0f) |
type | 'datetime' | 'date' | Formats the field as a date or datetime string |
See Custom Graph Reference for the list of geom, stat, and position types. Each Statistic's params are documented there with their accepted values and defaults. For facets, coordinates, and other graph-level options, see Custom Graph.
tabs.updateGraphLayer(tabId, layerIndex, layer)
Partially update an existing layer. Only the specified fields are changed; omitted fields retain their current values.
await window.midas.tabs.updateGraphLayer('tab_001', 0, {
geom: { type: 'line' }
});
When the geom is changed and the current position is not allowed by the new geom, position is automatically reset to identity and a warning is returned. Explicitly specifying a disallowed position returns an INVALID_INPUT error.
Pass scales: null to remove layer-specific scales and fall back to the default scales. Pass position: null to reset position to the default (unset). Pass tooltip: null to remove the tooltip.
tabs.removeGraphLayer(tabId, layerIndex)
Remove a layer.
await window.midas.tabs.removeGraphLayer('tab_001', 0);
tabs.moveToPane(tabId, toPaneId)
Move a tab to a different pane. Take the ID of the destination pane from layout.get(), or, when you create a pane to lay tabs out side by side, from what layout.split() returns.
await window.midas.tabs.moveToPane('tab_001', 'pane_002');
tabs.setDataset(tabId, datasetId)
Switch a tab's dataset. datasetId accepts a dataset ID or name (case-insensitive). For a graph-builder tab, the new dataset shows in the dataset selector and in tabs.getGraphBuilder().
await window.midas.tabs.setDataset('tab_001', 'ds_002');
tabs.configureGraph(tabId, config)
Configure a Graph Builder tab in one call. Select the chart type with graphType. datasetId accepts a dataset ID or name (case-insensitive); pass an empty string to clear it. Column names are resolved case-insensitively. Properties not recognized by GraphConfigInput or LayerDefInput are reported in result.warnings.
await window.midas.tabs.configureGraph('tab_001', {
graphType: 'custom',
datasetId: 'ds_001',
layers: [
{ geom: { type: 'point' }, aes: { x: 'weight', y: 'height', color: 'group' } }
],
aspectRatio: '4:3'
});
Use coordinates to set the coordinate system. 'flipped' swaps the X and Y axes (useful for horizontal bar charts with long category labels). 'cartesian' resets to the default Cartesian coordinates.
await window.midas.tabs.configureGraph('tab_001', {
coordinates: 'flipped'
});
Use scales to configure axis scales. When calling configureGraph with scales, only the specified axes are updated; unspecified axes retain their existing settings. An axis you do not specify gets its scale inferred from the column mapped to it: date and datetime columns become time, categorical columns become categorical, and numeric columns become linear. Scales you specify explicitly take precedence.
await window.midas.tabs.configureGraph('tab_001', {
scales: { y: { type: 'log', title: 'Log scale' } }
});
Each axis (x, y, y2) in scales accepts:
| Property | Type | Description |
|---|---|---|
type | 'linear' | 'log' | 'sqrt' | 'time' | 'categorical' | Scale type |
title | string | Axis title |
domain | { min?, max? } | Range for continuous scales (not applicable for categorical) |
tickCount | number | Number of ticks (not applicable for categorical) |
limits | string[] | Category display order (categorical only) |
breaks | string[] | Subset of categories to display (categorical only) |
labels | Record<string, string> | Custom display names for categories (categorical only) |
labelRotation | 'auto' | 0 | 45 | 90 | Label rotation angle |
Per-layer scales are set via layers[].scales, which accepts the color, fill, shape, linetype, size, and alpha aesthetics. Per-layer tooltips are set via layers[].tooltip (see addGraphLayer).
await window.midas.tabs.configureGraph('tab_001', {
graphType: 'custom',
datasetId: 'ds_001',
layers: [{
geom: { type: 'tile' },
aes: { x: 'col_x', y: 'col_y', fill: 'col_value' },
scales: { fill: { scaleType: 'sequential', paletteId: 'viridis' } }
}]
});
Each color / fill scale accepts:
| Property | Type | Description |
|---|---|---|
scaleType | 'categorical' | 'sequential' | 'diverging' | 'threshold' | Color scale type |
paletteId | string | Palette ID. See Custom Graph Reference for available values |
domain | { min?, max?, center? } | Domain for continuous scales |
legendPosition | 'right' | 'left' | 'top' | 'bottom' | 'none' | Legend position |
legendTitle | string | Legend title |
thresholds | number[] | Threshold values (threshold type) |
thresholdColors | string[] | Colors for each region (threshold type, length = thresholds.length + 1) |
thresholdVariable | 'x' | 'y' | Variable used for threshold comparison (threshold type, default 'y') |
The effective scaleType is determined from the specified value and the column type. When omitted, fill uses sequential for numeric columns and categorical for other columns, while color always uses categorical. When sequential or diverging is specified for a column that is not numeric, MIDAS gives priority to the column type, renders the aesthetic with a categorical scale, and reports the mismatch in the warnings of the configuring call's response and in the diagnostics (renderWarnings). However, when a diverging paletteId is also specified, the palette is incompatible with the effective categorical scale, so validation fails and the graph is not rendered. A sequential palette remains usable with a categorical scale and does not cause this error. The incompatible combination is reported in the warnings of the configuring call's response, and reports.addGraph / reports.updateElement return renderStatus: 'error'.
Each shape / linetype scale accepts:
| Property | Type | Description |
|---|---|---|
shapes | ('circle' | 'square' | 'triangle' | 'diamond' | 'cross' | 'plus')[] | Shapes assigned to categories, in order (shape aesthetic) |
linetypes | ('solid' | 'dashed' | 'dotted')[] | Line styles assigned to categories, in order (linetype aesthetic) |
legendPosition | 'right' | 'left' | 'top' | 'bottom' | 'none' | Legend position |
legendTitle | string | Legend title |
The first entry in the list goes to the first category. When there are more categories than entries, the list repeats from the start. Unknown shape and line style names are dropped and reported in warnings. The legend position applies to the whole graph: it is taken from the first legend-showing layer, searching its color, fill, shape, and linetype scales in that order. Only aesthetics with a column mapped are searched, so a legendPosition set on an aesthetic without a column does not affect the legend and is reported in warnings.
The size / alpha scales accept a range only. Neither aesthetic draws a legend.
| Property | Type | Description |
|---|---|---|
range | { min?, max? } | Range of drawn values. Defaults are 2-20 (pixels) for size and 0.2-1 for alpha |
The size range stays at 0 or above and the alpha range stays within 0 to 1. Values outside those bounds are clamped and reported in warnings.
await window.midas.tabs.configureGraph('tab_001', {
graphType: 'custom',
datasetId: 'ds_001',
layers: [{
geom: { type: 'point' },
aes: { x: 'weight', y: 'mpg', shape: 'origin', size: 'horsepower' },
scales: {
shape: { shapes: ['square', 'triangle', 'diamond'], legendTitle: 'Origin' },
size: { range: { min: 4, max: 30 } }
}
}]
});
Use facets to split the graph into panels by one or two categorical variables. Two modes are supported: wrap (single variable, auto-arranged panels) and grid (row and/or column variables).
// Facet wrap: split by one variable
await window.midas.tabs.configureGraph('tab_001', {
facets: { type: 'wrap', variable: 'species', ncol: 3, scales: 'free_y' }
});
// Facet grid: split by row and/or column variables
await window.midas.tabs.configureGraph('tab_001', {
facets: { type: 'grid', rows: 'region', cols: 'year' }
});
// Remove facets
await window.midas.tabs.configureGraph('tab_001', { facets: null });
Omitting facets preserves the current setting.
Facet wrap properties:
| Property | Type | Description |
|---|---|---|
type | 'wrap' | Facet wrap mode |
variable | string | Column name or ID to facet by (required) |
ncol | number | Number of columns (auto-calculated if omitted) |
nrow | number | Number of rows (auto-calculated if omitted) |
complete | boolean | Fill all combinations to show empty panels |
scales | 'fixed' | 'free_x' | 'free_y' | 'free' | Axis scale sharing across panels (default: 'fixed') |
Facet grid properties:
| Property | Type | Description |
|---|---|---|
type | 'grid' | Facet grid mode |
rows | string | Column name or ID for row faceting |
cols | string | Column name or ID for column faceting |
complete | boolean | Fill all combinations to show empty panels |
scales | 'fixed' | 'free_x' | 'free_y' | 'free' | Axis scale sharing across panels (default: 'fixed') |
At least one of rows or cols is required for facet grid.
For the simple graph types — histogram, scatter, timeseries, bar, pairplot, and datetime_histogram — set the fields specific to that type via graphType. layers, globalAes, scales, coordinates, and facets apply only to custom.
await window.midas.tabs.configureGraph('tab_001', {
graphType: 'histogram',
datasetId: 'ds_001',
column: 'sepal_length',
bins: 20
});
Column fields such as column, xColumn, and categoryColumn accept either a column name or a column ID. The type-specific fields are:
| Graph type | Fields |
|---|---|
histogram | column, bins, showDensity, orientation, groupByColumn, groupMode, facetNcol, showAnnotations |
scatter | xColumn, yColumn, colorColumn, sizeColumn, referenceLines, xScaleType, yScaleType, density options (displayMode, densityVisualization, densityBandwidth, contourLevels, densityColorScale) |
timeseries | xColumn, yColumns, rangeColumns, rangeOpacity |
bar | categoryColumn, valueColumns, aggregations, orientation, showValues, stackMode, sortOrder, topN |
pairplot | columns |
datetime_histogram | column, interval, showTrend |
For bar, valueColumns accepts aggregation target columns plus '$count' for a row count, and aggregations sets the aggregation method per column (sum, average, median, min, or max). Row counts are represented by the '$count' value column, not by an aggregation value: specifying count in aggregations returns an INVALID_INPUT error.
The boxplot and heatmap graph types cannot be configured; passing either returns an INVALID_GRAPH_TYPE error. For a box plot, use graphType: "custom" with a layer of geom: { type: "boxplot" } and stats: [{ type: "boxplot" }].
Every configurable graph type accepts lineageTargetDatasetId (ID or name). When datasetId is a derived dataset (for example a GROUP BY aggregate, or a filter or reshape of the original rows), set this to an ancestor so that clicking an element selects the underlying rows and double-clicking opens their contributing rows in a Contributing rows tab. The value must be a contributing-rows ancestor of datasetId; check the candidates with getGraphBuilder's availableLineageTargets. Pass an empty string or null to reset to the graph's own dataset.
Even a valid ancestor can be untraceable at runtime if a hop between datasetId and the target uses a window function or a set operation. The call still succeeds; warnings names the untraceable hop and the reason.
models
models.list()
List fitted models.
const result = await window.midas.models.list();
// result.data: [{ id, type, name, datasetId, family }, ...]
type is one of 'glm', 'glmm', 'random_forest', 'arima', 'linear_regression', 'anova', or 'doe'. DoE models are created from the DoE tab (Add to Report), not via models.run().
models.run(config)
Run a model. Set config.type to 'glm', 'glmm', 'random_forest', 'arima', 'linear_regression', 'anova', 'pca', 'kaplan_meier', or 'cox_regression'. datasetId accepts a dataset ID or name (case-insensitive) and must refer to a primary or derived dataset (specifying an ephemeral dataset by ID returns an INVALID_INPUT error). Columns can be specified by name (case-insensitive). The result is returned directly without opening a tab. To persist the model for later use with models.list() and models.describe(), call models.save() with the returned runId. Unsaved run results are kept in memory, up to 20. Beyond that limit, the oldest unsaved results are discarded first, and a discarded runId can no longer be passed to models.save(). All unsaved results are also lost on page reload.
GLM (type: 'glm'):
const result = await window.midas.models.run({
type: 'glm',
datasetId: 'ds_001',
yColumn: 'sepal_length',
xColumns: ['sepal_width', 'petal_length'],
family: 'gaussian'
});
// result.data:
// {
// type: 'glm',
// runId: '...',
// family: 'gaussian',
// link: 'identity',
// coefficients: [
// { variable: '(Intercept)', estimate: 2.25, se: 1.02, ciLower: 0.23, ciUpper: 4.27, expEstimate: null, expCiLower: null, expCiUpper: null },
// ...
// ],
// inference: { distribution: 't', df: 147 },
// fit: { deviance: 42.3, nullDeviance: 234.7, aic: 183.94, bic: 193.47, iterations: 5, converged: true },
// diagnosticSummary: { nObservations: 150, nIncomplete: 0, degreesOfFreedom: 147, dispersionParameter: 0.29 },
// warnings: []
// }
Fields in coefficients:
| Field | Description |
|---|---|
estimate | Coefficient estimate on the link scale |
se | Standard error of the estimate |
ciLower / ciUpper | Lower and upper bounds of the Wald confidence interval. The reference distribution is reported in inference; see the family-by-family table below |
expEstimate / expCiLower / expCiUpper | The exp() transformation of the estimate and confidence interval. See below for interpretation and the links for which these are null |
diagnosticSummary.dispersionParameter is the estimate of the dispersion parameter φ. For gaussian it is the deviance divided by the residual degrees of freedom n−p; for gamma it is Pearson χ² divided by n−p. For these families it is used to compute the SEs and confidence intervals. For poisson and binomial, SEs are computed with φ = 1, and this field instead contains deviance/(n−p) as an overdispersion diagnostic; it is null when the residual degrees of freedom is 0. For negative-binomial, it is 1.0 when θ is estimated automatically and Pearson χ²/(n−p) when θ is fixed.
GLMM (type: 'glmm'):
Specify the random-intercept grouping variable with groupColumn. family accepts 'gaussian', 'binomial', 'poisson', or 'gamma' (default 'gaussian'). maxIterations defaults to 100 and tolerance to 1e-6. See GLMM for background on the model.
const result = await window.midas.models.run({
type: 'glmm',
datasetId: 'ds_001',
yColumn: 'sepal_length',
xColumns: ['sepal_width', 'petal_length'],
groupColumn: 'species',
family: 'gaussian'
});
// result.data:
// {
// type: 'glmm',
// runId: '...',
// family: 'gaussian',
// link: 'identity',
// fixedEffects: [{ variable: '(Intercept)', estimate: 2.35, se: 0.87, ... }, ...],
// inference: { distribution: 'normal', df: null },
// randomEffects: { groupColumn: 'species', variance: 0.42, residualVariance: 0.14, icc: 0.75, blup: [...] },
// fit: { logLikelihood: -72.1, iterations: 8, converged: true },
// diagnosticSummary: { nObservations: 150, nGroups: 3, nFixedEffects: 3, nIncomplete: 0, groupSizes: [...] },
// warnings: []
// }
link, includeIntercept, confidenceLevel are also available as optional parameters, with the same meaning as in GLM. maxIterations defaults to 100 and tolerance to 1e-6 (different from GLM defaults).
Confidence intervals for GLMM fixed effects are Wald approximations based on the standard normal distribution; inference is always { distribution: 'normal', df: null }. When the number of groups is small, intervals based on this approximation can fall below the nominal coverage.
Fields in randomEffects:
variance— variance of the random intercepts, σ²_uresidualVariance— forgaussian, the residual variance σ²_e; forgamma, the estimated dispersion parameter φ. Not returned forbinomialandpoisson, where φ is fixed at 1 by theoryicc— intraclass correlation coefficient σ²_u / (σ²_u + σ²_e). σ²_e is the REML-estimated residual variance forgaussian+identity, π²/3 forbinomial+logit, and 1 forbinomial+probit— the latter two are latent-scale values. For all other family-link combinations, no latent-scale residual variance is defined andiccisnullblup— predicted random intercepts per group (Best Linear Unbiased Prediction). Each value is the group mean of the residuals from the fixed-effects prediction (y − Xβ̂), shrunk toward 0; groups with fewer observations are shrunk more.standardErrorquantifies the prediction uncertainty: for LMM it is the conditional prediction error standard deviation, and for other families it is an approximation based on the Laplace approximation.rankis the rank in descending order ofestimate
For LMM (gaussian + identity), fit.logLikelihood is the REML log-likelihood, and fit.aic and fit.bic are based on it. REML-based AIC/BIC cannot be used to compare models with different fixed-effects structures. For other families, the log-likelihood is a Laplace approximation.
Random Forest (type: 'random_forest'):
Set taskType to 'classification' or 'regression'. The metrics field contains fitting-set (resubstitution) evaluation metrics. For an estimate of generalization performance, use oobScore.
const result = await window.midas.models.run({
type: 'random_forest',
datasetId: 'ds_001',
yColumn: 'species',
xColumns: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width'],
taskType: 'classification',
nEstimators: 100,
randomState: 42
});
// result.data:
// {
// type: 'random_forest',
// runId: '...',
// taskType: 'classification',
// tuningParameters: { nEstimators: 100, maxDepth: null, ... },
// featureImportances: [{ feature: 'petal_length', importance: 0.45 }, ...],
// permutationImportances: [{ feature: 'petal_length', importance: 0.38 }, ...],
// metrics: { taskType: 'classification', accuracy: 0.96, precision: 0.96, recall: 0.96, f1Score: 0.96, nClasses: 3 },
// nSamples: 150,
// oobScore: 0.95,
// warnings: []
// }
For regression tasks, metrics contains { taskType: 'regression', mse, rmse, mae, r2 }. metrics values are computed on the fitting data (resubstitution) and are not available from models.describe(). For an estimate of generalization performance, use oobScore (OOB accuracy for classification, OOB R-squared for regression). For regression, when the response has effectively no variation, R-squared is undefined, so r2 and the regression oobScore are null. For both task types, oobScore is null when no samples have out-of-bag predictions, which can occur when the number of samples is very small. For regression, oobScore is also null when only one sample has out-of-bag predictions, or when the responses of the out-of-bag samples have effectively no variation. In each case, warnings states the reason. permutationImportances is the mean decrease in OOB prediction accuracy when each predictor is shuffled. Values can be negative, which means shuffling that predictor did not reduce OOB prediction accuracy.
| Parameter | Type | Default | Description |
|---|---|---|---|
nEstimators | number | 100 | Number of trees |
maxDepth | number | null | null | Maximum tree depth (null for unlimited) |
minSamplesSplit | number | 2 | Minimum samples to split a node |
minSamplesLeaf | number | 1 | Minimum samples in a leaf node |
maxFeatures | 'sqrt' | 'log2' | null | number | 'sqrt' | Number of predictors to consider at each split |
randomState | number | 42 | Random seed |
inference identifies the reference distribution used for ciLower and ciUpper. distribution: 't' indicates a t distribution with df degrees of freedom; distribution: 'normal' indicates a standard normal distribution, in which case df is null.
The family-by-family mapping is shown below. The critical value follows t(n−p) exactly only for Gaussian with the identity link. Other dispersion-estimating families apply a t distribution as a small-sample convention, while families marked asymptotic use the standard normal approximation.
| family | link | Reference distribution | Nature |
|---|---|---|---|
gaussian | identity | t(n−p) | Exact |
gaussian | non-identity | t(n−p) | Small-sample convention |
gamma | any | t(n−p) | Small-sample convention |
negative-binomial | any (fixed θ) | t(n−p) | Small-sample convention |
poisson | any | Standard normal | Asymptotic |
binomial | any | Standard normal | Asymptotic |
negative-binomial | any (estimated θ) | Standard normal | Asymptotic |
ciLower and ciUpper are the Wald confidence interval estimate ± criticalValue × se for each coefficient. The confidence level follows the confidenceLevel parameter (default 95). The critical value is the (1 + confidenceLevel/100) / 2 quantile of the reference distribution reported in inference.
expEstimate, expCiLower, and expCiUpper are the exp() transformation of the link-scale estimate and confidence interval. For logit link, these correspond to odds ratios (OR); for Poisson and Negative Binomial with log link, incidence rate ratios (IRR); for Gamma and Gaussian with log link, multiplicative effects. For identity, inverse, and probit links, these fields are null.
fit.aic and fit.bic are number | null. They are null when the log-likelihood constant is undefined (e.g., non-integer weights in Binomial, or a saturated model).
The response may include two kinds of warnings. Top-level result.warnings contains data preparation warnings such as exclusion of rows with missing values. result.data.warnings contains model execution warnings such as convergence issues. Rows with missing values in any response or explanatory variable are excluded from analysis. The number of excluded rows is available in diagnosticSummary.nIncomplete.
When the model does not converge within the maximum number of iterations, no error is raised; the result is returned with fit.converged: false, and message also reads "did not converge". When complete or quasi-complete separation is suspected, a warning is included in data.warnings. When a result is returned, coefficient se values are never null. When SEs cannot be computed — for example, a non-positive-definite covariance matrix, a rank-deficient design matrix, or a variance that overflows or becomes undefined because a predictor or the response spans an extreme range — no result is returned and a NUMERICAL_ERROR error is raised instead. For the extreme-range case, rescale or standardize the predictors and response, then refit. A NUMERICAL_ERROR is also raised when the fitted mean falls outside the valid range for the family (for example, an identity link applied to Poisson or Gamma); choose a link that keeps the fitted mean in range, such as log.
Specify family as 'gaussian' (default), 'binomial', 'poisson', 'gamma', or 'negative-binomial'. See GLM for guidance on choosing a family. Use link to set the link function. When omitted, the default link for the family is used.
| family | Default link | Available links |
|---|---|---|
gaussian | identity | identity, log |
binomial | logit | logit, probit |
poisson | log | log, identity |
gamma | inverse | inverse, log, identity |
negative-binomial | log | log |
Optional parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
includeIntercept | boolean | true | Include intercept term |
maxIterations | number | 25 | Maximum number of iterations |
tolerance | number | 1e-8 | Convergence tolerance |
binomialResponse | object | - | Binomial response format. See below |
theta | number | - | Overdispersion parameter for negative binomial. When omitted, estimated via profile likelihood |
offsetColumn | string | - | Offset column (e.g., exposure for Poisson regression) |
confidenceLevel | number | 95 | Confidence level for confidence intervals (50–99.99) |
When theta is omitted and estimated automatically, coefficient SEs and confidence intervals are computed treating the estimated θ as fixed. The estimation uncertainty of θ itself is not propagated into the SEs.
binomialResponse specification:
Specifies the response variable format when family: 'binomial'. When binomialResponse is omitted, binary format is assumed.
{ format: 'binary' }-- Binary 0/1 data. Specify the response variable withyColumn{ format: 'grouped', successesColumn: '...', trialsColumn: '...' }-- Successes/trials pair.yColumncan be omitted in this case
// Grouped Binomial example
const result = await window.midas.models.run({
type: 'glm',
datasetId: 'ds_001',
binomialResponse: { format: 'grouped', successesColumn: 'defects', trialsColumn: 'inspected' },
xColumns: ['temperature', 'pressure'],
family: 'binomial',
link: 'logit'
});
ARIMA (type: 'arima'):
Fit an ARIMA(p,d,q) model to a single time-series column. Specify order as [p, d, q] for manual order selection, or use autoSelect for automatic order selection. Setting seasonalPeriod to 2 or more turns the model into ARIMA(p,d,q)(P,D,Q)[s] (SARIMA) with seasonal orders. Automatic selection sets the differencing orders by tests first and chooses the remaining orders by AIC or BIC under that differencing. The differencing order d is set with the KPSS test. In seasonal models, the seasonal differencing order D is set first with the OCSB test, and KPSS is applied to the seasonally differenced series. For why differencing orders are not compared across by AIC/BIC, see Automatic ARIMA Order Selection; for the tab workflow, see The ARIMA Tab.
| Parameter | Type | Default | Description |
|---|---|---|---|
seriesColumn | string | (required) | Column name for the time series |
order | [number, number, number] | — | [p, d, q] — AR order, differencing order, MA order. Omit to use autoSelect |
seasonalPeriod | number | 1 | Seasonal period s: the number of observations per cycle, e.g. 12 for the yearly cycle of monthly data. Integer from 1 to 366. 1 means non-seasonal |
seasonalOrder | [number, number, number] | [0, 0, 0] | [P, D, Q] — seasonal AR order, seasonal differencing order, seasonal MA order. P and Q range 0–2, D ranges 0–1. Used when seasonalPeriod is 2 or more and order is specified |
autoSelect | object | { maxP: 3, maxD: 1, maxQ: 3, maxSeasonalP: 1, maxSeasonalQ: 1, criterion: 'aic' } | Auto order selection. Used when order is omitted |
autoSelect.maxP | number | 3 | Maximum AR order to search |
autoSelect.maxD | number | 1 | Maximum differencing order; the KPSS-based choice of d never exceeds it |
autoSelect.maxQ | number | 3 | Maximum MA order to search |
autoSelect.maxSeasonalP | number | 1 | Maximum seasonal AR order to search, 0–2. Effective when seasonalPeriod is 2 or more |
autoSelect.maxSeasonalQ | number | 1 | Maximum seasonal MA order to search, 0–2. Effective when seasonalPeriod is 2 or more |
autoSelect.criterion | 'aic' | 'bic' | 'aic' | Information criterion for choosing the remaining orders under fixed differencing |
includeIntercept | boolean | true | Include a constant term: the series mean when d + D = 0, a drift when d + D = 1. Omitted when d + D is 2 or more, where it would correspond to a polynomial trend |
includeTrend | boolean | false | Include a deterministic linear trend term. The time regressor is generated internally from the position of each valid observation (t = 1, 2, ...), and the slope is estimated only when d + D = 0 (the intercept is then the level at t = 0). When d + D = 1 the slope is represented by the drift term if a constant is included, and when d + D is 2 or more differencing removes the trend; in both cases it is not estimated separately and a warning is reported. In automatic selection, when no seasonal difference is taken (D = 0), the KPSS test on the undifferenced series switches to the variant whose null hypothesis is trend stationarity (decision threshold 0.146) |
confidenceLevel | number | 95 | Confidence level for coefficient CIs |
The response includes coefficients (AR/MA/SAR/SMA/Intercept/Trend with CIs), seasonalOrder, fit (AIC, BIC, log-likelihood, σ², convergence), residualDiagnostics (ACF and PACF of residuals), and nObservations. A coefficient whose standard error cannot be computed has a null se and null CI bounds; this happens, for example, when coefficients are pinned at the stationarity or invertibility boundary and the variance-covariance matrix is unavailable. When autoSelect is used, differencingSelection records the KPSS-based choice of d (the selected d, the KPSS statistic at each order, and the variant and decision threshold used at each order), and orderSearch contains the AIC/BIC for all candidate (p, q, P, Q) orders searched under that differencing. Every entry in orderSearch shares the same (d, D). When seasonalPeriod is 2 or more, seasonalDifferencingSelection also records the OCSB-based choice of D (the selected D, the OCSB statistic, and the decision threshold).
When the fit degenerates (too few observations, or zero variance after differencing), fit.error holds a message. In that case the coefficients, AIC, σ², and similar fields are meaningless values (zero or infinity), and residualDiagnostics.acf/.pacf are empty arrays. This is distinct from non-convergence (converged: false with no fit.error); failing to converge alone does not set fit.error.
Non-finite values (NaN, Infinity, null) in the series are dropped. When observations are dropped, a warning is included in the response. A warning is also included when the model's total differencing d + D is 2 or more, where the constant term is omitted; when includeTrend is requested but d + D is 1 or more, where the trend slope is not estimated separately; when a coefficient's standard error could not be computed; and when an autoregressive or moving-average root is close to the unit circle, where estimates and their normal-approximation confidence intervals may be unreliable (a near-noninvertible moving-average root may indicate overdifferencing). models.describe() returns the same warnings for a saved model.
// Manual order
const result = await window.midas.models.run({
type: 'arima',
datasetId: 'ds_001',
seriesColumn: 'temperature',
order: [1, 1, 1]
});
// Auto order selection
const result2 = await window.midas.models.run({
type: 'arima',
datasetId: 'ds_001',
seriesColumn: 'temperature',
autoSelect: { maxP: 5, maxD: 2, maxQ: 5, criterion: 'bic' }
});
Linear Regression (type: 'linear_regression'):
Fit a linear regression by ordinary least squares.
| Parameter | Type | Default | Description |
|---|---|---|---|
yColumn | string | (required) | Response variable column name |
xColumns | string[] | (required) | Explanatory variable column names |
includeIntercept | boolean | true | Include intercept term |
confidenceLevel | number | 95 | Confidence level for confidence intervals |
In the response, coefficients has the same shape as for GLM, and inference is always a t distribution. fit contains the same fields as for GLM plus rSquared, adjustedRSquared, and rmse. rSquared, adjustedRSquared, and rmse are null when the response has effectively no variation (responseDegenerate: true), in which case the coefficient se values and confidence intervals are also null, and warnings explains why. A saturated model (as many predictors as observations) cannot estimate the dispersion parameter and returns an error instead of a result. For a model without an intercept, rSquared is an uncentered R² and is not comparable to the centered R² of an intercept model.
const result = await window.midas.models.run({
type: 'linear_regression',
datasetId: 'ds_001',
yColumn: 'sepal_length',
xColumns: ['sepal_width', 'petal_length']
});
// result.data: { type: 'linear_regression', runId, coefficients, inference,
// fit: { ..., rSquared: 0.84, adjustedRSquared: 0.84, rmse: 0.33 }, diagnosticSummary, warnings }
ANOVA (type: 'anova'):
Run a one-way or two-way analysis of variance. The number of elements in factorColumns determines which.
| Parameter | Type | Default | Description |
|---|---|---|---|
responseColumn | string | (required) | Response variable column name |
factorColumns | string[] | (required) | Factor columns. One element for one-way, two for two-way |
includeInteraction | boolean | true | Include the interaction term in two-way ANOVA |
ssType | 'I' | 'III' | 'III' | Sum-of-squares decomposition type for two-way ANOVA |
confidenceLevel | number | 95 | Confidence level for Tukey HSD (50–99.99) |
postHoc | boolean | true | Compute Tukey HSD (one-way only; specifying true for two-way ANOVA returns INVALID_INPUT) |
Column eligibility follows the measurement scale, the same rule the ANOVA tab selectors use. responseColumn accepts columns with an interval or ratio scale, and factorColumns accepts columns with a nominal or ordinal scale. A column that does not meet the requirement returns INVALID_INPUT, and the error message names the column's current scale. Date and datetime columns cannot be used as responseColumn even though their scale is interval; for those, the error message names the data type instead of the scale.
The response includes mode ('one-way' or 'two-way'), anovaTable (sum of squares, degrees of freedom, mean square, and the effect sizes η² and ω² per effect, plus residuals and total), groupStatistics (n, mean, standard deviation, minimum, and maximum per group), nObservations, nExcluded, and exclusions. For one-way ANOVA with postHoc enabled, tukeyHSD (pairwise mean differences with SEs and confidence intervals) is also included. The postHoc setting is stored with models saved via models.save and is preserved when the model is re-estimated after a dataset reload. Because two-way ANOVA never computes Tukey HSD, the stored value is always false for two-way models.
exclusions breaks down the rows excluded for missing or invalid values. byGroup counts excluded rows per group (factor level for one-way, level combination for two-way), and factorMissing counts excluded rows whose factor value is missing and which therefore belong to no group. When exclusion removes every row of a level, droppedLevelsA and droppedLevelsB list the label and row count; when both factor levels survive but every row of a cell is excluded, droppedCells lists it. Each of these removals also appears as a message in warnings. In two-way ANOVA with the interaction term, however, a cell emptied by exclusion makes the run itself fail with an empty-cell error, so droppedCells and its warnings are returned only without the interaction term.
const result = await window.midas.models.run({
type: 'anova',
datasetId: 'ds_001',
responseColumn: 'sepal_length',
factorColumns: ['species']
});
// result.data: { type: 'anova', runId, mode: 'one-way',
// anovaTable: { ssType, rows: [{ source, ss, df, ms, etaSquared, omegaSquared }, ...], residuals, total },
// groupStatistics: [{ label, n, mean, std, min, max }, ...],
// tukeyHSD: { comparisons: [{ group1, group2, meanDiff, se, ciLower, ciUpper }, ...], confidenceLevel },
// nObservations: 150, nExcluded: 0,
// exclusions: { byGroup: [], factorMissing: 0, droppedLevelsA: [], droppedLevelsB: [], droppedCells: [] },
// warnings: [] }
PCA (type: 'pca'):
Runs a principal component analysis. Rows where any of the selected columns is missing are excluded, and their count is returned as nExcluded.
| Parameter | Type | Default | Description |
|---|---|---|---|
columns | string[] | (required) | Numeric columns to analyze. At least 2 |
preprocessing | 'standardize' | 'center' | 'none' | 'standardize' | Preprocessing |
nComponents | number | all components | Maximum number of components to return |
The response contains components (eigenvalue, explained variance ratio, and cumulative variance ratio per component) and loadings (the coefficient of each variable on each component). Component scores are not returned because they are as long as the data. Use Save as Dataset on the PCA tab when you need them.
const result = await window.midas.models.run({
type: 'pca',
datasetId: 'ds_001',
columns: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
});
// result.data: { type: 'pca', runId, nObservations: 150, nVariables: 4, nComponents: 4,
// nExcluded: 0, preprocessing: 'standardize',
// components: [{ component: 1, eigenvalue, explainedVarianceRatio, cumulativeVarianceRatio }, ...],
// loadings: [{ variable: 'sepal_length', values: [...] }, ...], warnings: [] }
Kaplan-Meier (type: 'kaplan_meier'):
Estimates the survival function with the Kaplan-Meier method. eventColumn must be an int64 or boolean column, and 1 or true counts as an observed event. If eventColumn contains values other than 0/1 (false/true for boolean columns), or timeColumn contains zero or negative values, the call returns an INVALID_INPUT error listing the offending values and their row counts. With groupColumn the estimation is done per group; without it the result has a single group named 'All'. groupColumn accepts columns whose measurement scale is nominal or ordinal. Rows whose group value is missing are collected into a group named 'Unknown'.
| Parameter | Type | Default | Description |
|---|---|---|---|
timeColumn | string | (required) | Observation time column |
eventColumn | string | (required) | Event indicator column |
groupColumn | string | none | Column that defines the groups |
confidenceLevel | number | 95 | Confidence level (50-99.99) |
Each entry of groups carries the number of observations and events, the median survival time with its confidence interval, and the event times (times) with the matching survival probabilities, confidence bands, risk set sizes, event counts, and censoring counts.
const result = await window.midas.models.run({
type: 'kaplan_meier',
datasetId: 'ds_001',
timeColumn: 'time',
eventColumn: 'DEATH_EVENT',
groupColumn: 'sex'
});
// result.data: { type: 'kaplan_meier', runId, confidenceLevel: 95, nExcluded: 0,
// groups: [{ group: '0', nObservations, nEvents, medianSurvivalTime, medianSurvivalTimeCI,
// times: [...], survival: [...], survivalCILower: [...], survivalCIUpper: [...],
// nRisk: [...], nEvent: [...], nCensor: [...] }, ...], warnings: [] }
Cox regression (type: 'cox_regression'):
Fits a Cox proportional hazards model. eventColumn must be an int64 or boolean column, and covariates must be columns whose measurement scale is interval or ratio. If eventColumn contains values other than 0/1 (false/true for boolean columns), or timeColumn contains zero or negative values, the call returns an INVALID_INPUT error listing the offending values and their row counts. Rows where the time, the event, or any covariate is missing are excluded, and their count is returned as nExcluded. The API does not return the proportional hazards diagnostics; check them in the Diagnostics section of the Cox regression tab.
| Parameter | Type | Default | Description |
|---|---|---|---|
timeColumn | string | (required) | Observation time column |
eventColumn | string | (required) | Event indicator column |
covariates | string[] | (required) | Numeric covariate columns. At least 1 |
tiesMethod | 'efron' | 'breslow' | 'efron' | Handling of tied event times |
maxIterations | number | 100 | Maximum Newton-Raphson iterations |
tolerance | number | 1e-9 | Convergence tolerance |
confidenceLevel | number | 95 | Confidence level for hazard ratios (50-99.99) |
Each entry of coefficients carries the log hazard ratio, its standard error, and the hazard ratio with its confidence interval. The response also reports the log partial likelihood, AIC, the concordance index with its standard error, the convergence state, and the iteration count. The intervals are Wald intervals on the log hazard ratio, exponentiated. Besides non-convergence, warnings reports signs that the estimates are diverging (quasi-separation).
const result = await window.midas.models.run({
type: 'cox_regression',
datasetId: 'ds_001',
timeColumn: 'time',
eventColumn: 'DEATH_EVENT',
covariates: ['age', 'ejection_fraction']
});
// result.data: { type: 'cox_regression', runId, confidenceLevel: 95, tiesMethod: 'efron',
// coefficients: [{ name: 'age', coefficient, standardError, hazardRatio,
// hazardRatioCILower, hazardRatioCIUpper }, ...],
// logPartialLikelihood, aic, concordance, concordanceSE, converged, iterations,
// nObservations, nEvents, nExcluded, warnings: [] }
PCA, Kaplan-Meier, and Cox regression results are not stored as models. Passing their runId to models.save() returns INVALID_INPUT. Read the results directly from the return value of models.run().
models.save(runId, name?)
Save a model run result to the project. After saving, the model is available via models.list() and models.describe(). PCA, Kaplan-Meier, and Cox regression results are not saved as models; passing one of their runId values returns INVALID_INPUT.
const run = await window.midas.models.run({ ... });
const saved = await window.midas.models.save(run.data.runId, 'My Model');
// saved.data: { id: '...', name: 'My Model' }
A diagnostic dataset is created on demand when you open the GLM Diagnostics tab. Key columns include fitted_values, deviance_residuals, pearson_residuals, standardized_residuals, leverage, and cooks_distance. Visualize these with reports.addGraph() or Graph Builder for residual analysis and diagnostic plots.
models.saveAsDataset(id, artifact, options?)
Saves a model artifact as a derived dataset, so that later SQL, graphs, and reports can use it directly.
The artifacts are coefficients (GLM, linear regression, and GLMM fixed effects), covariance (the covariance matrix of GLM and linear regression), and blup (GLMM random effects). Asking for an artifact the model does not have returns UNSUPPORTED_MODEL_TYPE.
| Option | Type | Default | Description |
|---|---|---|---|
name | string | derived from the model name and artifact | Name of the output dataset. A name already in use gets a numeric suffix |
confidenceLevel | number | 95 | Interval level of the coefficient table (50-99.99). Unused for covariance and blup |
The dataset carries the same operation the GUI Save as Dataset writes, so it is re-derived from the model in the same way. Fitted values and predictions are not covered here; use models.predict().
const result = await window.midas.models.saveAsDataset('model_001', 'coefficients', {
confidenceLevel: 99,
});
// result.data: { datasetId: 'derived_...', name: 'My GLM Coefficients', rowCount: 3,
// columnCount: 7, artifact: 'coefficients', modelType: 'glm' }
models.predict(id, config)
Predicts new data with a saved model and stores the result as a derived dataset. GLM, linear regression, and Random Forest are supported; other model types return UNSUPPORTED_MODEL_TYPE. datasetId accepts a dataset ID or name and must contain every predictor column the model was fitted with.
| Parameter | Type | Default | Description |
|---|---|---|---|
datasetId | string | (required) | Dataset to predict |
name | string | derived from the model name | Name of the output dataset. A name already in use gets a numeric suffix |
includeOriginalData | boolean | true | Keep the columns of the source dataset in the output |
confidenceLevels | number[] | [95] | Levels for the confidence interval of the mean (50-99.99) |
predictionLevels | number[] | [95] | Levels for the prediction interval of a single new observation (50-99.99) |
For GLM and linear regression the output adds the fitted values, the linear predictor, and the standard error, plus a pair of bound columns for each level in confidenceLevels and predictionLevels. Rows with a missing predictor or offset keep their row with null values.
For Random Forest the output keeps the predictor columns the model was fitted with and adds the predicted value (and one probability column per class for classification). Columns that are not predictors, including the response, are dropped. The output has as many rows as the source; rows with a missing predictor get a null prediction and are counted in nSkipped. confidenceLevels, predictionLevels, and includeOriginalData have no meaning for Random Forest; they are ignored and reported in warnings.
const result = await window.midas.models.predict('model_001', {
datasetId: 'New Patients',
confidenceLevels: [95],
predictionLevels: [90, 95],
});
// result.data: { datasetId: 'ds_...', name: 'GLM Predictions', rowCount: 40,
// columnCount: 12, modelType: 'glm', nSkipped: 0, warnings: [] }
models.describe(id)
Get model details. Supports GLM, GLMM, Random Forest, ARIMA, Linear Regression, and ANOVA. The response structure varies by model type (check result.data.type). DoE models are not supported by describe(); inspect them in the DoE tab. Models can be created via models.run() + models.save() or through the GUI.
GLM returns coefficients, fit statistics (AIC, BIC, deviance), diagnostic summary, and metadata.
GLMM returns fixed effects (same format as GLM coefficients), random effects (group variable, variance, ICC, BLUP), fit statistics (log-likelihood, iterations, convergence), and diagnostic summary.
Random Forest returns task type (classification/regression), tuningParameters, MDI variable importances (if available), and OOB permutation importances (when computed).
ARIMA returns the orders (p, d, q and the seasonal orders), coefficients (AR/MA/SAR/SMA/Intercept/Trend with CIs), fit statistics (AIC, BIC, log-likelihood, σ², convergence), and residualDiagnostics (ACF and PACF of residuals). The residual diagnostics and fit.error from models.run() are persisted, so they are available without refitting. The acf and pacf arrays are empty either for models saved before this was added or for degenerate fits (with fit.error set). For how to interpret coefficients and fit statistics when fit.error is set, see the ARIMA notes under models.run().
Linear Regression returns coefficients (same shape as GLM; inference is always a t distribution), fit statistics (R², adjusted R², RMSE, AIC, BIC), diagnostic summary, and metadata.
ANOVA returns the ANOVA table (sum of squares, degrees of freedom, mean square, and the effect sizes η² and ω²), group statistics, Tukey HSD (only when computed), and metadata. The response structure is the same as described for ANOVA under models.run(). exclusions is omitted for models saved before this information was persisted.
const result = await window.midas.models.describe('model_001');
// GLM example - result.data:
// {
// type: 'glm',
// family: 'gaussian',
// link: 'identity',
// id: 'model_001',
// name: 'My Model',
// metadata: {
// createdAt: '2025-01-15T10:30:00Z',
// fittingDatasetId: 'ds_001',
// predictors: ['sepal_width', 'petal_length'],
// response: 'sepal_length',
// sampleSize: 150
// },
// coefficients: [
// { variable: '(Intercept)', estimate: 2.25, se: 1.02, ciLower: 0.23, ciUpper: 4.27, expEstimate: null, expCiLower: null, expCiUpper: null },
// { variable: 'sepal_width', estimate: 0.60, se: 0.24, ciLower: 0.13, ciUpper: 1.07, expEstimate: null, expCiLower: null, expCiUpper: null },
// ...
// ],
// inference: { distribution: 't', df: 147 },
// fit: { deviance: 42.3, nullDeviance: 234.7, aic: 183.94, bic: 193.47, iterations: 5, converged: true },
// diagnosticSummary: { ... }
// }
For GLMM, the coefficients under fixedEffects have the same shape as GLM coefficients, and inference is always { distribution: 'normal', df: null }. Random Forest does not include inference, coefficients, or fit fields.
// GLMM example - result.data:
// {
// type: 'glmm',
// family: 'gaussian',
// link: 'identity',
// id: 'model_002',
// name: 'Mixed Model',
// metadata: { createdAt: '2025-01-15T10:30:00Z', fittingDatasetId: 'ds_001', predictors: ['x1'], response: 'y', sampleSize: 200 },
// fixedEffects: [
// { variable: '(Intercept)', estimate: 3.14, se: 0.85, ciLower: 1.47, ciUpper: 4.81, expEstimate: null, expCiLower: null, expCiUpper: null },
// { variable: 'x1', estimate: 0.52, se: 0.18, ciLower: 0.17, ciUpper: 0.87, expEstimate: null, expCiLower: null, expCiUpper: null }
// ],
// inference: { distribution: 'normal', df: null },
// randomEffects: {
// groupColumn: 'school',
// variance: 1.23,
// residualVariance: 4.56,
// icc: 0.212,
// blup: [{ groupId: 'A', estimate: 0.45, standardError: 0.21, rank: 1 }, { groupId: 'B', estimate: -0.32, standardError: 0.19, rank: 2 }]
// },
// fit: { logLikelihood: -447.05, iterations: 12, converged: true },
// diagnosticSummary: { nObservations: 200, nGroups: 10, nFixedEffects: 2, nIncomplete: 0, groupSizes: [{ groupId: 'A', size: 20 }, { groupId: 'B', size: 15 }, { groupId: 'C', size: 25 }] }
// }
// Random Forest example - result.data:
// {
// type: 'random_forest',
// id: 'model_003',
// name: 'RF Classifier',
// metadata: { createdAt: '2025-01-15T10:30:00Z', fittingDatasetId: 'ds_001', predictors: ['x1', 'x2', 'x3'], response: 'species', sampleSize: 150 },
// taskType: 'classification',
// tuningParameters: {
// nEstimators: 100,
// maxDepth: null,
// minSamplesSplit: 2,
// minSamplesLeaf: 1,
// maxFeatures: 'sqrt',
// randomState: 42
// },
// featureImportances: [
// { feature: 'x1', importance: 0.45 },
// { feature: 'x2', importance: 0.35 },
// { feature: 'x3', importance: 0.20 }
// ],
// permutationImportances: [
// { feature: 'x1', importance: 0.38 },
// { feature: 'x2', importance: 0.42 },
// { feature: 'x3', importance: 0.12 }
// ]
// }
featureImportances is MDI (Mean Decrease in Impurity). permutationImportances is OOB permutation importance — the mean decrease in OOB prediction accuracy when each predictor is shuffled; it is undefined when not computed. Values can be negative, which means shuffling that predictor did not reduce OOB prediction accuracy. Both arrays follow the order of metadata.predictors.
models.remove(id)
Remove a model from the project. Closes any open tabs that reference the model or the resources deleted with it, then cascade-deletes associated derived datasets (diagnostic, ANOVA, coefficient tables, etc.), any datasets derived from them, and any models fitted on those derived datasets. Report elements referencing the deleted datasets or models are also removed.
await window.midas.models.remove('model_001');
models.configure(tabId, config)
Configures a model tab. Set config.type to the model type, which must match the type of the tab. The available types are glm, glmm, random_forest, arima, linear_regression, and anova. Every field other than type is optional, and only the fields you pass are changed. Column names and dataset names are resolved case-insensitively.
The available fields are the same as those of models.run() for that model type. You can set the dataset, the variable selection, the model settings, the convergence controls, and the confidence level. The one exception is ANOVA postHoc, which has no matching setting on the ANOVA tab. Whether Tukey HSD is computed is decided by models.run().
When the tab already shows results, those results no longer belong to the settings you just changed, so they are removed from the view and replaced with a message prompting another run. Use models.run() to get results, or run the analysis again in the GUI.
await window.midas.models.configure('glm_001', {
type: 'glm',
family: 'binomial',
link: 'logit',
yColumn: 'outcome',
xColumns: ['age', 'treatment'],
});
await window.midas.models.configure('arima_001', {
type: 'arima',
seriesColumn: 'sales',
order: [1, 1, 1],
seasonalPeriod: 12,
});
reports
Report text content can be modified with two methods: addContent() appends Markdown to the end of the existing content; setContent() replaces the entire content. Both methods preserve the report's elements — only the text is affected.
reports.create(name, description?)
Create a new report.
const result = await window.midas.reports.create('Analysis Report');
// result.data: { id: 'report_...', name: 'Analysis Report' }
reports.list()
List reports.
const result = await window.midas.reports.list();
// result.data: [{ id, name, elementCount }, ...]
reports.getContent(reportId)
Get report content.
const result = await window.midas.reports.getContent('report_001');
// result.data: { content: '## Analysis Results\n...', elements: [{ id, type, title, renderStatus, renderStatusMessage?, renderWarnings? }, ...] }
renderStatus is included for every element. 'ok' means no issue preventing rendering was detected, 'empty' means data rows exist but no renderable points remain, and 'error' means the element cannot render due to a missing dataset, unloaded data, a validation error in the configuration (a column type the axis does not accept, a palette incompatible with the scale type, etc.), or a facet panel count above the limit configured in Settings (Max Facet Panels). The point-level pre-render check applies only to Custom Graph elements (graphConfig.type === 'custom'). Non-custom graph elements are only checked for dataset existence and load state; their 'ok' does not mean the rendered output was verified.
Custom Graph elements also carry renderWarnings when the graph has diagnostics. The kinds of diagnostic are the same as in tabs.getGraphBuilder(). Report elements have no place to show warnings, so this content does not appear in the report view.
reports.setContent(reportId, content)
Replace all text content of the report. Text added by addContent() or addModelSummary() is also replaced. If the content contains {{type:id}} element references whose IDs are not registered in the report's elements, those are reported via result.warnings.
Elements whose {{type:id}} references are removed from the content are not automatically deleted. They remain in the report's elements and can be re-referenced by inserting {{type:id}} back into the content. To permanently remove an element, use reports.removeElement().
const result = await window.midas.reports.setContent('report_001', '## Updated Results\n...');
// result.data: { contentLength: 42 }
// result.warnings: ['Element reference {{data_table:xxx}} not found in report elements'] // when unregistered references exist
reports.addContent(reportId, markdown)
Append Markdown text to the end of a report.
await window.midas.reports.addContent('report_001', '## Analysis Results\n\nThe model shows...');
reports.addDataTable(reportId, datasetId, options?)
Add a dataset to a report as a data table element. datasetId accepts a dataset ID or name (case-insensitive). The element is registered as type: 'data_table' under report.elements, and a {{data_table:elementId}} reference is appended to the content.
const result = await window.midas.reports.addDataTable('report_001', 'Species Averages', {
columns: ['species', 'avg_sl'],
maxRows: 10
});
// result.data: { elementId, reportId, renderStatus, renderStatusMessage? }
Options:
columns(string[]) — Columns to display, by column name or column ID. When omitted, all columns are displayedmaxRows(number) — Maximum number of rows to display. A positive integer, capped at 1000. When omitted, all rows are displayed (up to 1000)
Returns a NO_DATA error for datasets whose data has not been evaluated. renderStatus is 'empty' when the dataset has no rows, and 'ok' otherwise.
reports.addModelSummary(reportId, modelId)
Add a model summary to a report. Supports GLM, GLMM, Linear Regression, Random Forest, ARIMA, ANOVA, and DoE. For DoE it adds only a fit-statistics model_stats element (no coefficient table yet).
All model types use the element-reference scheme (the same as addGraph). For GLM, GLMM, and Linear Regression, the coefficient table is added as a type: 'data_table' element under report.elements, and a {{data_table:elementId}} reference is inserted into the report content. For Random Forest, Feature Importance is added as a type: 'data_table' element (Feature and MDI columns, plus a Permutation column when permutation importances are available; sorted by Permutation descending when available, otherwise by MDI descending) when featureImportances is available. The underlying derived dataset is registered in project.datasets, so it also appears in the Data tab listing. Deleting a model automatically removes associated coefficient datasets and prunes any report element that references the deleted datasets or model — data_table, model_stats, graph_builder, crosstab, statistics_summary, and anova. The modelId argument must refer to a saved model; otherwise the call returns APIResult.success === false.
For GLM, GLMM, and Linear Regression, the Model Fit / Random Effects / OLS Fit summary is registered as a type: 'model_stats' element under report.elements, and a {{model_stats:elementId}} reference is inserted into the report content. The element stores only the model id and resolves values from project.models[modelId] at render time, so when the same model id is refitted and project.models is overwritten, existing reports automatically reflect the new values. If the model is deleted after the report is created, the model_stats element renders a "Model not found" placeholder.
GLM and GLMM coefficient tables share the same columns: Variable, Estimate, Std. Error, Lower N%, Upper N%. For logit and log links, exp-transformed columns are appended: OR / IRR / exp(Est.), exp(Lower N%), exp(Upper N%). N is the confidence level saved with the model (confidenceLevel, default 95). Linear Regression coefficient tables additionally include Std. Coef. and VIF. Confidence intervals are Wald-type (estimate ± criticalValue × SE). For GLM, the critical value depends on family and link: families that estimate the dispersion parameter from data use , while families with use (see the table under models.run()). For GLMM fixed effects, MIDAS always uses the asymptotic standard normal distribution as an implementation choice. Linear Regression always uses the t distribution.
What each model type renders:
- GLM: The
model_statselement renders a Model Fit section with AIC, BIC, Deviance, Null Deviance, Converged, and iterations. - GLMM: When BLUP data exists, a BLUP table (Group, Conditional Mode, Std. Error, Rank — sorted by estimate descending) is added as a
data_tableelement, with a### Random Effects (BLUP)heading and{{data_table:blupElementId}}reference in the content (result.data.blupElementIdreturns the id). Themodel_statselement renders a Random Effects section with Group Variable, Number of Groups, Random Intercept Variance, Residual Variance (LMM only), and ICC; and a Model Fit section with Log-Likelihood, AIC, BIC, Converged, and iterations. For LMM (Gaussian + identity link), labels read REML Log-Likelihood and ICC; for Binomial + logit/probit, they read Log-Likelihood (Laplace) and ICC (latent scale). For other family+link combinations (Poisson, Gamma, etc.), ICC is not displayed (null) because no theoretically grounded latent-scale residual variance exists. - Linear Regression: Five elements are registered — coefficient table, ANOVA Type I, ANOVA Type III, Prediction Intervals (per-observation prediction / confidence intervals), and a
model_statselement. Themodel_statselement renders an OLS Fit section with R², Adjusted R², RMSE, and N observations, plus an Information Criteria section with AIC and BIC. Converged / iterations are not shown because they are trivial for OLS. - Random Forest: A Feature Importance
data_tableelement (Feature and MDI columns, plus a Permutation column when permutation importances are available; sorted by Permutation descending when available, otherwise by MDI descending) whenfeatureImportancesis available, and amodel_statselement rendering a Model Configuration section (Task Type, Number of Trees, Max Depth, Min Samples Split, Min Samples Leaf, Max Features) and OOB Accuracy (classification) or OOB R² (regression). - ARIMA: The coefficient table (AR, MA, SAR, SMA, and Intercept or Drift terms with confidence intervals) is added as a
data_tableelement, and themodel_statselement renders a Model Fit section with Order (including the seasonal (P, D, Q)[s] part for seasonal models), Log-Likelihood, AIC, BIC, σ², Converged, and N observations. - ANOVA: ANOVA Table and Group Statistics are registered as
data_tableelements. For one-way ANOVA with a computed Tukey HSD, a Tukey HSD table is also added. Nomodel_statselement is registered.
const result = await window.midas.reports.addModelSummary('report_001', 'model_001');
// result.data: { reportId, addedText, elementId?, statsElementId?, anovaTypeIElementId?, anovaTypeIIIElementId?, groupStatisticsElementId?, tukeyHSDElementId?, predictionIntervalsElementId?, blupElementId? }
// - elementId: id of the coefficient / Feature Importance / ANOVA Table data_table element (RF: only when featureImportances is non-empty)
// - statsElementId: id of the model_stats element that renders Model Fit / Random Effects / OLS Fit / Model Configuration (not returned for ANOVA)
// - blupElementId: id of the BLUP data_table element for GLMM (only when BLUP data exists)
// - anovaTypeIElementId / anovaTypeIIIElementId / predictionIntervalsElementId: Linear Regression only
// - groupStatisticsElementId: id of the Group Statistics table for ANOVA
// - tukeyHSDElementId: id of the Tukey HSD table for ANOVA (only when Tukey HSD is computed)
When called multiple times for the same model, the coefficients dataset is reused when an existing derived dataset has both the same name and an identical operation definition. Calling this method after refitting the same model with different fit conditions returns APIResult.success === false with a Dataset with name "X" already exists error, because the derived dataset would have the same name but a different operation definition. To record summaries for multiple fit configurations, either delete the previous model or save the new model under a different name before calling this method. Report elements and text are added anew each time.
reports.addGraph(reportId, config)
Add a graph to a report as a report element. Creates a Custom Graph without opening a tab. datasetId accepts a dataset ID or name (case-insensitive). Column names are also resolved case-insensitively. Properties not recognized by AddGraphInput or LayerDefInput are reported in result.warnings. Axis scales (scales), per-layer scales (layers[].scales), per-layer tooltips (layers[].tooltip, see addGraphLayer), and facets (facets) can be specified. See configureGraph for the facets property reference. For a graph that draws an intermediate aggregate, set lineageTargetDatasetId (an ancestor of datasetId) to make selection and drill-down act on the underlying data (see configureGraph).
const result = await window.midas.reports.addGraph('report_001', {
datasetId: 'ds_001',
layers: [
{ geom: { type: 'point' }, aes: { x: 'weight', y: 'height' } }
],
title: 'Weight vs Height',
aspectRatio: 'custom',
height: 500,
});
// result.data: { elementId, reportId, renderStatus, renderStatusMessage?, renderWarnings? }
renderStatus indicates the rendering outcome. 'ok' means data points exist and all specified aes properties are applied. 'partial' means data points exist and will be drawn, but some aes properties were not supported by the geom and were ignored (the graph may not match the intended visualization). 'empty' means data rows exist but no renderable points remain (for example, all rows were removed by filters). 'error' means the graph fails validation (a column type the axis does not accept, a palette incompatible with the scale type, a missing required aesthetic, etc.) and cannot render. renderStatusMessage provides a reason when the status is not 'ok'. renderWarnings is also included when the graph has diagnostics. The kinds of diagnostic are the same as in tabs.getGraphBuilder(), and since the report view does not show them, this API is the only way to read them.
Faceted graphs are evaluated with the same data processing as the actual rendering. MIDAS splits the data into panels, computes the domains shared across all panels, and then evaluates each panel individually. States that appear only after panel splitting are detected by this evaluation, so renderStatus and renderWarnings match the rendered result. Each line of renderWarnings carries the title of the panel that reported it, and a warning reported identically by every panel is merged into a single line prefixed with All panels:. When the number of panels exceeds the limit configured in Settings (Max Facet Panels), the graph is not rendered and renderStatus is 'error'.
The graph is stored as a report element and a {{graph_builder:elementId}} reference is appended to the report content.
See Custom Graph Reference for the list of geom, stat, and position types. Each Statistic's params are documented there with their accepted values and defaults. For facets, coordinates, and other graph-level options, see Custom Graph.
coordinates accepts 'flipped' or 'cartesian'. When 'flipped' is specified, the X and Y axes are swapped (e.g., vertical bars become horizontal bars). Defaults to 'cartesian'.
aspectRatio accepts '16:9', '4:3', '1:1', '3:4', '9:16', or 'custom'. Defaults to '16:9'. When a preset value other than 'custom' is specified, the aspect ratio determines the displayed height and height is not used for rendering. When 'custom' is specified, height sets the height. height defaults to 400, minimum 200, maximum 5000.
reports.updateElement(reportId, elementId, config)
Replace the configuration of an existing graph_builder element (full replacement). The element retains its ID and position in the report content. config has the same structure as addGraph (datasetId accepts a dataset ID or name).
const result = await window.midas.reports.updateElement('report_001', 'graph-xxx', {
datasetId: 'ds_001',
layers: [
{ geom: { type: 'bar' }, aes: { x: 'category', y: 'count' } }
],
title: 'Updated Chart',
});
// result.data: { elementId, reportId, renderStatus, renderStatusMessage?, renderWarnings? }
renderStatus, renderStatusMessage, and renderWarnings mean the same as in addGraph().
Specifying an element type other than graph_builder (e.g. data_table, model_stats) returns an error.
reports.removeElement(reportId, elementId)
Remove an element from a report and its {{type:elementId}} reference from the content. Supports all element types (graph_builder, data_table, model_stats, crosstab, statistics_summary, anova). Associated resources (derived datasets, models) are not deleted.
await window.midas.reports.removeElement('report_001', 'graph-xxx');
// result.data: { elementId, reportId }
reports.remove(reportId)
Remove a report from the project. Closes any open tabs that reference the report.
await window.midas.reports.remove('report_001');
layout
layout.split(config)
Split a pane to create a new area.
const result = await window.midas.layout.split({
tabId: 'tab_001',
direction: 'horizontal' // 'horizontal' or 'vertical'
});
// result.data: { newPaneId: 'pane_...', originalPaneId: 'pane_...' }
Use the returned newPaneId with tabs.moveToPane() to place tabs in the new pane.
layout.get()
Get how the panes are arranged. To move a tab into a pane you did not create with layout.split() yourself, take its ID from here and pass it to tabs.moveToPane().
const result = await window.midas.layout.get();
// result.data: { rootPane, activePaneId }
rootPane is a tree of panes. Each node is either a split or a pane: type is 'split' for a split and 'container' for a pane.
A split describes how its area is divided. direction is 'horizontal' for a left-right split and 'vertical' for a top-bottom one. splitRatio is the share taken by the first of the two children. children holds them in order: left then right for a horizontal split, top then bottom for a vertical one.
A pane holds tabs. Each entry of tabs has the same shape as in tabs.list(). activeTabId is the tab shown at the front, or null when the pane has no tabs. activePaneId names the pane operated on last, so compare a pane's id against it to tell whether that pane is the active one.
Both kinds of node carry rect, the position and size within the layout area expressed as fractions of the whole, with the origin at the top-left. It comes from the split ratios, so it does not account for the width of the resizers between panes.
A pane also carries viewportRect, the measured position and size of its DOM element in viewport coordinates, in pixels and on the same basis as getBoundingClientRect(). It is null before the pane is rendered. Resizing the window and dragging a resizer both change it, so read it again when matching it against a screenshot.
// In a layout whose right half is split top and bottom, move a tab into the lower pane
const { rootPane } = (await window.midas.layout.get()).data;
const [, right] = rootPane.children;
const [, rightBottom] = right.children;
await window.midas.tabs.moveToPane('tab_001', rightBottom.id);
Error Codes
| Code | Description |
|---|---|
ERROR | General error |
NO_PROJECT | No project is loaded |
NOT_FOUND | Specified resource not found |
DATASET_NOT_FOUND | No dataset matching the table name |
COLUMN_NOT_FOUND | Column not found |
INVALID_TAB_TYPE | Invalid tab type |
INVALID_TAB_TYPE_FOR_OPERATION | Tab type does not support this operation |
INVALID_GRAPH_TYPE | Layer operation attempted on non-custom graph |
INVALID_INPUT | Invalid input parameter |
INDEX_OUT_OF_RANGE | Layer index out of range |
DATASET_ALREADY_EXISTS | Dataset with the same name (case-insensitive) already exists (when overwrite is false) |
SELF_REFERENCE | The dataset being overwritten is a dependency (ancestor) of the operation |
NAME_CONFLICT | Output name of a derived method collides with an existing primary dataset |
OPERATION_TYPE_MISMATCH | The existing derived dataset was created by a different method. Each derived method (derive, addColumns, setColumnSchema, addOrthogonalPolynomials, reshapeWideToLong, reshapeLongToWide, dummyCode, filter) writes its own operation type. Overwriting across types is rejected — e.g., calling derive() on a dataset originally created by addColumns(), or calling addColumns() on a dataset created by derive() |
AMBIGUOUS_TABLE_NAME | Multiple datasets match the table name case-insensitively |
EXECUTION_ERROR | SQL execution error |
UNSUPPORTED_MODEL_TYPE | Unsupported model type |
MODEL_EXECUTION_ERROR | Model execution error |
NUMERICAL_ERROR | Numerical computation error (e.g., matrix singularity) |
INSUFFICIENT_DATA | Not enough data for the analysis (e.g., too few valid observations or factor levels) |
NO_DATA | Dataset has no data loaded |
NO_CONTAINER | No active container |
NO_TARGET | No table reference in SQL |
NO_CONFIG | No Graph Builder configuration |
SPLIT_FAILED | Pane split failed |
SANDBOX_MODE | Cannot save in sandbox mode |
NO_SIGNING_KEY | Cannot export or download because no signing key is configured |
ENUM_ALREADY_EXISTS | Enum definition already exists |
ENUM_NOT_FOUND | Enum definition not found |
ENUM_IN_USE | Enum definition is referenced by columns |
ENUM_VALUE_MISMATCH | Data contains values outside the enum definition |
FETCH_ERROR | URL fetch failure (network error, timeout, HTTP error) |
USER_CANCELLED | User cancelled the operation (e.g. declined unsaved changes confirmation) |
Reference
- Live reference: Run
window.midas.help()in the project screen
Also available as a Markdown file.