Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The .dioptra project file

A .dioptra file is a zip archive (deflate) of pretty-printed JSON. unzip -l lists it; unzip extracts it; git diff on the extracted tree shows exactly what changed. Keys are written in a stable order; numbers use shortest round-trip representation; empty cells are null.

manifest.json            format version, Dioptra version, created/modified timestamps
project.json             title, p-value style, display order of objects, layouts
tables/<id>.json         one table: kind, datasets, subcolumns, columns (columnar arrays),
                         row titles, column sources and formulas, excluded cells, text cells,
                         edit log
analyses/<id>.json       analysis spec (table id, kind, options); no results
graphs/<id>.json         graph spec (source id, family, mapping, style, axes, legend, options, annotations; docs/GRAPHS.md)
results/<id>.json        cached results sheets (optional; recomputed when absent or stale)
history.jsonl            command log: one JSON object per line, newest last
extensions/<name>        UTF-8 files kept for other components, e.g. Dioptra Lab's audit
                         trail; read back and saved unchanged by the core

manifest.json

{ "format": "dioptra/1.2", "app": "0.4.0", "created": "2026-10-11T09:00:00Z", "modified": "..." }

Readers must accept any dioptra/1.x; unknown keys are preserved on round trip where possible and ignored otherwise.

tables/<id>.json

{
  "id": "…", "title": "Dose response", "kind": "xy",
  "x": { "title": "Dose (nM)", "values": [1, 10, 100, null], "source": {"kind": "pasted", "at": "…"} },
  "row_titles": ["", "", "", ""],
  "datasets": [
    { "name": "Control", "format": {"kind": "values", "n": 3},
      "subcolumns": [
        { "values": [0.1, 0.5, 0.9, null], "excluded": [3], "text": {"2": "n/a"},
          "source": {"kind": "formula", "expr": "log10(A)"}, "decimals": 2,
          "edits": [{"row": 1, "at": "…", "from": 0.4, "to": 0.5}] }
      ] }
  ],
  "variables": null
}
  • values is a dense array the length of the table’s row count; null means empty.
  • excluded is a sorted list of row indices.
  • text holds non-numeric entries by row index (kept, shown, never used in numerics).
  • title on a subcolumn names it (a replicate or a nested subgroup, e.g. from Prism’s subcolumn titles); absent when unnamed. The X column’s title is the same field.
  • source is one of entered, pasted {at}, imported {file, sheet, column}, formula {expr}, derived {table, op}.
  • edits is the sparse per-cell edit log that, with source, gives each cell’s provenance.
  • For variables tables, each dataset has a single subcolumn and a type.
  • Derived tables carry derived_from: {table, op} at the top level.

history.jsonl

Each line is { "at": "…", "command": { … }, "label": "Paste 3×120 into Table 1" }. The engine replays nothing from it on open; it is an audit trail and the source of the undo timeline in the UI.

graphs/<id>.json

{
  "id": "…", "title": "Graph of Paired t test of Table 1",
  "spec": {
    "source": "…", "family": "column",
    "mapping": { "datasets": [0, 1], "error_bars": "sem", "points": true },
    "style": { "theme": "instrument", "size_mm": { "width": 85, "height": 70 },
               "datasets": [{ "dataset": 1, "pattern": "hatch" }] },
    "axes": { … }, "legend": { "position": "auto" },
    "options": { "jitter": 0, …,
                 "connecting": { "connect": "individuals", "style": "solid", "colour_by": "single",
                                 "opacity": 0.55, "missing": "gap", "direction": "within_groups",
                                 "summary_style": "solid" } },
    "annotations": [{ "kind": "significance_bracket", "from": 0, "to": 1, "text": "p = .002" }]
  }
}

Every field of the spec is listed in docs/GRAPHS.md. Fields at their defaults may be left out; connecting, orientation, error_direction, bar_fill and summary_line are written only when they differ from the default, so a graph without connecting lines is written exactly as format 1.0 wrote it.

Versions and migrations

FormatDioptraChange
dioptra/10.1, 0.2First format
dioptra/1.10.3Graph specs gain options.connecting, orientation, error_direction, cap_pt, bar_width, group_width, bar_fill, summary_line and style.datasets[].pattern. The before_after family is retired.
dioptra/1.20.4Layouts gain style (page width, font size, line width, panel letters). Files may carry extensions/<name>. Readers of 1.1 open 1.2 files and ignore the additions.

Migration 1.0 → 1.1 runs when a file is opened: a graph whose family is before_after becomes the strip spec that draws the same picture (jitter: 0, error_bars: none, summary_line: false, connecting.connect both when mean_line was on and individuals otherwise, opacity 0.4). Nothing else changes; saving writes the current format. A 0.2 reader opens a 1.1 file (the minor number is additive) and ignores the new fields, so it draws such a graph without its connecting lines.

Compatibility promise

The format version bumps the minor number for additive changes and the major number for anything a 1.x reader could misread. Readers of version N open any file ≤ N.