Write i2 Analyst's Notebook Exchange (.anx) files from Python, JSON, or YAML
Project description
anxwritter
For law enforcement, OSINT practitioners, and intelligence analysts who need to generate i2 Analyst's Notebook charts programmatically from case data, scrapers, or ETL pipelines, with reusable organization-level defaults instead of dragging entities by hand.
Write i2 Analyst's Notebook Exchange (.anx) files from Python, JSON, or YAML.
i2 Analyst's Notebook is an excellent link-analysis tool, and I've always appreciated how intuitive and powerful it is. But as someone who develops applications that produce data for it, I wanted a simpler workflow than exporting denormalized data into .xlsx or .csv files and maintaining separate .ximp import specifications. So I created anxwritter to generate .anx charts directly, making chart creation faster, cleaner, and easier for both developers and analysts.
Independent project — not affiliated with IBM, i2 Group, N.Harris Computer Corporation, or any other vendor. "i2", "i2 Analyst's Notebook", and "ANB" are trademarks of their respective owners (nominative use). See NOTICE.md for the full interoperability, trademark, and attribution statement.
Status: active development. See CHANGELOG.md for breaking changes between releases. API stabilization targeted for 2.0.
Install
# As a library — import in your own code
pip install anxwritter
# As a command-line tool only (isolated venv, no env conflicts)
pipx install anxwritter
With uv:
# Add to a uv-managed project
uv add anxwritter
# Install globally as a CLI tool
uv tool install anxwritter
# One-off run without installing
uvx anxwritter chart.yaml -o my_chart.anx
Requires Python 3.10+.
Want a standalone executable?
pip install pyinstaller(ornuitka) and point it atanxwritter/cli.py. anxwritter does not ship pre-built binaries.
Quick example
from anxwritter import ANXChart
chart = ANXChart()
chart.add_icon(id='Alice', type='Person', color='Blue')
chart.add_icon(id='Bob', type='Person', color='Red')
chart.add_link(
from_id='Alice', to_id='Bob',
type='Telephone Call', arrow='->',
date='2024-01-15',
)
chart.to_anx('output/my_chart')
This writes output/my_chart.anx. Open it in ANB.
YAML + CLI
# chart.yaml
entities:
icons:
- { id: Alice, type: Person, color: Blue }
- { id: Bob, type: Person, color: Red }
links:
- { from_id: Alice, to_id: Bob, type: Telephone Call, arrow: '->', date: '2024-01-15' }
anxwritter chart.yaml -o output/my_chart.anx
What's in the box
- Geographic positioning — map entity attributes to lat/lon for canvas layout and/or ANB Esri Maps
- Org-level config files — separate entity types, link types, attribute classes, and palettes from per-chart data; layered configs with append-and-dedup or wholesale-replace semantics
- Semantic types — full
lcx:LibraryCataloguesupport with custom type extension; per-instance overrides - Auto-layout — geometric (circle, grid, radial, random) plus topology-aware force-directed: Fruchterman-Reingold, ForceAtlas2, tidy tree (Reingold-Tilford). Manual
x/yalways wins; pinned entities act as anchors - Auto-coloring — distribute HSV hues across entities; matching link colors that follow the target entity
- Data-driven link styling — width and/or color from a numeric attribute via a configurable scale (linear, log, sqrt, power, quantile) and color ramp; or per-value lookup on a string attribute. Optional auto-generated legend.
- CLI —
anxwritter [--config org.yaml ...] data.{json,yaml} -o out.anx, with--show-configprovenance and--geo-datafor external geo lookups - Three input forms — Python objects, JSON, or YAML; all paths produce identical output
- Typed dataclass API —
Icon,Box,Circle,ThemeLine,EventFrame,TextBlock,Label,Link,Card - Validation — collects every error in one pass before writing the file
Customize everything ANB exposes
No fixed catalog — every configurable surface in ANB is yours to define:
- Entity types & link types — names, icons, colors, shading, semantic-type bindings
- Attribute classes — type, prefix/suffix, decimals, font, merge behavior, icons, visibility
- Palettes — your own "Insert from Palette" panels with grouped types and pre-filled attribute entries
- Legend — 8 item types (icon, link, line, font, text, attribute, timezone, icon-frame) with full styling
- Colors — 40 named, hex, COLORREF, or auto-distributed HSV with link colors that follow the entity
- Strengths, grades, source types, datetime formats, semantic types — all configurable
Define your defaults once in config.yaml, layer overrides on top, reuse across every chart.
Documentation
- Getting started — install, first chart, where to go next
- Analyst guide — every feature via practical examples
- Reference docs — field-by-field API reference
License
MIT — see LICENSE. Copyright (c) 2024-2026 gustavo-gkmi.
Developed with the help of AI coding assistants.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anxwritter-1.13.0.tar.gz.
File metadata
- Download URL: anxwritter-1.13.0.tar.gz
- Upload date:
- Size: 366.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a6ecb29d95b60f5c7ababe8448cf8f43e08adc80ecfefd3431d04a01410a37b
|
|
| MD5 |
f0d31966a750df4a6df3cd4335172b90
|
|
| BLAKE2b-256 |
68b29e8443a18c9a609c3094b27c728a338fb6b2fce701baff5ed3519bf38fca
|
Provenance
The following attestation bundles were made for anxwritter-1.13.0.tar.gz:
Publisher:
publish.yml on gustavo-gkmi/anxwritter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anxwritter-1.13.0.tar.gz -
Subject digest:
8a6ecb29d95b60f5c7ababe8448cf8f43e08adc80ecfefd3431d04a01410a37b - Sigstore transparency entry: 1598131541
- Sigstore integration time:
-
Permalink:
gustavo-gkmi/anxwritter@16075d6d1947912510ebc92d0e7c504da563c677 -
Branch / Tag:
refs/tags/v1.13.0 - Owner: https://github.com/gustavo-gkmi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@16075d6d1947912510ebc92d0e7c504da563c677 -
Trigger Event:
release
-
Statement type:
File details
Details for the file anxwritter-1.13.0-py3-none-any.whl.
File metadata
- Download URL: anxwritter-1.13.0-py3-none-any.whl
- Upload date:
- Size: 147.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13e955514d404ee5a1ae319c013e186b6929e30b2283888e62059b8659218d1c
|
|
| MD5 |
670bc6f38d38e6bfda6fc347acae3563
|
|
| BLAKE2b-256 |
4a2dfc057a85dc474045f218d68b5a2212cee1da880e03a35c1c8ef8ac6501fb
|
Provenance
The following attestation bundles were made for anxwritter-1.13.0-py3-none-any.whl:
Publisher:
publish.yml on gustavo-gkmi/anxwritter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anxwritter-1.13.0-py3-none-any.whl -
Subject digest:
13e955514d404ee5a1ae319c013e186b6929e30b2283888e62059b8659218d1c - Sigstore transparency entry: 1598131641
- Sigstore integration time:
-
Permalink:
gustavo-gkmi/anxwritter@16075d6d1947912510ebc92d0e7c504da563c677 -
Branch / Tag:
refs/tags/v1.13.0 - Owner: https://github.com/gustavo-gkmi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@16075d6d1947912510ebc92d0e7c504da563c677 -
Trigger Event:
release
-
Statement type: