---
title: Agent API (window.midas)
description: window.midas API を使って、AI エージェントや Playwright などの外部ツールから MIDAS を操作できます。データセットの取得、タブの操作、モデルの実行、レポートの編集などをプログラムから実行できます。
priority: 0.6
---

# Agent API (window.midas) {#agent-api-windowmidas}

AI エージェントや Playwright などの外部ツールから MIDAS をプログラムで操作するための API です。

- [概要](#overview)
- [使い方](#usage)
- [レスポンス形式](#response-format)
- [データモデル](#data-model)
- [メソッド一覧](#method-reference): [status](#status) / [project](#project) / [datasets](#datasets) / [enums](#enums) / [tabs](#tabs) / [models](#models) / [reports](#reports) / [layout](#layout)
- [エラーコード](#error-codes)

## 概要 {#overview}

`window.midas` は、ブラウザの DevTools コンソールや Playwright などの自動化ツールから MIDAS の機能にアクセスするための JavaScript API です。データセットの操作、タブの管理、統計モデルの実行、レポートの編集などを行えます。

### API が利用可能なタイミング {#availability}

- **プロジェクト画面**: すべてのメソッドが利用可能
- **ランチャー画面**: `help()`、`project.openFile()`、`project.openUrl()` が利用可能。他のメソッドは `NO_PROJECT` エラーを返す

Playwright で自動化する場合は、`project.openFile()` または `project.openUrl()` でプロジェクトを開いてから他の API メソッドを使用してください。

### AI エージェント向けクイックスタート {#quick-start-for-ai-agents}

1. [`status()`](#status) でプロジェクトの状態を確認します（データセット数、タブ数、モデル数）
2. [`datasets.list()`](#datasetslist) と [`datasets.describe(id)`](#datasetsdescribeid) でデータの構成を把握します
3. [データモデル](#data-model)で永続化、データセットの種類、グラフ仕様の構造を理解します
4. 目的に応じて[メソッド一覧](#method-reference)から操作を選びます

## 使い方 {#usage}

### DevTools コンソールから使う {#from-devtools-console}

ブラウザの DevTools を開き、コンソールで直接呼び出します。

```javascript
// プロジェクトの状態を確認
const result = await window.midas.status();
console.log(result.data);
// { datasets: 3, tabs: 2, models: 1, ... }
```

### Playwright から使う {#from-playwright}

```javascript
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}

`help()` メソッドで、利用可能なメソッドの一覧とシグネチャを確認できます。戻り値には `documentation` フィールドがあり、パラメータの詳細や設定オプションを記載したこのページの URL が含まれます。

```javascript
const help = window.midas.help();
console.log(help.documentation);
// "https://midas-app.org/docs/en/agent-api.md"
```

## レスポンス形式 {#response-format}

`help()` を除くすべてのメソッドは非同期で、`APIResult<T>` 型の統一されたレスポンスを返します。`help()` のみ同期メソッドで、`HelpInfo` オブジェクトを直接返します。

```javascript
// 成功時
{
  success: true,
  message: "Found 3 datasets",
  data: [...]
}

// 失敗時
{
  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"
  }
}
```

`warnings` フィールドが含まれる場合もあります。処理自体は成功していますが、注意が必要な点を示します。たとえば [`models.run()`](#modelsrunconfig) ではデータ準備段階の警告がトップレベルの `warnings` に、モデル実行時の警告が `data.warnings` に格納されます。

```javascript
// 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}

API を使う前に、MIDAS がデータをどう管理しているかを把握しておくと操作の見通しが立ちやすくなります。

### 永続化 {#persistence}

API の操作はメモリ上のプロジェクト状態を変更します。[ブラウザストレージ](privacy-security)への書き込みは [`project.save()`](#projectsave) を呼んだときだけ行われます。`save()` を呼ばずにページをリロードすると、そのセッションの変更はすべて失われます。

```javascript
// データセットのスキーマを変更
await window.midas.datasets.setColumnSchema('ds_001', { ... });

// この時点ではメモリ上だけに反映されている

await window.midas.project.save();
// ブラウザストレージに書き込まれた
```

### DataSet の種類 {#dataset-types}

[`datasets.list()`](#datasetslist) が返すデータセットには 2 つの種類があります。

**Primary** — CSV などからインポートした元データです。データ本体をプロジェクトファイル内に保持します。

**Derived** — SQL やクロス集計などの変換操作から作成されたデータです。データ本体ではなく操作の定義（どの SQL を実行したか等）をプロジェクトファイルに保存します。データはキャッシュであり、プロジェクトファイルには含まれません。プロジェクトを開くたびに親データセットから再計算されるため、その時点の親データが反映されます。`parentIds` で親への依存関係を確認できます。

```javascript
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 が内部のレンダリング用に一時的に作成する Ephemeral DataSet がありますが、[`datasets.list()`](#datasetslist) には含まれません。

### レポート要素のライフサイクル {#report-element-lifecycle}

レポートは 2 つの部品で構成されます。Markdown テキストの **content** と、グラフやモデルサマリーなどの **elements** です。content の中に `{{graph_builder:element_001}}` のような参照を書くと、その位置に対応する要素が描画されます。

[`reports.addGraph()`](#reportsaddgraphreportid-config) や [`reports.addModelSummary()`](#reportsaddmodelsummaryreportid-modelid) は要素の作成と content への参照挿入を一度に行います。[`reports.removeElement()`](#reportsremoveelementreportid-elementid) は要素と content 内の参照を同時に除去します。

モデルやデータセットを削除すると、それに依存するレポート要素は自動的に除去されます。手動で掃除する必要はありません。

### グラフ仕様の構造 {#graph-specification}

Custom Graph の設定は 2 層に分かれています。

**グラフレベル** — データソース、座標系（`coordinates`）、ファセット（`facets`）、軸スケール（`scales`）など、グラフ全体に関わる設定です。[`tabs.configureGraph()`](#tabsconfiguregraphtabid-config) や [`reports.addGraph()`](#reportsaddgraphreportid-config) で指定します。

**レイヤー** — 幾何要素（`geom`: 散布図の点、折れ線など）、統計変換（`stats`）、aesthetic mapping（`aes`: どの列を X 軸・色・サイズに対応させるか）を組み合わせた描画単位です。1 つのグラフに複数のレイヤーを重ねられます。[`tabs.addGraphLayer()`](#tabsaddgraphlayertabid-layer) で追加します。各レイヤーは `scales` で color/fill チャネルのカラースケールを個別に設定できます。

グラフレベルの `globalAes` は全レイヤーの既定値になり、各レイヤーの `aes` で上書きできます。

設定の詳細は [Custom Graph](custom-graph) と [Custom Graph Reference](custom-graph-reference) を参照してください。

## メソッド一覧 {#method-reference}

### status() {#status}

プロジェクトの状態を取得します。

```javascript
const result = await window.midas.status();
// result.data:
// {
//   datasets: 3,
//   derivedDatasets: 1,
//   tabs: 2,
//   models: 1,
//   reports: 1,
//   activeDatasetId: 'ds_001',
//   activeTabId: 'tab_001'
// }
```

### project {#project}

#### project.save() {#projectsave}

プロジェクトをブラウザストレージに保存します。保存先の詳細は[プライバシーとセキュリティ](privacy-security)を参照してください。

```javascript
await window.midas.project.save();
```

サンドボックスモード（デモやトライアルなど、永続化が無効なプロジェクト）では `SANDBOX_MODE` エラーを返します。

#### project.exportMds() {#projectexportmds}

プロジェクトを MDS（MIDAS のプロジェクトファイル形式）バイナリとしてエクスポートします。エクスポートされたデータは `ArrayBuffer` として返されます。

```javascript
const result = await window.midas.project.exportMds();
// result.data: { data: ArrayBuffer, size: 12345, suggestedFilename: 'MyProject.mds' }
```

#### project.downloadMds() {#projectdownloadmds}

プロジェクトを MDS ファイルとしてブラウザからダウンロードします。

```javascript
const result = await window.midas.project.downloadMds();
// result.data: { filename: 'MyProject.mds' }
```

#### project.openFile(data, options?) {#projectopenfile}

MDS バイナリデータ（`Uint8Array`）からプロジェクトを開きます。ランチャー画面でも実行できます。

```javascript
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' }
```

オプション:

- `sandbox` (boolean, デフォルト: `false`) — `true` の場合、新しい ID を振ってブラウザストレージへの保存をスキップします
- `onDuplicate` (`'overwrite'` | `'copy'`, デフォルト: `'overwrite'`) — 同一 ID のプロジェクトがブラウザストレージに存在する場合の挙動を指定します。`'overwrite'` は既存を上書きし、`'copy'` は重複時のみ新しい ID を割り当てます

現在のプロジェクトに未保存の変更がある場合、確認ダイアログが表示されます。ユーザーがキャンセルすると `USER_CANCELLED` を返します。署名警告はダイアログを表示せず、戻り値の `warnings` 配列で通知します。

#### project.openUrl(url, options?) {#projectopenurl}

URL から MDS ファイルをフェッチしてプロジェクトを開きます。常にサンドボックスモードで開かれます（ブラウザストレージには保存されません）。ランチャー画面でも実行できます。

```javascript
const result = await window.midas.project.openUrl('https://example.com/project.mds');
// result.data: { projectId: 'project-xxx' }
```

オプション:

- `signal` (AbortSignal) — フェッチの中断に使用します

現在のプロジェクトに未保存の変更がある場合、確認ダイアログが表示されます。ユーザーがキャンセルすると `USER_CANCELLED` を返します。署名警告はダイアログを表示せず、戻り値の `warnings` 配列で通知します。

URL のバリデーションとセキュリティ制限は [`datasets.importFromURL()`](#datasetsimportfromurlurl-options) と同じです。プロトコルは HTTP/HTTPS のみ許可され、クラウドメタデータエンドポイントへのアクセスはブロックされます。ブロックされた URL には `INVALID_INPUT` エラーを返します。信頼済み URL リストに含まれない URL に対しては警告が `warnings` に含まれ、設定で「信頼されていないドメインへの接続をブロック」を有効にしている場合はエラーになります。詳細は [プライバシーとセキュリティ](privacy-security) を参照してください。ネットワークエラー・タイムアウトのいずれの場合も `FETCH_ERROR` を返します。

### datasets {#datasets}

#### datasets.list() {#datasetslist}

プロジェクト内のデータセット一覧を取得します。

```javascript
const result = await window.midas.datasets.list();
// result.data: [{ id, name, rows, columns, type, parentIds? }, ...]
```

`type` は `'primary'`（読み込んだデータ）または `'derived'`（SQL やその他の操作で作成）のいずれかです。`parentIds` は派生データセットの場合に、元となったデータセットの ID を含みます。一時的な内部データセット（ephemeral）は一覧に含まれません。

#### datasets.describe(id) {#datasetsdescribeid}

データセットの詳細情報を取得します。データセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。

```javascript
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: 'string', scale: 'nominal', enumName: 'species_enum' },
//     ...
//   ]
// }
```

`columns` の各要素には `id`、`name`、`type` が含まれます。`scale` と `enumName` はオプショナルです。`enumName` は列の型が enum の場合に、対応する enum 定義の名前を返します。

#### datasets.profile(id) {#datasetsprofileid}

データセットの各列について基本統計量を返します。データセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。未実体化の派生データセット（保存済みプロジェクトを開いた直後など、まだ再計算されていないもの）には `NO_DATA` エラーを返します。タブで開くか、そのデータセットを参照するクエリを実行すると実体化されます。

```javascript
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 }
//       ]
//     },
//     ...
//   ]
// }
```

全列に `nullCount` と `uniqueCount` が含まれます。`uniqueCount` は null 以外の全ユニーク値数で、非有限値（Infinity、NaN）も含みます。数値列（`int64`、`float64`）には `nonFiniteCount`（Infinity や NaN の件数）、`min`、`max`、`mean`、`median`、`sd`（標本標準偏差、n-1 で除算）が追加されます。非有限値は統計量の計算から除外されます。有効な数値が存在しない場合は `min`〜`sd` の値が `null` になります。`sd` は有効な値が 1 件のみ（n < 2）の場合も `null` です。文字列列と enum 列には `topValues`（頻度上位 5 件まで）が追加されます。

#### datasets.query(sql, options?) {#datasetsquerysql-options}

SQL クエリを実行し、行データを返します。データセットの作成・変更は行いません。SQL は DuckDB の構文に従います。

```javascript
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: [...] }
```

テーブル名はデータセット名から自動解決されます（大文字小文字を区別しません）。日本語やスペースを含むデータセット名は、SQL 内でダブルクォートで囲んでください（例: `SELECT * FROM "売上データ"`）。`options.limit` と `options.offset` でページネーションを制御できます。`limit` を省略すると全行が返されます。

受け付けられるのは単一の SELECT 文のみです。セミコロン区切りの複数ステートメントや DML/DDL は拒否されます。

#### datasets.derive(sql, name, options?) {#datasetsderivesql-name-options}

SQL クエリを実行し、結果を新しい派生データセットとして保存します。SQL は DuckDB の構文に従います。

```javascript
const result = await window.midas.datasets.derive(
  'SELECT species, AVG(sepal_length) as avg_sl FROM Iris GROUP BY species',
  'Species Averages'
);
// result.data: { datasetId: 'derived_...', name: 'Species Averages', rowCount: 3, columnCount: 2, overwrote: false }
```

テーブル名はデータセット名から自動解決されます（大文字小文字を区別しません）。日本語やスペースを含むデータセット名は、SQL 内でダブルクォートで囲んでください（例: `SELECT * FROM "売上データ"`）。`derive()` の完了時点で結果データはメモリ上に実体化されており、直後に [`datasets.fetch()`](#datasetsfetchid-options) や [`datasets.profile()`](#datasetsprofileid) で参照できます。デフォルトでは同名の派生データセットが存在する場合に in-place で更新します。既存のデータセット ID が維持されるため、そのデータセットを参照しているタブや依存する派生データセットは影響を受けません。`options.overwrite` を `false` にすると、同名の派生データセットが既に存在する場合にエラーを返します。

出力名が SQL の `FROM` / `JOIN` で参照しているデータセット、またはそれらの祖先（参照先データセットの派生元）のいずれかと同じ ID に解決される場合、依存関係の循環を生む操作になるため `SELF_REFERENCE` エラーを返します（例: `derive('SELECT species, COUNT(*) FROM Iris GROUP BY species', 'Iris')`、または `Iris → A → B` のチェーンで `derive('SELECT * FROM B', 'A')`）。また、出力名がプライマリデータセットの名前と一致する場合は `NAME_CONFLICT` エラーを返します（プライマリを派生で上書きしません）。同名の派生データセットが異なるメソッドで作成されている場合（例: `addColumns` で作成したデータセットを `derive` で上書きしようとした場合）は `OPERATION_TYPE_MISMATCH` エラーを返します。

SQL が複数のテーブルを参照している場合（`JOIN` やサブクエリ）、参照された全データセットの ID が派生データセットの `parentIds` として保存されます。`datasets.list()` で取得できる各派生データセットのエントリに `parentIds` 配列が含まれます。Project Lineage タブでは各親から派生データセットへのエッジとして表示されます。

受け付けられるのは単一の SELECT 文のみです。セミコロン区切りの複数ステートメントや DML/DDL は拒否されます。外部からデータを取り込む場合は `datasets.importFromURL` または `datasets.importFromBuffer` を使ってください。

#### datasets.importFromURL(url, options?) {#datasetsimportfromurlurl-options}

外部 URL から CSV/TSV ファイルをフェッチしてデータセットとして取り込みます。

```javascript
const result = await window.midas.datasets.importFromURL(
  'https://example.com/data.csv'
);
// result.data: { datasetId: 'ds_...', name: 'data', rowCount: 100, columnCount: 5 }
```

`options` の `name` プロパティで取り込み後のデータセット名を指定できます。省略した場合は URL から推測されます。同名（大文字小文字を区別しない）のデータセットが既に存在する場合はエラー（`DATASET_ALREADY_EXISTS`）を返します。`options.overwrite` を `true` にすると、既存のデータセットを in-place で置き換えます（ID が維持されます）。`importFromURL` / `importFromBuffer` はプライマリデータセットも上書きできます（派生系メソッドとの非対称性）。返却される `columnCount` は元ファイルの列数と一致します。MIDAS が内部で追加する行番号列（`Row#`）はカウントに含まれません。

CSV パースに失敗した場合（空データ、ヘッダー行が空、行ごとの列数が食い違う、URL バリデーション失敗、Content-Type 不正など）は `INVALID_INPUT` エラーを返します。ネットワーク障害やタイムアウトは `EXECUTION_ERROR` を返します。サイズ警告閾値（デフォルト 10 MB、Settings で変更可能）を超えるファイルはインポートされますが、サイズ警告が `result.warnings` に含まれます。

URL のバリデーションとセキュリティ制限が適用されます。プロトコルは HTTP/HTTPS のみ許可され、クラウドメタデータエンドポイントへのアクセスはブロックされます。信頼済み URL リストに含まれない URL に対しては警告が発生し、設定で「信頼されていないドメインへの接続をブロック」を有効にしている場合はエラーになります。詳細は[プライバシーとセキュリティ](privacy-security)を参照してください。

#### datasets.importFromBuffer(data, options?) {#datasetsimportfrombufferdata-options}

`ArrayBuffer` または TypedArray（`Uint8Array`、Node.js の `Buffer` など）から CSV/TSV データをデータセットとして取り込みます。Playwright のテストから HTTP サーバーを立てずにローカル CSV を読み込みたい場合に使用します。

```javascript
// Playwright: ローカル CSV を 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: { datasetId: 'ds_...', name: 'Sales', rowCount: 500, columnCount: 7 }
```

`data` は `ArrayBuffer` または `ArrayBufferView`（`Uint8Array`、`DataView`、Node.js の `Buffer` 等）を受け付けます。`options` のプロパティは次のとおりです。

- `name`: 取り込み後のデータセット名。省略時は `"Untitled"`
- `hasHeader`: 先頭行をヘッダーとして扱うか。省略時は `true`
- `encoding`: 文字エンコーディング（`"utf-8"`、`"shift_jis"`、`"euc-jp"`）。省略時はバイト列から自動判定
- `overwrite`: 同名のデータセットが存在する場合に上書きするか。省略時は `false`

区切り文字は PapaParse が自動判定するため、CSV と TSV のどちらも渡せます。返却される `columnCount` は元ファイルの列数と一致します。MIDAS が内部で追加する行番号列（`Row#`）はカウントに含まれません。

同名（大文字小文字を区別しない）のデータセットが既に存在する場合はエラー（`DATASET_ALREADY_EXISTS`）を返します。`overwrite: true` で既存を in-place で置き換えられます（ID 維持）。`importFromBuffer` はプライマリデータセットも上書きできます（派生系メソッドとの非対称性）。CSV パースに失敗した場合（空データ、ヘッダー行が空、行ごとの列数が食い違う、など）は `INVALID_INPUT` エラーを返します。

#### datasets.reloadFromURL(options?) {#datasetsreloadfromurloptions}

URL から取り込んだデータセットを元の URL から再取得して更新します。

```javascript
// すべての URL-sourced データセットを再取得
const result = await window.midas.datasets.reloadFromURL();
// result.data: { reloaded: [{ datasetId, name, rowCount, previousRowCount }], failed: [] }

// 特定のデータセットのみ再取得
const result = await window.midas.datasets.reloadFromURL({
  datasetId: 'primary_abc123',
});
```

`options.datasetId` を指定すると、そのデータセットだけを再取得します。省略すると、URL から取り込まれたすべてのプライマリデータセットが対象になります。指定した ID のデータセットが存在しない場合は `DATASET_NOT_FOUND` エラー、存在するが URL から取り込まれたものでない場合は `INVALID_INPUT` エラーを返します。

再取得ではデータセット ID、名前、派生データセット、モデルとの紐づけが維持されます。除外行と行コメントはクリアされます。再取得先の CSV のスキーマ（列数・列名・型）が元のデータセットと一致しない場合、そのデータセットのリロードは失敗します。

`result.data.reloaded` には再取得に成功したデータセットの情報（`datasetId`、`name`、更新後の行数 `rowCount`、更新前の行数 `previousRowCount`）が含まれます。`result.data.failed` には失敗したデータセットの情報（`datasetId`、`name`、`sourceUrl`、`error`）が含まれます。一部のデータセットが失敗した場合でも `success` は `true` になります。全件失敗した場合のみ `success: false` になります。

#### datasets.addColumns(datasetId, input) {#datasetsaddcolumnsdatasetid-input}

計算列をデータセットに追加します。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。結果は新しい派生データセットとして作成されます。`expression` は DuckDB の SQL 式構文に従います。`CASE WHEN` や `CAST` 等の SQL 関数も使用できます。

```javascript
const result = await window.midas.datasets.addColumns('Iris', {
  columns: [
    { name: 'bmi', expression: 'weight / (height * height)' }
  ]
});
// result.data: { datasetId: 'derived_...', name: '...', rowCount: 150, columnCount: 6 }
```

`outputName` で出力データセット名を指定できます。同名の派生データセットが存在する場合は in-place で更新し、既存のデータセット ID を維持します。`outputName` がソース `datasetId` またはその祖先（派生元のデータセット）のいずれかに解決される場合、依存関係の循環を防ぐため `SELF_REFERENCE` エラーを返します。同名のプライマリデータセットと衝突する場合は `NAME_CONFLICT` エラーを返します。同名の派生データセットが異なるメソッドで作成されている場合は `OPERATION_TYPE_MISMATCH` エラーを返します。

#### datasets.addOrthogonalPolynomials(datasetId, input) {#datasetsaddorthogonalpolynomialsdatasetid-input}

直交多項式列をデータセットに追加します。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。多項式回帰の説明変数として使用します。

```javascript
const result = await window.midas.datasets.addOrthogonalPolynomials('Iris', {
  column: 'temperature',
  degree: 3
});
// result.data: { datasetId: 'derived_...', name: '...', rowCount: 150, columnCount: 8, columnNames: ['temperature_poly1', 'temperature_poly2', 'temperature_poly3'] }
```

`degree` の最大値は 30 です。`outputName` で出力データセット名を指定できます。`outputName` がソース `datasetId` またはその祖先（派生元のデータセット）のいずれかに解決される場合、依存関係の循環を防ぐため `SELF_REFERENCE` エラーを返します。同名のプライマリデータセットと衝突する場合は `NAME_CONFLICT` エラーを返します。同名の派生データセットが異なるメソッドで作成されている場合は `OPERATION_TYPE_MISMATCH` エラーを返します。

#### datasets.setColumnSchema(datasetId, columnId, schema) {#datasetssetcolumnschemadatasetid-columnid-schema}

列のデータ型、測定尺度、enum 定義を変更します。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。

```javascript
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` には `type`、`scale`、`enumName` を指定できます。少なくとも1つは必須です。データ型の変更は SQL による型変換を伴うため、新しい派生データセットが作成されます。同名の出力データセットが既に存在する場合は in-place で更新し、既存のデータセット ID を維持します。`outputName` がソースデータセット自身またはその祖先（派生元のデータセット）を指す場合、依存関係の循環を防ぐため `SELF_REFERENCE` エラーを返します。同名のプライマリデータセットと衝突する場合は `NAME_CONFLICT` エラーを返します。同名の派生データセットが異なるメソッドで作成されている場合は `OPERATION_TYPE_MISMATCH` エラーを返します。測定尺度のみの変更はメタデータの更新のみで、派生データセットは作成されません。

enum 型への変換では、列の値が全て enum 定義内または NULL である必要があります。定義外の値が存在する場合は `ENUM_VALUE_MISMATCH` で拒否されます。事前に [Convert Column Types](column-type-conversion) タブで不要な値を NULL 化または除外するか、[`enums.update`](#enumsupdatename-values) で定義に値を追加してください。

#### datasets.remove(id) {#datasetsremoveid}

データセットをプロジェクトから削除します。データセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。対象データセットを参照しているタブを閉じたあと、依存する派生データセットとモデルをカスケード削除します。

```javascript
await window.midas.datasets.remove('Iris');
```

#### datasets.fetch(id, options?) {#datasetsfetchid-options}

データセットの行データを副作用なしで取得します。データセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。

```javascript
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, ... }, ...]
// }
```

`limit` と `offset` で取得範囲を制御します。省略時は全行を返します。未実体化の派生データセット（保存済みプロジェクトを開いた直後など、まだ再計算されていないもの）には `NO_DATA` エラーを返します。タブで開くか、そのデータセットを参照するクエリを実行すると実体化されます。

#### datasets.buildMapping(datasetId, columnId, input) {#datasetsbuildmapping}

文字列列または enum 列のユニーク値に対して value → canonical のマッピングデータセットを生成します。

```javascript
// Key Collision: 全角統一 → 小文字化
const result = await window.midas.datasets.buildMapping('ds_001', 'city', {
  method: { type: 'key_collision', normalizers: ['fullwidth', 'case'] }
});
// result.data: { datasetId: 'primary_...', changedCount: 3, valueCount: 7 }

// Nearest Neighbor: 編集距離
const result2 = await window.midas.datasets.buildMapping('ds_001', 'city', {
  method: { type: 'nearest_neighbor', method: 'levenshtein', threshold: 2 }
});
```

`method.type` は `'key_collision'` または `'nearest_neighbor'` を指定します。

**Key Collision** は決定的な正規化関数を順序付きで適用し、canonical の初期値を生成します。`normalizers` に適用順で指定します。利用可能な normalizer: `'trim'`（前後空白除去）、`'fullwidth'`（NFKC 正規化）、`'kana'`（カタカナ→ひらがな）、`'case'`（小文字化）、`'fingerprint'`（小文字化・句読点除去・重複排除・トークンソート）。

**Nearest Neighbor** は距離関数で近傍の値をグルーピングし、クラスタ内の最頻値を canonical の初期値とします。`method` は `'levenshtein'`（編集距離）を指定します。`threshold`（デフォルト: 2）で距離の閾値を設定します。ユニーク値数の上限は 10,000 です。

`overrides` で特定の値の canonical を上書きできます。`name` でデータセット名を指定できます（デフォルト: `{source}_{column}_mapping`）。

結果は `value` 列と `canonical` 列を持つ Primary DataSet です。

#### datasets.normalize(datasetId, columnId, mappingDatasetId, input?) {#datasetsnormalize}

マッピングデータセットを使って元データを正規化します。SQL JOIN で `value` → `canonical` の変換を適用します。

```javascript
const result = await window.midas.datasets.normalize('ds_001', 'city', mp.data.datasetId, {
  mode: 'replace'
});
// result.data: { datasetId: 'derived_...', name: 'sales_normalized', rowCount: 100, columnCount: 5 }
```

`mode` は `'add'`（デフォルト）で `{column}_normalized` 列を追加、`'replace'` で元列を `COALESCE(canonical, 元値)` で置き換えます。`name` で出力データセット名を指定できます（デフォルト: `{source}_normalized`）。マッピングデータセットは `value` 列と `canonical` 列を持つ任意のデータセットを指定できます。

#### datasets.traceRowLineage(datasetId, rowIndices) {#datasetstracerowlineage}

派生データセットの指定行に寄与した親データセットの行を 1 ホップ分たどります。derive クエリの最上段の集約を外して親の `Row #` を射影する probe クエリに書き換えて再実行し、指定行の値に一致する親行を集めます。

```javascript
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` は対象データセット内の 0 始まりの行インデックスです。0 以上の整数のみ受け付けます。空配列、非整数、負値はいずれも `INVALID_INPUT` エラーになります。範囲外の整数は無視します。戻り値の `contributions` は関与した親データセットごとの寄与行で、JOIN では複数要素になります。各 `rowIndices` は昇順で重複しません。複数行を渡すと寄与はまとめて返り、行ごとの内訳は付きません。行ごとに調べるには 1 行ずつ呼び出します。

たどれるのは次の形です。GROUP BY 集計（式によるキー、序数や出力エイリアスでの GROUP BY を含む）、JOIN、FROM のサブクエリと CTE、素の射影とフィルタ、DISTINCT、テーブル全体の集計（全行が寄与）。

たどれない形のときは `traceable: false` と `reason` を返します。

- `window-function`: ウィンドウ関数または QUALIFY 句を含む
- `set-operation`: UNION などの集合演算を含む
- `nondeterministic`: TABLESAMPLE や ORDER BY を伴わない LIMIT を含む
- `nested-aggregation`: FROM のサブクエリや CTE がそれ自身集計している
- `ambiguous-group-keys`: GROUP BY のキーが出力列に無く、行のキー値を読めない
- `no-parent-table`: FROM が登録済みの親データセットに解決できない
- `not-derived`: 対象が派生データセットでない
- `unsupported-operation`: SQL クエリ以外の操作で作られている
- `parse-failed`: クエリの構造を解析できなかった

`reason` によっては `detail` に補足が入ります。解決できなかったテーブル名（`no-parent-table`）、元の operation 種別（`unsupported-operation`）、`TABLESAMPLE` などです。

### enums {#enums}

#### enums.create(name, values) {#enumscreatename-values}

enum 定義を作成します。値は最大 50 個まで設定できます。

```javascript
const result = await window.midas.enums.create('color', ['red', 'green', 'blue']);
// result.data: { name: 'color', valueCount: 3 }
```

#### enums.list() {#enumslist}

enum 定義の一覧を取得します。

```javascript
const result = await window.midas.enums.list();
// result.data: [{ name: 'color', values: ['red', 'green', 'blue'] }, ...]
```

#### enums.update(name, values) {#enumsupdatename-values}

既存の enum 定義の値を更新します。

```javascript
await window.midas.enums.update('color', ['red', 'green', 'blue', 'yellow']);
```

値は最大 50 個まで設定できます。値を削除する場合、この enum 型の列を持つデータセットに削除対象の値が残っていれば `ENUM_VALUE_MISMATCH` で拒否されます。enum 列の値は常に定義内または NULL である不変条件を維持するためです。先に [Convert Column Types](column-type-conversion) タブで該当値を NULL 化または除外するか、値を残したまま定義に保持してください。

#### enums.remove(name) {#enumsremovename}

enum 定義を削除します。列がまだこの enum を参照している場合は `ENUM_IN_USE` エラーで拒否されます。

```javascript
await window.midas.enums.remove('color');
```

### tabs {#tabs}

#### tabs.list() {#tabslist}

開いているタブの一覧を取得します。

```javascript
const result = await window.midas.tabs.list();
// result.data: [{ id, type, title }, ...]
```

#### tabs.open(config) {#tabsopenconfig}

新しいタブを開きます。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。`graph-builder` タブではデータセットがタブに紐づき、データセット選択欄と [`tabs.getGraphBuilder()`](#tabsgetgraphbuildertabid) に反映されます。

```javascript
// 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' }

// SQL Editor を開く
const result2 = await window.midas.tabs.open({
  type: 'sql-editor',
  initialQuery: 'SELECT * FROM Iris LIMIT 10',
  initialOutputName: 'Preview'
});
```

利用可能なタブタイプ:

| タイプ | 説明 |
|--------|------|
| `graph-builder` | Graph Builder |
| `sql-editor` | SQL Editor |
| `glm` | GLM |
| `glmm` | GLMM |
| `random-forest` | Random Forest |
| `linear-regression` | 線形回帰 |
| `pca` | 主成分分析 |
| `statistics` | 記述統計 |
| `crosstab` | クロス集計 |
| `anova` | ANOVA |
| `kaplan-meier` | Kaplan-Meier |
| `cox-regression` | Cox 回帰 |
| `doe-analysis` | 実験計画法 |
| `arima` | ARIMA |
| `data-table` | データテーブル |
| `report` | レポート（`reportId` が必要） |
| `computed-column` | 計算列 |
| `dummy-coding` | ダミーコーディング |
| `orthogonal-polynomials` | 直交多項式 |
| `reshape` | データ整形 |
| `column-type-conversion` | 型変換 |
| `enum-definition` | enum 定義 |
| `project-overview` | プロジェクト概要 |
| `project-lineage` | Project Lineage |
| `selected-rows` | 選択行 |
| `excluded-rows` | 除外行 |
| `filtered-data` | フィルタ済みデータ |
| `model-detail` | モデル詳細（`modelId` が必要） |
| `glm-diagnostics` | GLM 診断（`modelId` が必要） |
| `glm-prediction` | GLM 予測（`modelId` が必要） |
| `sql-query-viewer` | SQL クエリビューア |
| `variant-normalization` | 表記揺れ正規化 |
| `apply-mapping` | マッピング適用 |
| `project-diff` | プロジェクト差分 |
| `help` | ヘルプ |

`report` タブには `reportId`、`model-detail`・`glm-diagnostics`・`glm-prediction` タブには `modelId` の指定が必須です。`modelId` には [`models.list()`](#modelslist) で取得した保存済みモデルの ID を指定します。省略すると `INVALID_INPUT` エラーを返します。

```javascript
// モデル詳細タブを開く
const result3 = await window.midas.tabs.open({
  type: 'model-detail',
  modelId: 'model_001'
});
```

`glm-diagnostics` タブは GLM と線形回帰（`linear_regression`）の両方のモデルを開けます。線形回帰モデルでは Deviance/Pearson 残差の切り替えを省き、見出しを Residual Diagnostics に変えて表示します。

`models.run()` が対応するモデルタイプは `glm`、`glmm`、`random_forest`、`arima`、`linear_regression`、`anova` の 6 つです。対応するタブ（`glm`、`glmm`、`random-forest`、`arima`、`linear-regression`、`anova`）およびその他の分析タブ（`pca`、`kaplan-meier`、`cox-regression`、`doe-analysis`、`crosstab`、`statistics`）はすべて `tabs.open()` で開けますが、上記 6 タイプ以外は API からフィットできず、設定と実行は GUI で行います。

#### tabs.close(id) {#tabscloseid}

タブを閉じます。

```javascript
await window.midas.tabs.close('tab_001');
```

#### tabs.closeOthers(keepTabId) {#tabscloseotherskeeptabid}

指定したタブ以外をすべて閉じます。

```javascript
const result = await window.midas.tabs.closeOthers('tab_001');
// result.data: { closedCount: 3 }
```

#### tabs.getGraphBuilder(tabId) {#tabsgetgraphbuildertabid}

Graph Builder タブの設定を取得します。

```javascript
const result = await window.midas.tabs.getGraphBuilder('tab_001');
// result.data: { tabId, graphType, datasetId, config, aspectRatio }
```

#### tabs.addGraphLayer(tabId, layer) {#tabsaddgraphlayertabid-layer}

カスタムグラフにレイヤーを追加します。`graphType` が `'custom'` のタブでのみ使用できます。

```javascript
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 マッピング (`aes`) ではカラム名またはカラム ID を指定します。カラム名は大文字小文字を区別せずに解決されます。利用可能なプロパティは `x`、`y`、`color`、`fill`、`stroke`、`size`、`shape`、`alpha`、`linetype`、`ymin`、`ymax`、`label`、`group` です。すべてのプロパティがすべての geom type で使えるわけではありません。例えば Point と Line は `fill` に対応していません。固定色を使う場合は `{ fixedColor: '#FF0000' }` 形式で、固定サイズは正の数値で、固定アルファ（不透明度）は 0 から 1 の数値で指定できます。範囲外の固定値は警告とともに無視されます。`stats` を省略した場合はデフォルトで `identity` が設定されます。`position` を省略した場合、bar geom では `{ type: "stack" }`（積み上げ）、それ以外の geom では `identity` がデフォルトです。geom ごとに使用できる position type は異なります（例: line は `identity` のみ）。使用できない position を指定すると `INVALID_INPUT` エラーが返ります。`scales` でレイヤー固有のカラースケール（`color`、`fill`）を設定できます。詳細は [configureGraph](#tabsconfiguregraphtabid-config) のレイヤースケールの説明を参照してください。

Label geom (`{ type: 'label' }`) で集約 stat（summary, count, bin 等）を使う場合、`aes.label` で指定した列は集約時に失われます。代わりに `geom.defaults.labelContent` で stat 出力変数を参照できます。

```javascript
await window.midas.tabs.addGraphLayer(tabId, {
  geom: {
    type: 'label',
    defaults: {
      labelContent: { field: '$y', format: '.1f', prefix: 'Mean: ' }
    }
  },
  stats: [{ type: 'summary', params: { fun: 'mean' } }],
});
```

`labelContent` のプロパティ:

| プロパティ | 型 | 説明 |
|---|---|---|
| `field` | `string` | 表示するフィールド。`$x`、`$y`、`$n` 等の stat 変数またはカラム名 |
| `format` | `string` | d3-format 形式の書式指定（例: `.2f`、`,.0f`） |
| `prefix` | `string` | 値の前に付ける文字列 |
| `suffix` | `string` | 値の後に付ける文字列 |

`labelContent` が設定されている場合、`aes.label` は不要です。

レイヤーには以下のオプションプロパティも指定できます。

| プロパティ | 型 | 説明 |
|---|---|---|
| `name` | `string` | レイヤーの表示名 |
| `filter` | `string` | レイヤーのデータを絞り込む SQL WHERE 式 |
| `visible` | `boolean` | レイヤーの表示/非表示（デフォルト `true`） |
| `yAxis` | `'primary' \| 'secondary'` | 使用する Y 軸 |
| `showLegend` | `'auto' \| 'show' \| 'hide'` | レイヤーの凡例表示 |
| `clickSelection` | `boolean` | データポイントのクリック選択を有効にする |

利用可能な geom、stat、position の一覧は [Custom Graph リファレンス](custom-graph-reference)を参照してください。各 Statistic の [`params`](custom-graph-reference#stat-params) は指定可能な値とデフォルト値とともに同ページに掲載しています。ファセット、座標系などグラフレベルのオプションは [Custom Graph](custom-graph) を参照してください。

#### tabs.updateGraphLayer(tabId, layerIndex, layer) {#tabsupdategraphlayertabid-layerindex-layer}

既存のレイヤーを部分更新します。指定したフィールドのみが変更され、省略したフィールドは既存の値を保持します。

```javascript
await window.midas.tabs.updateGraphLayer('tab_001', 0, {
  geom: { type: 'line' }
});
```

geom を変更した際、現在の position が新しい geom で許可されていない場合は `identity` に自動リセットされ、warning が返ります。許可されない position を明示指定した場合は `INVALID_INPUT` エラーが返ります。

`scales: null` を渡すとレイヤー固有のカラースケールを削除し、グローバルスケールに戻します。`position: null` で position をデフォルト（未設定）にリセットできます。

#### tabs.removeGraphLayer(tabId, layerIndex) {#tabsremovegraphlayertabid-layerindex}

レイヤーを削除します。

```javascript
await window.midas.tabs.removeGraphLayer('tab_001', 0);
```

#### tabs.moveToPane(tabId, toPaneId) {#tabsmovetopanetabid-topaneid}

タブを別のペインに移動します。[`layout.split()`](#layoutsplitconfig) で作成したペインの ID を指定します。

```javascript
await window.midas.tabs.moveToPane('tab_001', 'pane_002');
```

#### tabs.setDataset(tabId, datasetId) {#tabssetdatasettabid-datasetid}

タブのデータセットを切り替えます。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。`graph-builder` タブでは、切り替えたデータセットがデータセット選択欄と [`tabs.getGraphBuilder()`](#tabsgetgraphbuildertabid) に反映されます。

```javascript
await window.midas.tabs.setDataset('tab_001', 'ds_002');
```

#### tabs.configureGraph(tabId, config) {#tabsconfiguregraphtabid-config}

Graph Builder タブを一括設定します。`graphType` でグラフタイプを選びます。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定でき、空文字を渡すとデータセットの紐づけを解除します。カラム名は大文字小文字を区別せずに解決されます。`GraphConfigInput` や `LayerDefInput` に存在しないプロパティが渡された場合は `result.warnings` で通知されます。

```javascript
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'
});
```

`coordinates` で座標系を設定できます。`'flipped'` は X 軸と Y 軸を入れ替えます（カテゴリ名が長い横棒グラフなどに有用です）。`'cartesian'` はデフォルトのデカルト座標系に戻します。

```javascript
await window.midas.tabs.configureGraph('tab_001', {
  coordinates: 'flipped'
});
```

`scales` で軸スケールを設定できます。`configureGraph` で `scales` を渡すと、指定した軸のみ上書きし、指定しなかった軸の設定は保持されます。

```javascript
await window.midas.tabs.configureGraph('tab_001', {
  scales: { y: { type: 'log', title: 'Log scale' } }
});
```

`scales` の各軸（`x`、`y`、`y2`）には以下を指定できます。

| プロパティ | 型 | 説明 |
|---|---|---|
| `type` | `'linear' \| 'log' \| 'sqrt' \| 'time' \| 'categorical'` | スケールの種類 |
| `title` | `string` | 軸タイトル |
| `domain` | `{ min?, max? }` | 連続スケールの範囲（`categorical` では無効） |
| `tickCount` | `number` | 目盛りの数（`categorical` では無効） |
| `limits` | `string[]` | カテゴリの表示順（`categorical` 用） |
| `breaks` | `string[]` | 表示するカテゴリのサブセット（`categorical` 用） |
| `labels` | `Record<string, string>` | カテゴリのカスタム表示名（`categorical` 用） |
| `labelRotation` | `'auto' \| 0 \| 45 \| 90` | ラベルの回転角度 |

レイヤーごとのカラースケールは `layers[].scales` で設定します。`color` と `fill` チャネルに対して個別にスケールを指定できます。

```javascript
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' } }
  }]
});
```

レイヤースケールの `color` / `fill` には以下を指定できます。

| プロパティ | 型 | 説明 |
|---|---|---|
| `scaleType` | `'categorical' \| 'sequential' \| 'diverging' \| 'threshold'` | カラースケールの種類 |
| `paletteId` | `string` | パレット ID。有効な値の一覧は [Custom Graph リファレンス](custom-graph-reference#palettes) を参照 |
| `domain` | `{ min?, max?, center? }` | 連続スケールのドメイン |
| `legendPosition` | `'right' \| 'left' \| 'top' \| 'bottom' \| 'none'` | 凡例の位置 |
| `legendTitle` | `string` | 凡例のタイトル |
| `thresholds` | `number[]` | 閾値の配列（`threshold` 用） |
| `thresholdColors` | `string[]` | 各領域の色（`threshold` 用、長さ = `thresholds.length + 1`） |
| `thresholdVariable` | `'x' \| 'y'` | 閾値の比較に使う変数（`threshold` 用、デフォルト `'y'`） |

`facets` でカテゴリ変数によるパネル分割（ファセット）を設定できます。`wrap`（1 変数で自動配置）と `grid`（行・列の 2 変数）の 2 種類があります。

```javascript
// Facet wrap: 1 変数でパネル分割
await window.midas.tabs.configureGraph('tab_001', {
  facets: { type: 'wrap', variable: 'species', ncol: 3, scales: 'free_y' }
});

// Facet grid: 行・列の変数でパネル分割
await window.midas.tabs.configureGraph('tab_001', {
  facets: { type: 'grid', rows: 'region', cols: 'year' }
});

// ファセットを解除
await window.midas.tabs.configureGraph('tab_001', { facets: null });
```

`facets` を省略すると既存の設定が保持されます。

Facet wrap のプロパティ:

| プロパティ | 型 | 説明 |
|---|---|---|
| `type` | `'wrap'` | Facet wrap モード |
| `variable` | `string` | 分割するカラム名またはカラム ID（必須） |
| `ncol` | `number` | 列数（省略時は自動計算） |
| `nrow` | `number` | 行数（省略時は自動計算） |
| `complete` | `boolean` | 全組み合わせのパネルを表示して欠損を補完する |
| `scales` | `'fixed' \| 'free_x' \| 'free_y' \| 'free'` | パネル間の軸スケール共有方法（デフォルト: `'fixed'`） |

Facet grid のプロパティ:

| プロパティ | 型 | 説明 |
|---|---|---|
| `type` | `'grid'` | Facet grid モード |
| `rows` | `string` | 行方向の分割カラム名またはカラム ID |
| `cols` | `string` | 列方向の分割カラム名またはカラム ID |
| `complete` | `boolean` | 全組み合わせのパネルを表示して欠損を補完する |
| `scales` | `'fixed' \| 'free_x' \| 'free_y' \| 'free'` | パネル間の軸スケール共有方法（デフォルト: `'fixed'`） |

Facet grid では `rows` と `cols` の少なくとも一方が必要です。

`graphType` に `histogram`、`scatter`、`timeseries`、`bar`、`pairplot`、`datetime_histogram` を指定すると、そのタイプ固有のフィールドを設定できます。`layers`、`globalAes`、`scales`、`coordinates`、`facets` は `custom` でのみ有効です。

```javascript
await window.midas.tabs.configureGraph('tab_001', {
  graphType: 'histogram',
  datasetId: 'ds_001',
  column: 'sepal_length',
  bins: 20
});
```

`column` や `xColumn`、`categoryColumn` などの列を指定するフィールドは、カラム名またはカラム ID のどちらでも指定できます。タイプ固有のフィールドは次のとおりです。

| グラフタイプ | フィールド |
|---|---|
| `histogram` | `column`、`bins`、`showDensity`、`orientation`、`groupByColumn`、`groupMode`、`facetNcol`、`showAnnotations` |
| `scatter` | `xColumn`、`yColumn`、`colorColumn`、`sizeColumn`、`referenceLines`、`xScaleType`、`yScaleType`、密度可視化系（`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` |

`bar` の `valueColumns` には集計対象のカラムのほか、行数を数える `'$count'` を指定できます。`aggregations` はカラムごとの集計方法を指定します。

`boxplot` と `heatmap` は設定できません。指定すると `INVALID_GRAPH_TYPE` エラーを返します。

### models {#models}

#### models.list() {#modelslist}

適合済みモデルの一覧を取得します。

```javascript
const result = await window.midas.models.list();
// result.data: [{ id, type, name, datasetId, family }, ...]
```

`type` は `'glm'`、`'glmm'`、`'random_forest'`、`'arima'`、`'linear_regression'`、`'anova'` のいずれかです。

#### models.run(config) {#modelsrunconfig}

モデルを実行します。`config.type` で `'glm'`、`'glmm'`、`'random_forest'`、`'arima'`、`'linear_regression'`、`'anova'` を指定します。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。primary または derived データセットが対象です（ephemeral データセットは使用できません）。カラムは名前で指定でき、大文字小文字を区別しません。結果はタブを開かず直接返されます。[`models.list()`](#modelslist) や [`models.describe()`](#modelsdescribeid) で後から参照するには、返された `runId` を [`models.save()`](#modelssaverunid-name) に渡してモデルを保存してください。未保存の実行結果はメモリ上に最大 20 件保持されます。上限を超えると最も古い未保存の結果から順に破棄され、破棄された `runId` は [`models.save()`](#modelssaverunid-name) に渡せなくなります。ページリロードでもすべて消失します。

**GLM** (`type: 'glm'`):

```javascript
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: []
// }
```

`coefficients` の各フィールド:

| フィールド | 説明 |
|---|---|
| `estimate` | リンクスケールの係数推定値 |
| `se` | 推定値の標準誤差 |
| `ciLower` / `ciUpper` | Wald 信頼区間の下限と上限。参照分布は `inference` フィールドが示します。family ごとの対応は後述の表を参照してください |
| `expEstimate` / `expCiLower` / `expCiUpper` | 推定値と信頼区間を `exp()` で変換した値。解釈と `null` になるリンクは後述の説明を参照してください |

`diagnosticSummary.dispersionParameter` は分散パラメータ φ の推定値です。`gaussian` では deviance を残余自由度 n−p で除した値、`gamma` では Pearson χ² を n−p で除した値で、これらの family では SE と信頼区間の計算に使われます。`poisson` と `binomial` では SE の計算に φ = 1 を使い、このフィールドには過分散の診断指標として deviance/(n−p) が入ります。残余自由度が 0 の場合は `null` です。`negative-binomial` では θ を自動推定した場合は 1.0、θ を固定した場合は Pearson χ²/(n−p) です。

**GLMM** (`type: 'glmm'`):

`groupColumn` でランダム切片のグループ変数を指定します。`family` は `'gaussian'`、`'binomial'`、`'poisson'`、`'gamma'` から選択します（デフォルト `'gaussian'`）。`link`、`includeIntercept`、`confidenceLevel` も GLM と同じ意味で指定できます。`maxIterations` のデフォルトは 100、`tolerance` のデフォルトは 1e-6 です（GLM とは異なります）。モデルの背景は [GLMM](glmm) を参照してください。

```javascript
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, ciLower: 0.64, ciUpper: 4.06, ... },
//     ...
//   ],
//   inference: { distribution: 'normal', df: null },
//   randomEffects: {
//     groupColumn: 'species',
//     variance: 0.42,
//     residualVariance: 0.14,
//     icc: 0.75,
//     blup: [{ groupId: 'setosa', estimate: -0.31, standardError: 0.12, rank: 3 }, ...]
//   },
//   fit: { logLikelihood: -72.1, iterations: 8, converged: true },
//   diagnosticSummary: { nObservations: 150, nGroups: 3, nFixedEffects: 3, nIncomplete: 0, groupSizes: [...] },
//   warnings: []
// }
```

GLMM の固定効果の信頼区間は標準正規分布に基づく Wald 近似で、`inference` は常に `{ distribution: 'normal', df: null }` です。グループ数が少ない場合、この近似による信頼区間は名目の被覆率を下回ることがあります。

`randomEffects` の各フィールド:

- `variance` — ランダム切片の分散 σ²_u です
- `residualVariance` — `gaussian` では残差分散 σ²_e、`gamma` では推定された分散パラメータ φ です。`binomial` と `poisson` では φ が理論的に 1 に固定されるため返されません
- `icc` — 級内相関係数 σ²_u / (σ²_u + σ²_e) です。σ²_e は `gaussian` + `identity` では REML で推定した残差分散、`binomial` + `logit` では π²/3、`binomial` + `probit` では 1 で、後の 2 つは潜在尺度の値です。それ以外の family と link の組み合わせでは潜在尺度の残差分散が定義できないため `null` になります
- `blup` — グループ別ランダム切片の予測値（Best Linear Unbiased Prediction）です。固定効果による予測値からの残差（y − Xβ̂）のグループ平均を 0 に向けて縮小した値で、観測数が少ないグループほど縮小の度合いが大きくなります。`standardError` は予測の不確実性を表し、LMM では条件付き予測誤差の標準偏差、それ以外の family では Laplace 近似に基づく近似値です。`rank` は `estimate` の降順順位です

LMM（`gaussian` + `identity`）では `fit.logLikelihood` は REML 対数尤度で、`fit.aic` と `fit.bic` もこれに基づきます。REML に基づく AIC/BIC は固定効果の構成が異なるモデル間の比較には使えません。それ以外の family では Laplace 近似による対数尤度です。

**Random Forest** (`type: 'random_forest'`):

`taskType` で `'classification'` または `'regression'` を指定します。`metrics` には適合データに対する評価指標（resubstitution metrics）が含まれます。汎化性能の推定には `oobScore` を使用してください。

```javascript
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, minSamplesSplit: 2, minSamplesLeaf: 1, maxFeatures: 'sqrt', randomState: 42 },
//   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: []
// }
```

Random Forest の `metrics` は `taskType` によって構造が変わります。`'regression'` の場合は `{ taskType: 'regression', mse, rmse, mae, r2 }` が返されます。`metrics` は適合データに対する値であり、[`models.describe()`](#modelsdescribeid) では取得できません（永続化されないため）。汎化性能の推定には `oobScore` を使用してください（分類では OOB accuracy、回帰では OOB R-squared）。`permutationImportances` は各 predictor をシャッフルした際の OOB 予測精度の平均低下量です。値は負になることがあります。これはシャッフルしても OOB 予測精度が低下しなかったことを意味します。

| パラメータ | 型 | デフォルト | 説明 |
|-----------|-----|-----------|------|
| `nEstimators` | `number` | `100` | 決定木の本数 |
| `maxDepth` | `number \| null` | `null` | 最大深度（`null` で無制限） |
| `minSamplesSplit` | `number` | `2` | ノード分割に必要な最小サンプル数 |
| `minSamplesLeaf` | `number` | `1` | 葉ノードの最小サンプル数 |
| `maxFeatures` | `'sqrt' \| 'log2' \| null \| number` | `'sqrt'` | 各分割で検討する説明変数の数 |
| `randomState` | `number` | `42` | 乱数シード |

`inference` は `ciLower`、`ciUpper` の計算に使われた参照分布を表します。`distribution: 't'` のとき自由度 `df` の t 分布、`distribution: 'normal'` のとき標準正規分布で、後者では `df` は `null` になります。

family ごとの対応は次のとおりです。`β̂/SE` が t(n−p) に厳密に従うのは Gaussian + identity link のみで、他の分散パラメータ推定族は有限標本補正の慣習として t 分布を適用します。漸近と書かれた family は標準正規近似です。

| family | link | 参照分布 | 性質 |
|--------|------|----------|------|
| `gaussian` | `identity` | t(n−p) | 厳密 |
| `gaussian` | 非 identity | t(n−p) | 有限標本補正の慣習 |
| `gamma` | 任意 | t(n−p) | 有限標本補正の慣習 |
| `negative-binomial` | 任意（θ 固定） | t(n−p) | 有限標本補正の慣習 |
| `poisson` | 任意 | 標準正規 | 漸近 |
| `binomial` | 任意 | 標準正規 | 漸近 |
| `negative-binomial` | 任意（θ 推定） | 標準正規 | 漸近 |

`ciLower` と `ciUpper` は各係数の Wald 信頼区間 `estimate ± criticalValue × se` です。信頼水準は `confidenceLevel` パラメータ（デフォルト 95）に従います。臨界値は `inference` の参照分布の `(1 + confidenceLevel/100) / 2` 分位点を使います。

`expEstimate`、`expCiLower`、`expCiUpper` は link スケールの推定値と信頼区間を `exp()` で変換した値です。logit リンクではオッズ比 (OR)、Poisson・Negative Binomial の log リンクでは率比 (IRR)、Gamma・Gaussian の log リンクでは乗法的効果に対応します。identity、inverse、probit リンクでは `null` になります。

`fit.aic` と `fit.bic` は `number | null` です。対数尤度の定数項が定義できない場合（Binomial の非整数重み、飽和モデルなど）に `null` になります。

レスポンスには2種類の warnings が含まれる場合があります。トップレベルの `result.warnings` にはデータ準備段階の警告（欠測行の除外など）、`result.data.warnings` にはモデル実行時の警告（収束の問題など）が格納されます。応答変数と説明変数のいずれかに欠測がある行は分析から除外されます。除外された行数は `diagnosticSummary.nIncomplete` で確認できます。

最大反復回数までに収束しなかった場合もエラーにはならず、結果は `fit.converged: false` で返されます。`message` にも did not converge と表示されます。完全分離・準完全分離が疑われる場合は `data.warnings` に警告が含まれます。結果が返る場合、係数の `se` が `null` になることはありません。SE が計算できない場合（分散共分散行列が正定値でない、計画行列のランク落ちなど）は結果を返さず `NUMERICAL_ERROR` エラーになります。適合した平均が family の有効範囲外になる場合（例: Poisson や Gamma に identity link を当てた場合）も結果を返さず `NUMERICAL_ERROR` になります。適合した平均が範囲内に収まる link（log など）を検討してください。

`family` は `'gaussian'`（デフォルト）、`'binomial'`、`'poisson'`、`'gamma'`、`'negative-binomial'` から選択します。各 family の選択指針と使い分けは [GLM](glm) を参照してください。`link` でリンク関数を指定できます。省略した場合は family に応じたデフォルトが使われます。

| family | デフォルト link | 利用可能な link |
|--------|---------------|----------------|
| `gaussian` | `identity` | `identity`, `log` |
| `binomial` | `logit` | `logit`, `probit` |
| `poisson` | `log` | `log`, `identity` |
| `gamma` | `inverse` | `inverse`, `log`, `identity` |
| `negative-binomial` | `log` | `log` |

**オプションパラメータ:**

| パラメータ | 型 | デフォルト | 説明 |
|-----------|-----|-----------|------|
| `includeIntercept` | `boolean` | `true` | 切片の有無 |
| `maxIterations` | `number` | `25` | 最大反復回数 |
| `tolerance` | `number` | `1e-8` | 収束判定の許容誤差 |
| `binomialResponse` | `object` | - | 二項応答の形式。下記参照 |
| `theta` | `number` | - | 負の二項分布の過分散パラメータ。省略した場合はプロファイル尤度で自動推定される |
| `offsetColumn` | `string` | - | オフセット列（ポアソン回帰での exposure 等） |
| `confidenceLevel` | `number` | `95` | 信頼区間の信頼水準（50〜99.99） |

`theta` を省略して自動推定した場合、係数の SE と信頼区間は推定された θ を固定値として扱って計算されます。θ 自体の推定不確実性は SE に反映されません。

**`binomialResponse` の指定:**

`family: 'binomial'` の場合に応答変数の形式を指定します。`binomialResponse` を省略した場合は binary として扱われます。

- `{ format: 'binary' }` -- 0/1 の二値データ。`yColumn` で応答変数を指定します
- `{ format: 'grouped', successesColumn: '...', trialsColumn: '...' }` -- 成功数/試行数のペア。この場合 `yColumn` は省略できます

```javascript
// Grouped Binomial の例
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'`):

単一の時系列列に ARIMA(p,d,q) モデルを適合します。`order` に `[p, d, q]` を指定するか、`autoSelect` で次数の格子探索を行い AIC または BIC が最小のモデルを選択します。

| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| `seriesColumn` | `string` | (必須) | 時系列データの列名 |
| `order` | `[number, number, number]` | — | `[p, d, q]` — AR 次数、差分次数、MA 次数。省略時は `autoSelect` を使用 |
| `autoSelect` | `object` | `{ maxP: 3, maxD: 1, maxQ: 3, criterion: 'aic' }` | 自動次数選択。`order` 省略時に使用 |
| `autoSelect.maxP` | `number` | `3` | 探索する AR 次数の上限 |
| `autoSelect.maxD` | `number` | `1` | 探索する差分次数の上限 |
| `autoSelect.maxQ` | `number` | `3` | 探索する MA 次数の上限 |
| `autoSelect.criterion` | `'aic' \| 'bic'` | `'aic'` | モデル選択の情報量基準 |
| `includeIntercept` | `boolean` | `true` | 切片（d > 0 の場合はドリフト）を含める |
| `confidenceLevel` | `number` | `95` | 係数の信頼区間の信頼水準 |

レスポンスには `coefficients`（AR/MA/Intercept と CI）、`fit`（AIC, BIC, 対数尤度, σ², 収束状態）、`residualDiagnostics`（残差の ACF と PACF）、`nObservations` が含まれます。`autoSelect` 使用時は `orderSearch` に全候補次数の AIC/BIC が含まれます。

観測数が不足している、または差分後の系列の分散がゼロで適合が縮退した場合は、`fit.error` にメッセージが入ります。このとき係数や AIC、σ² などは無意味な値（ゼロや無限大）になり、`residualDiagnostics` の `acf` と `pacf` は空配列です。これは最適化が収束しなかった場合（`converged: false` で `fit.error` なし）とは区別されます。

系列中の非有限値（NaN, Infinity, null）は除外されます。除外が発生した場合、レスポンスの `warnings` に報告されます。

```javascript
// 手動で次数を指定
const result = await window.midas.models.run({
  type: 'arima',
  datasetId: 'ds_001',
  seriesColumn: 'temperature',
  order: [1, 1, 1]
});

// 自動次数選択
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'`):

最小二乗法による線形回帰を適合します。

| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| `yColumn` | `string` | (必須) | 応答変数の列名 |
| `xColumns` | `string[]` | (必須) | 説明変数の列名 |
| `includeIntercept` | `boolean` | `true` | 切片の有無 |
| `confidenceLevel` | `number` | `95` | 信頼区間の信頼水準 |

レスポンスの `coefficients` は GLM と同形式で、`inference` は常に t 分布です。`fit` には GLM と同じフィールドに加えて `rSquared`、`adjustedRSquared`、`rmse` が含まれます。

```javascript
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'`):

一元配置または二元配置の分散分析を実行します。`factorColumns` の要素数でどちらかが決まります。

| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| `responseColumn` | `string` | (必須) | 応答変数の列名 |
| `factorColumns` | `string[]` | (必須) | 因子列。1 要素で一元配置、2 要素で二元配置 |
| `includeInteraction` | `boolean` | `true` | 二元配置で交互作用項を含める |
| `ssType` | `'I' \| 'III'` | `'III'` | 二元配置の平方和の分解タイプ |
| `confidenceLevel` | `number` | `95` | Tukey HSD の信頼水準。90、95、99 のいずれか |
| `postHoc` | `boolean` | `true` | 一元配置で Tukey HSD を計算する |

レスポンスには `mode`（`'one-way'` または `'two-way'`）、`anovaTable`（各効果の平方和・自由度・平均平方と効果量 η²・ω²、残差、合計）、`groupStatistics`（グループ別の n、平均、標準偏差、最小値、最大値）、`nObservations`、`nExcluded` が含まれます。一元配置で `postHoc` が有効な場合は `tukeyHSD`（ペアごとの平均差、SE、信頼区間）も含まれます。

```javascript
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, warnings: [] }
```

#### models.save(runId, name?) {#modelssaverunid-name}

モデルの実行結果をプロジェクトに保存します。保存後、[`models.list()`](#modelslist) や [`models.describe()`](#modelsdescribeid) で参照できます。

```javascript
const run = await window.midas.models.run({ ... });
const saved = await window.midas.models.save(run.data.runId, 'My Model');
// saved.data: { modelId: '...', name: 'My Model' }
```

診断データセットは GLM Diagnostics タブを開いた時点で自動作成されます。含まれる主な列は `fitted_values`、`deviance_residuals`、`pearson_residuals`、`standardized_residuals`、`leverage`、`cooks_distance` です。これらを [`reports.addGraph()`](#reportsaddgraphreportid-config) や Graph Builder で可視化して残差分析や診断プロットに使用できます。

#### models.describe(id) {#modelsdescribeid}

モデルの詳細を取得します。GLM、GLMM、Random Forest、ARIMA、Linear Regression、ANOVA に対応しています。レスポンス構造はモデルタイプにより異なります（`result.data.type` で判別）。モデルは [`models.run()`](#modelsrunconfig) + [`models.save()`](#modelssaverunid-name) で API から作成するか、GUI から作成できます。

**GLM**: 係数、適合度指標（AIC, BIC, deviance）、診断サマリー、メタデータを返します。

**GLMM**: 固定効果（GLM の係数と同形式）、ランダム効果（グループ変数、分散、ICC、BLUP）、適合度指標（対数尤度、反復回数、収束状態）、診断サマリーを返します。

**Random Forest**: タスクタイプ（classification/regression）、チューニングパラメータ、MDI 変数重要度（保存されている場合）、OOB Permutation Importance（計算済みの場合）を返します。

**ARIMA**: 次数（p, d, q）、係数（AR/MA/Intercept と CI）、適合度指標（AIC, BIC, 対数尤度, σ², 収束状態）、`residualDiagnostics`（残差の ACF と PACF）を返します。`models.run()` の残差診断と `fit.error` は保存時に残るため、再適合せずに取得できます。`acf` と `pacf` が空配列になるのは、この機能の追加前に保存されたモデルか、適合が縮退したモデル（`fit.error` あり）です。`fit.error` が設定されているときの係数や適合度指標の扱いは [`models.run()`](#modelsrunconfig) の ARIMA の説明を参照してください。

**Linear Regression**: 係数（GLM と同形式、`inference` は常に t 分布）、適合度指標（R², Adjusted R², RMSE, AIC, BIC）、診断サマリー、メタデータを返します。

**ANOVA**: 分散分析表（平方和、自由度、平均平方、効果量 η²・ω²）、グループ別統計量、Tukey HSD（計算済みの場合のみ）、メタデータを返します。レスポンス構造は [`models.run()`](#modelsrunconfig) の ANOVA の説明と同じです。

```javascript
const result = await window.midas.models.describe('model_001');
// GLM の例 - 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: { ... }
// }
```

GLMM の場合は `fixedEffects` 配下の係数が GLM の `coefficients` と同形式になり、`inference` は常に `{ distribution: 'normal', df: null }` です。Random Forest には `inference`、`coefficients`、`fit` フィールドはありません。

```javascript
// GLMM の例 - 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 }] }
// }
```

```javascript
// Random Forest の例 - 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` は MDI（Mean Decrease in Impurity）です。`permutationImportances` は OOB permutation importance（各 predictor をシャッフルした際の OOB 予測精度の平均低下量）で、未計算の場合は `undefined` になります。値は負になることがあります。これはシャッフルしても OOB 予測精度が低下しなかったことを意味します。両配列とも `metadata.predictors` と同じ順序です。

#### models.remove(id) {#modelsremoveid}

モデルをプロジェクトから削除します。対象モデルを参照しているタブを閉じたあと、関連する診断データセットや ANOVA テーブルなどの派生データセットをカスケード削除します。

```javascript
await window.midas.models.remove('model_001');
```

#### models.configure(tabId, config) {#modelsconfiguratabid-config}

GLM タブを設定します。family、link 関数、目的変数、説明変数を指定できます。カラム名は大文字小文字を区別せずに解決されます。

```javascript
await window.midas.models.configure('glm_001', {
  family: 'binomial',
  link: 'logit',
  yColumn: 'outcome',
  xColumns: ['age', 'treatment'],
});
```

### reports {#reports}

レポートのテキスト内容は 2 つのメソッドで変更できます。`addContent()` は既存の内容の末尾に Markdown を追記し、`setContent()` は内容全体を置換します。どちらもレポートの `elements` には影響しません。

#### reports.create(name, description?) {#reportscreatename-description}

レポートを新規作成します。

```javascript
const result = await window.midas.reports.create('Analysis Report');
// result.data: { reportId: 'report_...', name: 'Analysis Report' }
```

#### reports.list() {#reportslist}

レポートの一覧を取得します。

```javascript
const result = await window.midas.reports.list();
// result.data: [{ id, name, elementCount }, ...]
```

#### reports.getContent(reportId) {#reportsgetcontentreportid}

レポートの内容を取得します。

```javascript
const result = await window.midas.reports.getContent('report_001');
// result.data: { content: '## Analysis Results\n...', elements: [{ id, type, title, renderStatus, renderStatusMessage? }, ...] }
```

`renderStatus` はすべての要素に付与されます。`'ok'` は描画を妨げる問題が検出されなかったこと、`'empty'` はデータ行はあるが描画可能なポイントがないこと、`'error'` はデータセット未発見・データ未ロード・aesthetic 設定不備等で描画できないことを示します。描画ポイント単位の事前チェックの対象は Custom Graph 要素（`graphConfig.type === 'custom'`）だけです。非 custom のグラフ要素はデータセットの存在とロード状態のみを検証し、問題がなければ `'ok'` を返します。この `'ok'` は描画内容を検証した結果ではありません。

#### reports.setContent(reportId, content) {#reportssetcontentreportid-content}

レポートのテキスト内容を全体置換します。`addContent()` や `addModelSummary()` で追加済みのテキストも置き換えられます。content に `{{type:id}}` 形式の要素参照が含まれていて、その要素 ID がレポートの `elements` に登録されていない場合、`result.warnings` で通知されます。

content から `{{type:id}}` 参照を削除しても、対応する要素は自動削除**されません**。要素はレポートの `elements` に残り続け、再び `{{type:id}}` を content に記述すれば表示されます。要素を完全に削除するには `reports.removeElement()` を使用してください。

```javascript
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']  // 未登録の参照がある場合
```

#### reports.addContent(reportId, markdown) {#reportsaddcontentreportid-markdown}

レポートの末尾に Markdown テキストを追記します。

```javascript
await window.midas.reports.addContent('report_001', '## Analysis Results\n\nThe model shows...');
```

#### reports.addDataTable(reportId, datasetId, options?) {#reportsadddatatablereportid-datasetid-options}

データセットをデータテーブル要素としてレポートに追加します。`datasetId` にはデータセット ID またはデータセット名（大文字小文字を区別しない）を指定できます。要素は `type: 'data_table'` として `report.elements` に登録され、本文に `{{data_table:elementId}}` の参照が追記されます。

```javascript
const result = await window.midas.reports.addDataTable('report_001', 'Species Averages', {
  columns: ['species', 'avg_sl'],
  maxRows: 10
});
// result.data: { elementId, reportId, renderStatus, renderStatusMessage? }
```

オプション:

- `columns` (`string[]`) — 表示する列。カラム名またはカラム ID で指定します。省略時は全列を表示します
- `maxRows` (`number`) — 表示する最大行数。1 以上の整数で、上限は 1000 です。省略時は全行（最大 1000 行）を表示します

データが実体化されていないデータセットには `NO_DATA` エラーを返します。`renderStatus` はデータセットに行がない場合に `'empty'`、それ以外は `'ok'` になります。

#### reports.addModelSummary(reportId, modelId) {#reportsaddmodelsummaryreportid-modelid}

モデルのサマリーをレポートに追加します。GLM、GLMM、Linear Regression、Random Forest、ARIMA、ANOVA に対応しています。

全モデルタイプで要素参照方式を使用します（[`addGraph`](#reportsaddgraphreportid-config) と同じ方式）。GLM / GLMM / Linear Regression の係数テーブルは `type: 'data_table'` の要素として `report.elements` に追加され、レポート本文には `{{data_table:elementId}}` の参照が挿入されます。Random Forest の Feature Importance も `featureImportances` がある場合に `type: 'data_table'` の要素（Feature, MDI の 2 列、Permutation Importance がある場合は Permutation 列を加えた 3 列、Permutation がある場合は Permutation 降順、なければ MDI 降順でソート）として追加されます。テーブルの実体は派生データセットとして `project.datasets` に登録されるため、Data タブの一覧にも表示されます。モデルを削除すると関連する係数の派生データセットも自動的に削除され、削除された dataset / model を参照するレポート要素（`data_table` / `model_stats` / `graph_builder` / `crosstab` / `statistics_summary` / `anova`）がレポートから取り除かれます。引数 `modelId` が実在する保存済みモデルを指していないと `APIResult.success === false` でエラーが返ります。

GLM / GLMM / Linear Regression の Model Fit / Random Effects / OLS Fit は、`type: 'model_stats'` の要素として `report.elements` に登録され、本文には `{{model_stats:elementId}}` の参照が挿入されます。要素はモデル ID のみ保持し、描画時に `project.models[modelId]` から値を動的に解決します。したがって、同じモデル ID で再適合して `project.models` が上書きされた場合、既存のレポートも自動で新しい値を表示します。レポート作成後にモデルを削除すると、`model_stats` 要素は "Model not found" プレースホルダを表示します。

GLM と GLMM の係数テーブルは共通の列構成です: Variable, Estimate, Std. Error, Lower N%, Upper N%。logit リンクと log リンクでは exp 変換列（OR / IRR / exp(Est.)、exp(Lower N%)、exp(Upper N%)）が family/link の組み合わせに応じて追加されます。N はモデル保存時の信頼水準（`confidenceLevel`、デフォルト 95）です。Linear Regression の係数テーブルはこれに加えて Std. Coef. と VIF を持ちます。信頼区間はすべて Wald 型（`estimate ± criticalValue × SE`）です。臨界値の参照分布は GLM では family と link から決まり（[`models.run()`](#modelsrunconfig) の節の対応表を参照）、GLMM の固定効果は常に標準正規分布、Linear Regression は常に t 分布を用います。

モデル別の描画内容:

- **GLM**: `model_stats` 要素の Model Fit セクションに AIC, BIC, Deviance, Null Deviance, Converged, iterations を表示します
- **GLMM**: BLUP データがある場合は BLUP テーブル（Group, Random Intercept, Std. Error, Rank の 4 列、estimate 降順でソート済み）を `data_table` 要素として追加登録し、本文に `### Random Effects (BLUP)` 見出しと `{{data_table:blupElementId}}` 参照を挿入します（`result.data.blupElementId` で ID を取得できます）。`model_stats` 要素の Random Effects セクションに Group Variable, Number of Groups, Random Intercept Variance, Residual Variance (LMM のみ), ICC を、Model Fit セクションに Log-Likelihood, AIC, BIC, Converged, iterations を表示します。LMM（Gaussian + identity link）では REML Log-Likelihood, ICC と表記し、Binomial + logit/probit では Log-Likelihood (Laplace), ICC (latent scale) と表記します。それ以外の family+link（Poisson, Gamma 等）では、理論的根拠のある潜在尺度残差分散が存在しないため ICC は表示されません（null）
- **Linear Regression**: 5 つの要素を登録します — 係数テーブル、ANOVA Type I、ANOVA Type III、Prediction Intervals (per-observation 予測区間/信頼区間)、`model_stats` 要素。`model_stats` 要素の OLS Fit セクションに R², Adjusted R², RMSE, N observations を、Information Criteria セクションに AIC, BIC を表示します。Converged / iterations は OLS では自明なので表示しません
- **Random Forest**: featureImportances がある場合は Feature Importance の `data_table` 要素（Feature, MDI の 2 列、Permutation Importance がある場合は Permutation 列を加えた 3 列、Permutation がある場合は Permutation 降順、なければ MDI 降順でソート）を登録します。Model Configuration（Task Type, Number of Trees, Max Depth, Min Samples Split, Min Samples Leaf, Max Features）と OOB Accuracy（分類）/ OOB R²（回帰）は `model_stats` 要素として登録します
- **ANOVA**: ANOVA Table と Group Statistics を `data_table` 要素として登録します。一元配置で Tukey HSD が計算済みの場合は Tukey HSD テーブルも追加します。`model_stats` 要素は登録しません

```javascript
const result = await window.midas.reports.addModelSummary('report_001', 'model_001');
// result.data: { reportId, addedText, elementId?, statsElementId?, anovaTypeIElementId?, anovaTypeIIIElementId?, groupStatisticsElementId?, tukeyHSDElementId?, predictionIntervalsElementId?, blupElementId? }
// - elementId: 係数 / Feature Importance / ANOVA Table の data_table 要素の id (RF: featureImportances が非空のときのみ)
// - statsElementId: Model Fit / Random Effects / OLS Fit / Model Configuration を描画する model_stats 要素の id (ANOVA では返されない)
// - blupElementId: GLMM のとき、BLUP テーブルの data_table 要素の id (BLUP データがある場合のみ)
// - anovaTypeIElementId / anovaTypeIIIElementId / predictionIntervalsElementId: Linear Regression のみ
// - groupStatisticsElementId: ANOVA の Group Statistics テーブルの id
// - tukeyHSDElementId: ANOVA かつ Tukey HSD が計算済みのときの id
```

同一モデルに対して複数回呼び出した場合、係数の派生データセットは名前と操作定義が完全一致する既存の派生データセットがあれば再利用されます。同一モデルの fit 条件を変えて再実行した後に呼ぶと、派生データセットが同名で操作定義が一致しなくなるため `Dataset with name "X" already exists` エラーで `APIResult.success === false` が返ります。設定違いのサマリーを並存させたい場合は、旧モデルを削除するか、新モデルを別名で保存してから呼んでください。レポート要素とテキストは毎回新規追加されます。

#### reports.addGraph(reportId, config) {#reportsaddgraphreportid-config}

レポートにグラフをレポート要素として追加します。タブを開かずに Custom Graph を宣言的に作成します。`datasetId` にはデータセット ID またはデータセット名を指定できます（大文字小文字を区別しません）。カラム名も大文字小文字を区別せずに解決されます。`AddGraphInput` や `LayerDefInput` に存在しないプロパティが渡された場合は `result.warnings` で通知されます。軸スケール（`scales`）、レイヤーごとのカラースケール（`layers[].scales`）、ファセット（`facets`）を指定できます。`facets` のプロパティ詳細は [configureGraph](#tabsconfiguregraphtabid-config) を参照してください。

```javascript
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? }
```

`renderStatus` はグラフのレンダリング結果です。`'ok'` はデータポイントが存在し、指定した aes がすべて適用されて描画されます。`'partial'` はデータポイントが存在し描画されますが、geom が対応していない aes プロパティが無視されたことを示します（意図した描画と異なる可能性があります）。`'empty'` はデータ行はあるが描画可能なポイントがないことを示します（型不一致、フィルタ除外等）。`'error'` は aesthetic 設定不備等で描画不能です。`renderStatusMessage` には `'ok'` 以外の場合に原因の説明が入ります。

グラフはレポート要素として保存され、レポートの content に `{{graph_builder:elementId}}` の参照が追記されます。

利用可能な geom、stat、position の一覧は [Custom Graph リファレンス](custom-graph-reference)を参照してください。各 Statistic の [`params`](custom-graph-reference#stat-params) は指定可能な値とデフォルト値とともに同ページに掲載しています。ファセット、座標系などグラフレベルのオプションは [Custom Graph](custom-graph) を参照してください。

`coordinates` には `'flipped'` または `'cartesian'` を指定できます。`'flipped'` を指定すると X 軸と Y 軸が入れ替わります（例: 縦棒グラフが横棒グラフになります）。デフォルトは `'cartesian'` です。

`aspectRatio` には `'16:9'`、`'4:3'`、`'1:1'`、`'3:4'`、`'9:16'`、`'custom'` を指定できます。デフォルトは `'16:9'` です。`'custom'` 以外のプリセット値を指定した場合、アスペクト比が表示時の高さを決定するため `height` は描画に使用されません。`'custom'` の場合は `height` で高さを指定します。`height` のデフォルトは 400、最小値は 200、最大値は 5000 です。

#### reports.updateElement(reportId, elementId, config) {#reportsupdateelementreportid-elementid-config}

既存の `graph_builder` 要素のグラフ設定を全置換します。要素 ID と本文中の位置はそのまま維持されます。`config` は `addGraph` と同じ構造です（`datasetId` にはデータセット ID または名前を指定できます）。

```javascript
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? }
```

`graph_builder` 以外の要素タイプ（`data_table`、`model_stats` 等）を指定するとエラーになります。

#### reports.removeElement(reportId, elementId) {#reportsremoveelementreportid-elementid}

レポートから要素を削除し、本文中の `{{type:elementId}}` 参照も除去します。全要素タイプ（`graph_builder`、`data_table`、`model_stats`、`crosstab`、`statistics_summary`、`anova`）に対応しています。関連リソース（derived dataset、モデル等）は削除されません。

```javascript
await window.midas.reports.removeElement('report_001', 'graph-xxx');
// result.data: { elementId, reportId }
```

#### reports.remove(reportId) {#reportsremovereportid}

レポートをプロジェクトから削除します。対象レポートを参照しているタブを閉じてからレポートを削除します。

```javascript
await window.midas.reports.remove('report_001');
```

### layout {#layout}

#### layout.split(config) {#layoutsplitconfig}

ペインを分割して新しい領域を作成します。

```javascript
const result = await window.midas.layout.split({
  tabId: 'tab_001',
  direction: 'horizontal'  // 'horizontal' または 'vertical'
});
// result.data: { newPaneId: 'pane_...', originalPaneId: 'pane_...' }
```

返された `newPaneId` を [`tabs.moveToPane()`](#tabsmovetopanetabid-topaneid) に渡すことで、タブを新しいペインに配置できます。

## エラーコード {#error-codes}

| コード | 説明 |
|--------|------|
| `ERROR` | 汎用エラー |
| `NO_PROJECT` | プロジェクトが読み込まれていない |
| `NOT_FOUND` | 指定したリソースが見つからない |
| `DATASET_NOT_FOUND` | テーブル名に一致するデータセットが見つからない |
| `COLUMN_NOT_FOUND` | カラムが見つからない |
| `INVALID_TAB_TYPE` | タブタイプが無効 |
| `INVALID_TAB_TYPE_FOR_OPERATION` | タブタイプがこの操作に対応していない |
| `INVALID_GRAPH_TYPE` | カスタムグラフ以外でレイヤー操作を試みた |
| `INVALID_INPUT` | 入力パラメータが無効 |
| `INDEX_OUT_OF_RANGE` | レイヤーインデックスが範囲外 |
| `DATASET_ALREADY_EXISTS` | 同名（大文字小文字を区別しない）のデータセットが既に存在する（overwrite: false 時） |
| `SELF_REFERENCE` | 上書き対象が操作自身の依存先（祖先）である |
| `NAME_CONFLICT` | 派生系メソッドの出力名が既存プライマリデータセットと衝突する |
| `OPERATION_TYPE_MISMATCH` | 上書き対象の派生データセットが異なるメソッドで作成されている。各派生メソッド（`derive`、`addColumns`、`setColumnSchema`、`addOrthogonalPolynomials`）はそれぞれ固有の operation type を書き込む。異なるタイプ間での上書きは拒否される（例: `addColumns()` で作成したデータセットを `derive()` で上書き、`derive()` で作成したデータセットを `addColumns()` で上書き） |
| `AMBIGUOUS_TABLE_NAME` | テーブル名に case-insensitive で複数のデータセットがマッチした |
| `EXECUTION_ERROR` | SQL 実行エラー |
| `UNSUPPORTED_MODEL_TYPE` | 未対応のモデルタイプ |
| `MODEL_EXECUTION_ERROR` | モデル実行エラー |
| `NUMERICAL_ERROR` | 数値計算エラー（行列の特異性など） |
| `INSUFFICIENT_DATA` | 有効な観測数が不足 |
| `NO_DATA` | データセットにデータがロードされていない |
| `NO_CONTAINER` | アクティブなコンテナがない |
| `NO_TARGET` | SQL にテーブル参照がない |
| `NO_CONFIG` | Graph Builder 設定がない |
| `SPLIT_FAILED` | ペイン分割に失敗 |
| `SANDBOX_MODE` | サンドボックスモードで保存不可 |
| `ENUM_ALREADY_EXISTS` | enum 定義が既に存在する |
| `ENUM_NOT_FOUND` | enum 定義が見つからない |
| `ENUM_IN_USE` | enum 定義が列から参照されている |
| `ENUM_VALUE_MISMATCH` | enum 定義外の値がデータに存在する |
| `FETCH_ERROR` | URL フェッチ失敗（ネットワークエラー、タイムアウト、HTTP エラー） |
| `USER_CANCELLED` | ユーザーが操作をキャンセルした（未保存変更の確認ダイアログで拒否など） |

## 参考 {#reference}

- ライブリファレンス: プロジェクト画面で `window.midas.help()` を実行
