tries converts a list of hostnames, IPs, paths, or tokens into a
trie and outputs Graphviz DOT.
You can then use Graphviz to render the text output into PDF, PNG, SVG, etc.
A trie is a tree-like structure used for storing strings in a way that exposes shared prefixes.
It is useful for:
- Visualising naming conventions
- Discovering embedded structure in text
- Analysing patterns in hostnames, IPs, or path structures
- Documenting legacy naming schemes
- Seeing structure that is usually hidden
- Making interesting diagrams from plain text lists
There are no Python dependencies to produce DOT output.
Graphviz is needed if you want to render the DOT into PDF or PNG.
- Reads from files or STDIN
- Character-level trie mode
- Token mode via
-D "CHAR" - Themes (color + text presets)
- Per-node color overrides
- Per-node text color overrides
- Case-insensitive tries (
--ignore-case) - Windows
DOMAIN\hostprefix stripping (--include-domain) - Optional FQDN stripping (
--include-fqdn) - Hide labels (
--no-labels) - Reverse token order (token mode only
--rtl) - Multiple sample datasets:
--sample-hosts--sample-ips--sample-paths--sample-urls--sample-emails--sample-nato
- Automatically combines sample data + file input
- Fully standalone, no imports beyond Python stdlib
- Per-node color control
- normal terminals
- marked terminals
- head node
- Per-node text colors
text_normaltext_marktext_head
- Cross-platform safe font choices
- Case-insensitive filtering and marking
- Included theme-gallery generator script
- Simple
--versionflag and--debugoutput
Just copy tries.py and optionally themes.py somewhere into your $PATH.
Requirements:
- Python 3.6+
- Graphviz (only for rendering)
macOS install:
brew install graphviz
Render a trie from a file:
./tries.py servers.txt | dot -Tpdf -o trie.pdf
Render PNG:
./tries.py servers.txt | dot -Tpng -o trie.png
Read from STDIN:
cat servers.txt | ./tries.py | dot -Tpng -o trie.png
Print the version and exit:
./tries.py --version
Enable debug logging:
./tries.py --debug file.txt
This image was generated using:
./tries.py --sample-hosts -H -m oob \
| dot -Tpng -o example_hosts.png
This example demonstrates:
- Default theme (
warm-sand) - Head-nodes (
-H), which formats the head node as a circle - Character-mode
- Marking rules (
-m), which marks nodes with the text as a different color - Built-in sample hosts dataset
This image was generated using:
./tries.py --sample-paths -D "/" -m usr \
| dot -Tpng -o example_paths.png
This example demonstrates:
- Default theme (
warm-sand) - Token-mode (
-D), for delimiter-based tries (Paths) - Marking rules (
-m), which marks nodes with the text as a different color - Built-in sample paths dataset
This image was generated using:
./tries.py --sample-ips -D "." -m 192 \
| dot -Tpng -o example_ips.png
This example demonstrates:
- Default theme (
warm-sand) - Token-mode (
-D), for delimiter-based tries (IPs) - Marking rules (
-m), which marks nodes with the text as a different color - Built-in sample IP dataset
This image was generated using:
./tries.py --sample-urls -D "/" -m login \
| dot -Tpng -o example_urls.png
This example demonstrates:
- Default theme (
warm-sand) - Token-mode (
-D), for delimiter-based tries (URLs) - Marking rules (
-m), which marks nodes with the text as a different color - Built-in sample url dataset
Themes define all colors for:
- Normal terminal nodes
- Marked terminal nodes
- Head node (
-H) - Edges
- Point nodes
- Node text colors
List available themes:
./tries.py --list-themes
To use a theme, for example midnight:
./tries.py --sample-hosts -T midnight | dot -Tpdf -o midnight.pdf
Generate a gallery:
./generate-theme-gallery.sh
You can save your current color and text overrides as a reusable theme:
./tries.py \
-cn lightskyblue1 \
-cm mediumspringgreen \
-ch royalblue3 \
-ce cyan3 \
-cp gray50 \
-tn black \
-tm black \
-th white \
--save-theme electric-dusk
This creates (or updates) themes_custom.py with a theme called
electric-dusk.
You can then use it later:
./tries.py --sample-hosts -T electric-dusk | dot -Tpng -o dusk.png
All colors used by tries.py - including theme colors and CLI overrides - use the X11 color palette supported by Graphviz.
This means you can use any standard color name such as cornsilk2, palegreen3, royalblue3, gray60, or lightskyblue1 without needing hex codes.
The full list of valid color names is available here:
https://graphviz.org/doc/info/colors.html
Override theme colors with:
-cn,--color-normal-cm,--color-mark-ch,--color-head-ce,--color-edge-cp,--color-point
Example:
./tries.py --sample -H -T warm-sand \
-cn mistyrose -ch skyblue \
| dot -Tpdf -o custom.pdf
Override per-node label colors:
-tn,--text-normal(normal terminal)-tm,--text-mark(marked terminal)-th,--text-head(head node)
Example:
./tries.py --sample -H -T nightfall -fh black \
| dot -Tpdf -o out.pdf
Use a safe cross-platform font family:
-F courier-F courier-new-F dejavu-F liberation-F nimbus-F helvetica-F menlo-F consolas
Example:
./tries.py --sample-hosts -F menlo | dot -Tpdf -o out.pdf
Filter text via regex:
./tries.py -f 'fw' servers.txt
Filtering is case-sensitive.
Sometimes it’s easier to filter out patterns instead of matching them.
Use --invert-filter to keep every line not matching -f:
./tries.py -f 'oob' --invert-filter
This keeps everything except lines containing “oob”.
Useful for:
- excluding environments
- excluding "oob" or "mgmt" hosts
- excluding high-noise patterns
- cleanup passes
Use --mark (-m) with regex patterns:
./tries.py -m 'prod$' servers.txt
Multiple patterns:
./tries.py -m 'oob$' 'fw$' 'lm[0-9][0-9]$' servers.txt
Regex is case-sensitive.
To display the first character as a filled circle:
./tries.py -H servers.txt
To treat upper and lower case as equivalent in the trie:
./tries.py --ignore-case servers.txt
This normalises internal trie IDs but keeps labels unchanged.
When --ignore-case is enabled:
- Internal trie nodes IDs are lowercased
- Mixed-case variants (e.g.
acmeweb01andACMEWEB02) share the same root path - Labels retain their original case
- Prevents mixed-case duplication caused by case-only differences
When --ignore-case is not set, case is preserved in node IDs and the trie
structure is strictly case-sensitive.
Strip:
ACME\server01
ACME\server02
Normally becomes:
server01
server02
To keep the domain:
./tries.py --include-domain
Input:
server01.domain.local
Default becomes:
server01
Keep the full FQDN:
./tries.py --include-fqdn
Remove labels from terminal and head nodes:
./tries.py --no-labels
Some structured strings are naturally hierarchical from the right rather than the left
--rtlonly applies in token mode (-Dis used)- Useful for emails or domain names
Using token mode (-D), the highest-level component appears last, so
a normal left-to-right trie gives an inverted structure. The --rtl
flag fixes this by reversing the token order after splitting,
producing a more logical root
./tries.py --sample-emails -D '@' --rtl
The sample flags are useful for:
- Testing themes
- Rendering example outputs
- Verifying colors and texts
- Ensuring Graphviz output works
./tries.py --sample-hosts
./tries.py --sample-ips
./tries.py --sample-paths
./tries.py --sample-urls
./tries.py --sample-nato
DOT output always goes to STDOUT unless -o is used.
Example DOT output:
graph tries {
graph [fontname="Courier"];
node [fontname="Courier"];
rankdir="LR";
"a" [shape="point"];
"ac" [shape="Mrecord", label="ac"];
{ rank = same; "a" }
"a" -- "ac";
}
Render (using Graphviz):
dot -Tpdf -o trie.pdf
./tries.py servers.txt -H -T safe \
| dot -Tpdf -o networks.pdf
GPLv3 (c) David Marsh 2019–2025




