CLI Tutorial

This tutorial walks through common analytics workflows using the Xplain CLI. Each example uses the xoedevtest dataset (root object: Patients) and can be run from any terminal with a configured session.

Prerequisites

  1. Install the xplain package and its CLI dependencies:

    pip install xplain
    
  2. Create a profile in ~/.xplainpyrc with a "startup" key so the CLI knows which dataset to load:

    {
      "default": "demo",
      "profiles": {
        "demo": {
          "url": "https://xoedevtest.xplain-data.com",
          "user": "your-user",
          "password": "your-password",
          "startup": "TestSet1"
        }
      }
    }
    

    The "startup" key tells the CLI which dataset to load automatically when connecting. Without it, commands that inspect or query data will fail.

  3. (Optional) Verify the connection:

    xplain connect
    

    If you have a default profile with "startup" configured, this step is optional — the CLI automatically connects and loads the dataset when you run any command.

Tutorial 1: Explore the Object Tree

Start by understanding the data hierarchy.

If your profile does not define a "startup" key, or if you want to switch datasets, load a startup configuration explicitly:

# Load a saved startup configuration from the server
xplain startup TestSet1.xstartup

# The extension is optional for .xstartup files
xplain startup TestSet1

# Or load a local XView JSON file
xplain startup ./views/my_view.xview

To initialize the current server session before loading data:

xplain init-xplain-session --output json

Show the tree:

xplain explore show-tree --output table

Get root object info:

xplain explore get-object-info --object-name Patients --output json

This returns the object metadata including all its dimensions. To see dimension details:

xplain explore get-dimension-info \
    --object-name Patients --dimension-name Gender --output json

Drill into attributes:

xplain explore get-attribute-info \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output json

Browse the hierarchy at different levels:

# Full tree (root)
xplain explore get-tree-details --output json

# Object level
xplain explore get-tree-details --object-name Hospitalizations --output json

# Dimension level
xplain explore get-tree-details \
    --object-name Patients --dimension-name DoB --output json

# Attribute level
xplain explore get-tree-details \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output json

Get the full structure in one call:

xplain explore get-full-object-structure --output json | python -m json.tool

Tutorial 2: Run Your First Query

The most common workflow is executing a statistical request.

COUNT Patients by Gender:

xplain query execute-request --output json --request '{
  "requestName": "tut_gender_count",
  "aggregations": [
    {"aggregationType": "COUNT", "object": "Patients", "dimension": "Gender"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Patients",
        "dimension": "Gender",
        "attribute": "Gender"
      }
    }]
  }],
  "selections": []
}'

View as a formatted table:

xplain query execute-request --output table --request '{...}'

Export as CSV (pipe to a file):

xplain query execute-request --output csv --request '{...}' > gender_counts.csv

Quick count with the convenience command:

xplain query count-attribute \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output json

Tutorial 3: Queries on Child Objects

The xoedevtest hierarchy is: Patients > Hospitalizations > Hosp.-Diagnoses, and Patients > Prescriptions.

COUNT Prescriptions by Year:

xplain query execute-request --output json --request '{
  "requestName": "tut_presc_year",
  "aggregations": [
    {"aggregationType": "COUNT", "object": "Prescriptions", "dimension": "Date"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Prescriptions",
        "dimension": "Date",
        "attribute": "Date",
        "groupByLevel": "Years"
      }
    }]
  }],
  "selections": []
}'

COUNT Hosp.-Diagnoses by ICD code:

xplain query execute-request --output table --request '{
  "requestName": "tut_icd_count",
  "aggregations": [
    {"aggregationType": "COUNT", "object": "Hosp.-Diagnoses", "dimension": "ICD"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Hosp.-Diagnoses",
        "dimension": "ICD",
        "attribute": "ICD"
      }
    }]
  }],
  "selections": []
}'

Tutorial 4: Selections (Filters)

Selections filter the data seen by all subsequent operations.

Select only Male patients:

xplain select select --output json --selection '{
  "attribute": {
    "object": "Patients",
    "dimension": "Gender",
    "attribute": "Gender"
  },
  "selectedStates": ["Male"]
}'

Verify the active selections:

xplain select get-selections --output json

Run a query (results now reflect Male patients only):

xplain query count-attribute \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output json

Clear the selection:

xplain select clear-all-selections --output json

Tutorial 5: Live Queries (open-request)

Unlike execute-request (which gives a static snapshot), open-request creates a live query that automatically recomputes whenever selections change.

Open a live request:

xplain query open-request --delete-if-exists --output json --request '{
  "requestName": "tut_live_gender",
  "aggregations": [
    {"aggregationType": "COUNT", "object": "Patients", "dimension": "Gender"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Patients",
        "dimension": "Gender",
        "attribute": "Gender"
      }
    }]
  }],
  "selections": []
}'

Now change selections — the live query updates automatically:

