Skip to content

Command Line Interface

EVAnalyzer can be driven entirely from the command line via the evanalyzer cli subcommand, enabling headless batch processing, integration into automated workflows, and remote execution on servers - no GUI/display required.

The same evanalyzer binary handles both modes:

Terminal window
# Linux
./evanalyzer # launch the GUI
./evanalyzer cli <command> [options...] # run a one-shot CLI command and exit
# Windows
evanalyzer.exe cli <command> [options...]
CommandPurpose
analyzeRun a project’s enabled pipelines over its images and write a new results database
project-infoPrint a project’s images, classes, and pipelines without running anything
validateCheck that every image referenced by a project can be found on disk
viewPrint a quick summary and a page of rows from a results database
columnsList the column ids available for grouping/chart axes in a results database
exportExport a results database to CSV, XLSX, or a chart image

Every command supports --help:

Terminal window
./evanalyzer cli analyze --help

Runs a project’s enabled pipelines over its images and writes a new results database.

Terminal window
./evanalyzer cli analyze --project settings.improj
ArgumentDescription
--project <path>Project file to analyze (required)
--images <dir>Scan this directory and use it as the project’s image root before running. If omitted, the project’s already-saved image list is used as-is
--threads <n>Number of images to process in parallel. If omitted, EVAnalyzer picks the highest thread count that fits within available RAM and CPU cores

The parallelism is automatically capped to whichever is lower — the number of CPU cores or the number of images that fit in available RAM — so a low-memory machine never launches more parallel workers than it can sustain.

The command prints a progress line per image as it completes, then a summary:

Project: settings.improj
Images: 48
Pipelines: 1 enabled
Output: ./evanalyzer/EV Detection
Running with 7 parallel thread(s)...
[48/48] /data/plate1/A1_01.tif
Done: 48 image(s) analyzed in 32.4s (0 failed)
Results database written under: ./evanalyzer/EV Detection

A project with no images (and no --images override) fails fast with an error instead of running.

Press Ctrl+C to request a graceful stop; in-flight images will finish before the process exits.

Prints a project’s image count, classes, and pipelines without running anything - useful for sanity-checking a project file before kicking off a long batch run.

Terminal window
./evanalyzer cli project-info --project settings.improj
ArgumentDescription
--project <path>Project file to inspect (required)
--jsonEmit machine-readable JSON instead of human-readable text
Project: settings.improj
Name: EV detection screen
Image root: /data/plate1
Images: 48
Reachable: yes
Classes (3):
- dapi@nucleus
- cy5@spot
- cy7@spot
Pipelines (1):
- EV Detection [enabled] - 8 step(s)

If the configured image root can’t be found on disk, Reachable reports why instead of just “no”.

Checks that every image referenced by a project can be found on disk. Useful as a pre-flight step before starting a long headless run.

Terminal window
./evanalyzer cli validate --project settings.improj
ArgumentDescription
--project <path>Project file to check (required)

The command exits with a non-zero status code if any images are missing, making it suitable for use in CI scripts:

Terminal window
./evanalyzer cli validate --project settings.improj && \
./evanalyzer cli analyze --project settings.improj

analyze writes results to a results.evadb file (DuckDB format) under the project’s job folder - the same file the GUI’s Results view opens. view, columns, and export all read from this file via --db.

Terminal window
duckdb results.evadb "SELECT object_class_name, COUNT(*) FROM objects GROUP BY object_class_name"

Prints a database summary (image/class counts, T/Z-stack ranges) followed by a paginated, human-readable table of per-object rows - a quick terminal preview without exporting anything.

Terminal window
./evanalyzer cli view --db results.evadb --limit 10
ArgumentDescription
--db <path>Results database produced by analyze (required)
--page <n>Zero-based page index (default 0)
--limit <n>Rows per page (default 25)
--channelsAlso show per-channel intensity columns
--jsonEmit machine-readable JSON instead of human-readable text
--image <name>Restrict to this image name (repeatable)
--class <name>Restrict to this object class (repeatable)

Lists every column id available in a results database - including per-channel intensity columns and per-partner-class colocalization counts - grouped the same way as the GUI’s Columns picker (General, Geometry, Shape, Coloc, Intensity).