# Filter to a specific age range (the live query result changes)
xplain select select --output json --selection '{
  "attribute": {
    "object": "Patients",
    "dimension": "DoB",
    "attribute": "Altersgruppe (20er, 10er, 5er, 1er)"
  },
  "selectedStates": ["20-39"]
}'

Pause / unpause live queries:

xplain query pause-request --request-name tut_live_gender --output json
xplain query unpause-request --request-name tut_live_gender --output json

Clean up:

xplain query delete-request --request-name tut_live_gender --output json
xplain select clear-all-selections --output json

Tutorial 6: Two-Step Query Workflow

For complex queries you can separate creation from computation.

Step 1 — Create without computing:

xplain query create-request --delete-if-exists --output json --request '{
  "requestName": "tut_twostep",
  "aggregations": [
    {"aggregationType": "SUM", "object": "Prescriptions", "dimension": "Costs (est.)"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Prescriptions",
        "dimension": "Date",
        "attribute": "Date",
        "groupByLevel": "Years"
      }
    }]
  }],
  "selections": []
}'

Step 2 — Compute when ready:

xplain query compute-request --request-name tut_twostep --output json

Tutorial 7: Connecting and Session Management

Connect using the default profile (automatic):

Most commands work without an explicit connect — the CLI reads the default profile from ~/.xplainpyrc automatically (including its "startup" dataset). You can also connect explicitly:

# Use default profile (startup from profile config)
xplain connect

# Use a named profile
xplain connect --profile xoedevtest

# Use explicit credentials with a dataset
xplain connect --url https://xoe.example.com --user admin --password secret \
    --startup TestSet1

Attach to an existing server session by ID:

If you already have a running session (e.g. from the web UI or another client), you can attach to it using its 32-character session ID:

xplain connect --profile xoedevtest \
    --session-id CED14155E7A90C9376749487A6B52C24

# or with an explicit URL instead of a profile:
xplain connect --url https://xoedevtest.xplain-data.com \
    --session-id CED14155E7A90C9376749487A6B52C24

The dataset is already loaded on the server, so --startup is not needed.

Save a session for reuse:

xplain connect --profile xoedevtest --save-as mywork

Saved sessions are stored in ~/.xplainpy/sessions/ and restored automatically in subsequent CLI calls.

Use a specific profile per command:

Any command that accepts --session can take either a saved session name or a profile name from ~/.xplainpyrc:

xplain query count-attribute --session xoedevtest \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output json

Get current session state:

xplain config get-session --output json

Refresh session from server:

xplain config refresh --output json

Check resource usage:

xplain config resource-usage --output json

Load an analysis:

xplain config load-analysis --analysis-name MyAnalysis --output json

Performance tuning:

xplain config set-max-threads --max-threads 4 --output json
xplain config enable-caching --output json

Tutorial 8: Piping and Scripting

The --output json flag makes the CLI composable with standard Unix tools.

Pretty-print with jq:

xplain explore get-object-info --object-name Patients --output json \
    | jq '.dimensions[].dimensionName'

Extract CSV column:

xplain query count-attribute \
    --object-name Patients --dimension-name Gender \
    --attribute-name Gender --output csv \
    | cut -d',' -f1

Loop over objects:

for obj in Patients Hospitalizations Prescriptions; do
  echo "=== $obj ==="
  xplain explore get-object-info --object-name "$obj" --output json \
      | jq '.dimensions | length'
done

Shell script for a complete workflow:

#!/bin/bash
set -e

# Execute query
xplain query execute-request --output csv --request '{
  "requestName": "export_gender",
  "aggregations": [
    {"aggregationType": "COUNT", "object": "Patients", "dimension": "Gender"}
  ],
  "groupBys": [{
    "subGroupings": [{
      "attribute": {
        "object": "Patients", "dimension": "Gender", "attribute": "Gender"
      }
    }]
  }],
  "selections": []
}' > gender_report.csv

echo "Exported $(wc -l < gender_report.csv) rows to gender_report.csv"

# Clean up
xplain query delete-request --request-name export_gender --output json > /dev/null

CLI vs Python API

Every CLI command maps directly to a Python API method:

CLI

Python

xplain explore get-object-info --object-name Patients

session.explore.get_object_info(object_name="Patients")

xplain query execute-request --request '{...}'

session.query.execute_request(request={...})

xplain query count-attribute --object-name Patients ...

session.query.count_attribute(object_name="Patients", ...)

xplain select clear-all-selections

session.select.clear_all_selections()

xplain config refresh

session.config.refresh()

xplain startup TestSet1.xstartup

session.startup("TestSet1.xstartup")

xplain startup ./view.xview

session.startup_from_xview_config({...})

xplain init-xplain-session

session.http_post("/init_xplain_session", {})

The naming convention is consistent: CLI uses kebab-case, Python uses snake_case. CLI option names like --object-name map to keyword arguments object_name.