Terminal window
./evanalyzer cli columns --db results.evadb
ArgumentDescription
--db <path>Results database to inspect (required)
--jsonEmit machine-readable JSON instead of the formatted table
ID LABEL GROUP
object_id Object ID General
image_name Image General
object_class_name Class General
count Count General
area_px Area [px] Geometry
area_nm2 Area [nm²] Geometry
circularity Circularity Shape
solidity Solidity Shape
eccentricity Eccentricity Shape
n_colocalized_class_ch2@spot Coloc with ch2@spot Coloc
mean_scaled_ch0 Avg Intensity (Ch 0) intensity
sum_scaled_ch0 Sum Intensity (Ch 0) intensity

Run this first when scripting export - column ids are the values to pass to --group-by-adjacent tooling and to duckdb queries against the same file.

Exports a results database to CSV, XLSX, or Parquet, with the same filtering and (for image grouping) aggregation logic as the GUI’s Results List view. Chart image export (histogram/scatter/boxplot PNGs) isn’t wired up in the CLI yet - use the GUI’s Charts tab for those.

Terminal window
./evanalyzer cli export csv --db results.evadb --out results.csv
./evanalyzer cli export xlsx --db results.evadb --out results.xlsx \
--group-by image --agg avg,median
ArgumentDescription
--db <path>Results database to export (required)
--out <path>Output file path (required)
filter argsSee Filter Arguments
group argsSee Group Arguments

Writes the database’s raw objects table straight to a Parquet file via DuckDB’s own COPY ... TO ... (FORMAT parquet) - every column, completely unfiltered. There’s no column selection, image/class filtering, or grouping to apply (that’s the GUI’s Parquet export behavior too), so it takes a plainer set of arguments than csv/xlsx:

Terminal window
./evanalyzer cli export parquet --db results.evadb --out objects.parquet
ArgumentDescription
--db <path>Results database to export (required)
--out <path>Output file path (required)

Shared by view and every export subcommand:

ArgumentDescription
--image <name>Restrict to this image name (repeatable)
--class <name>Restrict to this object class (repeatable)

Shared by export csv and export xlsx - mirrors the GUI’s Grouping and Aggregating Rows:

ArgumentDescription
--group-by <image|folder|regex>Aggregate rows instead of exporting one row per object. Only image has a matching query today - folder/regex are recognized but currently rejected
--agg <list>Comma-separated aggregate function(s) applied to every numeric column when grouping: min, max, avg (default), median, stdev, sum
--split-colocalizedAccepted but currently rejected - no row-level “is this object colocalized at all” split exists in the current backend
--group-by-classNo-op when grouping by image - image grouping always splits by class already

The CLI operates on an EVAnalyzer project file (.improj). Create and configure the project using the GUI, save it, and then use the saved file for headless runs.

The project file is a JSON document - it can be modified programmatically using any scripting language.

A common use case is running the same pipeline with multiple parameter sets. The project file can be modified by a script before each run.

Example: vary blur kernel size with Python

Section titled “Example: vary blur kernel size with Python”
import json
import subprocess
def set_blur_kernel(filename, kernel_size):
with open(filename) as f:
data = json.load(f)
for pipeline in data.get("pipelines", []):
for step in pipeline.get("steps", []):
if step.get("command", {}).get("type") == "blur":
step["command"]["kernelSize"] = kernel_size
with open(filename, "w") as f:
json.dump(data, f, indent=2)
def run_analysis(project_file):
subprocess.run(
["./evanalyzer", "cli", "analyze", "--project", project_file],
check=True,
)
for size in [3, 5, 7, 9]:
set_blur_kernel("settings.improj", size)
run_analysis("settings.improj")
print(f"Finished kernel_size={size}")

The project file is a JSON document following the EVAnalyzer schema. Key top-level fields:

{
"metadata": { "name": "My experiment", ... },
"classification": { "classes": [...] },
"plate": { ... },
"images": { "root": "/path/to/images", "list": { ... } },
"pipelines": [
{
"id": "...",
"name": "EV Detection",
"enabled": true,
"imageSource": { ... },
"steps": [
{
"enabled": true,
"command": { "type": "rollingBall", "radius": 4.0, "ballType": "paraboloid" }
},
...
]
}
]
}
ExtensionDescription
.improjEVAnalyzer project file
.imptProject template file
.evadbResults database (DuckDB format)