AMPY: An Electrical diagram parsing and electrical assembly graph extraction tool
AMPY Electrical Assembly Analyzer is a specialized tool designed to parse electrical one-line diagrams and extract structured knowledge graphs from them. It's specifically built for electrical engineers, power system analysts, and automation professionals who need to work with electrical substation diagrams and similar power system schematics.
- LLM-Powered Analysis: Analyze electrical diagram images using AI (OpenAI, Anthropic, Google Gemini)
- Web Application: Modern React-based frontend with FastAPI backend for interactive analysis
- Real-time Graph Visualization: Interactive node-edge graphs using React Flow
- Structured Data Extraction: Convert electrical diagrams into machine-readable knowledge graphs
- Component Analysis: Identify and catalog electrical components (transformers, breakers, buses, relays, etc.)
- Topology Analysis: Map electrical connections and relationships between components
- Engineering Calculations: Extract and validate short circuit analysis, breaker specifications, and other engineering data
- Flexible Querying: Query specific components, connections, or system characteristics
- Rich Visualization: Generate summaries and reports with detailed component breakdowns
- Neo4j Integration: Store and query electrical diagrams in Neo4j graph database (via Docker Compose)
- Power Sources: Grid sources, generators
- Transformers: Power transformers with ratings and specifications
- Switchgear: Breakers, switches, bus ties
- Protection: Relays, current transformers, potential transformers
- Loads: Feeders, capacitor banks, loads
- Control Systems: Batteries, meters, control circuits
- Python 3.9 or higher
- uv package manager
- Docker and Docker Compose (for Neo4j database)
-
Install uv (if not already installed):
curl -LsSf https://astral.sh/uv/install.sh | sh -
Clone and setup the project:
git clone <repository-url> cd EA-Analyzer
-
Set up environment variables (for LLM integration):
# Create .env file with your API keys cp .env.example .env # Edit .env file with your actual API keys
See ENV_SETUP.md for detailed environment configuration.
-
Verify installation:
make check
Analyze an electrical diagram image using LLM:
# Start all of the components
make run
# Analyze image and extract structured data
./ea-analyzer-cli.sh analyze substation.png
# Analyze and store in Neo4j
./ea-analyzer-cli.sh analyze substation.png --storeParse and summarize an existing diagram:
./ea-analyzer-cli.sh summary data/one-line-knowledge-graph.jsonStore diagram in Neo4j database:
./ea-analyzer-cli.sh store data/one-line-knowledge-graph.jsonQuery the database:
./ea-analyzer-cli.sh neo4j summary
./ea-analyzer-cli.sh neo4j protection-schemesGet up and running quickly with these essential commands:
# Check system status and prerequisites
./ea-analyzer-cli.sh check
# Analyze an electrical diagram image with LLM
./ea-analyzer-cli.sh analyze substation.png
# Analyze and store in Neo4j database
./ea-analyzer-cli.sh analyze substation.png --store
# View stored diagrams
./ea-analyzer-cli.sh neo4j list
# Export diagram to PNG
./ea-analyzer-cli.sh neo4j export 1
# Run complete demo
./ea-analyzer-cli.sh demoLaunch the complete web application with a single command:
# Build and run the web application (frontend + backend + Neo4j)
make run
# For development with hot reload (recommended for UI work)
make run-dev
# Access the application
# Frontend: http://localhost:3000
# Backend API: http://localhost:8000
# API Docs: http://localhost:8000/docs
# Neo4j: http://localhost:7474
# Stop the web application
make stop
# For development mode
make stop-devDevelopment Mode Features:
- Hot Reload: Changes to frontend files are reflected immediately
- File Mounting: Local files are mounted into the container
- Development Tools: Full source maps and debugging support
For detailed frontend development instructions, see FRONTEND_DEVELOPMENT.md.
The ea-parse command provides several subcommands for different operations:
ea-parse summary <input_file>Displays comprehensive information about the electrical diagram including:
- Metadata (title, source, extraction date)
- Component statistics (total nodes/edges)
- Component type breakdown
- Connection type analysis
- Engineering calculations status
ea-parse list-items <input_file> [--node-type TYPE] [--edge-type TYPE]Lists all components and connections in the diagram:
--node-type: Filter by component type (e.g., Transformer, Breaker, Busbar)--edge-type: Filter by connection type (e.g., CONNECTS_TO, PROTECTS, MEASURES)
ea-parse parse <input_file> [--output OUTPUT_FILE]Processes and optionally saves the diagram:
--output, -o: Save processed diagram to specified file
For programmatic access, use the Python API:
from ea_analyzer.parser import ElectricalDiagramParser
from pathlib import Path
# Load a diagram
parser = ElectricalDiagramParser()
diagram = parser.load_from_file(Path("data/one-line-knowledge-graph.json"))
# Get summary statistics
summary = parser.get_summary()
print(f"Total components: {summary['total_nodes']}")
print(f"Total connections: {summary['total_edges']}")
# Query specific components
transformers = diagram.get_nodes_by_type("Transformer")
for tx in transformers:
print(f"Transformer {tx.id}: {tx.name}")
print(f" Ratings: {tx.extra_attrs.get('mva_ratings', 'N/A')} MVA")
print(f" HV: {tx.extra_attrs.get('hv_kv', 'N/A')} kV")
print(f" LV: {tx.extra_attrs.get('lv_kv', 'N/A')} kV")
# Find connections
connections = diagram.get_edges_by_type("CONNECTS_TO")
for conn in connections:
print(f"{conn.from_} connects to {conn.to} via {conn.via}")
# Get specific node
tx1 = diagram.get_node_by_id("TX1")
if tx1:
print(f"TX1 details: {tx1.extra_attrs}")
# Get connections from/to a specific node
from_connections = diagram.get_edges_from_node("TX1")
to_connections = diagram.get_edges_to_node("BUS1")EA Parsing works with JSON files containing electrical diagram knowledge graphs. The format includes:
{
"metadata": {
"title": "Diagram Title",
"source_image": "diagram.png",
"extracted_at": "2025-01-16T10:30:00Z",
"notes": ["Additional context"]
},
"ontology": {
"node_types": {
"Transformer": { "attrs": ["name", "mva_ratings", "hv_kv", "lv_kv"] },
"Breaker": { "attrs": ["name", "kv_class", "continuous_a"] }
},
"edge_types": {
"CONNECTS_TO": { "attrs": ["via", "notes"] },
"PROTECTS": { "attrs": ["notes"] }
}
},
"nodes": [
{
"id": "TX1",
"type": "Transformer",
"name": "Main Transformer",
"mva_ratings": [12, 16, 20],
"hv_kv": 115,
"lv_kv": 13.8
}
],
"edges": [
{
"from": "GS_A",
"type": "CONNECTS_TO",
"to": "TX1",
"via": "HV bushings",
"notes": "115kV delta"
}
],
"calculations": {
"short_circuit": {
"bus1": {
"first_cycle_asym_ka": 12.4,
"one_point_five_cycles_sym_ka": 7.2
}
},
"breaker_spec": {
"type": "GE VB1 vacuum",
"kv_class": 13.8,
"continuous_a": 1200
}
}
}- metadata: Information about the source diagram and extraction process
- ontology: Definitions of component and connection types
- nodes: Electrical components with their attributes
- edges: Connections and relationships between components
- calculations: Engineering analysis results (short circuit, breaker specs, etc.)
The system supports custom component types through the ontology definition. Add new types by extending the node_types and edge_types in your JSON data.
Extract and validate engineering calculations including:
- Short circuit analysis (first cycle, interrupting capacity)
- Breaker specifications and ratings
- Transformer ratings and impedance
- Protection coordination data
All data is validated using Pydantic models, ensuring:
- Type safety and validation
- Required field checking
- Data consistency
- Error reporting for malformed data
The Electrical Assembly Analyzer includes comprehensive Neo4j integration for storing and querying electrical diagrams as graph databases. This enables powerful graph-based analysis and querying capabilities.
- Neo4j database (version 5.0+)
- Neo4j Python driver (included in dependencies)
-
Start Neo4j (using Docker):
docker run -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/password neo4j:latest
-
Store a diagram in Neo4j:
ea-analyze neo4j store data/one-line-knowledge-graph.json
-
View stored data summary:
ea-analyze neo4j summary
Store an electrical diagram in Neo4j database.
ea-analyze neo4j store <input_file> [OPTIONS]
Options:
--uri TEXT Neo4j connection URI [default: bolt://localhost:7687]
--username TEXT Neo4j username [default: neo4j]
--password TEXT Neo4j password [default: password]
--database TEXT Neo4j database name [default: neo4j]
--clear Clear database before storingShow a summary of the stored diagram data.
ea-analyze neo4j summary [OPTIONS]Query and display protection schemes in the diagram.
ea-analyze neo4j protection-schemes [OPTIONS]Execute custom Cypher queries on the stored data.
ea-analyze neo4j query "MATCH (n:Transformer) RETURN n.id, n.name, n.hv_kv, n.lv_kv" [OPTIONS]from ea_analyzer.neo4j_client import Neo4jClient
from ea_analyzer.parser import ElectricalDiagramParser
# Load diagram
parser = ElectricalDiagramParser()
diagram = parser.load_from_file("data/one-line-knowledge-graph.json")
# Store in Neo4j
with Neo4jClient(uri="bolt://localhost:7687", username="neo4j", password="password") as client:
result = client.store_diagram(diagram)
print(f"Stored {result['nodes_created']} nodes and {result['relationships_created']} relationships")
# Query protection schemes
schemes = client.get_protection_schemes()
for scheme in schemes:
print(f"Relay {scheme['relay_id']} protects {scheme['protected_name']}")
# Custom query
transformers = client.query_diagram("MATCH (t:Transformer) RETURN t.id, t.name")
for tx in transformers:
print(f"Transformer: {tx['t.id']} - {tx['t.name']}")The Neo4j integration creates the following graph structure:
-
Nodes: Each electrical component becomes a node with its type as a label
- Labels:
GridSource,Transformer,Breaker,Busbar,RelayFunction, etc. - Properties: All component attributes (voltage, ratings, specifications, etc.)
- Labels:
-
Relationships: Electrical connections and functional relationships
CONNECTS_TO: Physical electrical connectionsPROTECTS: Protection relationships (relays protecting equipment)MEASURES: Measurement relationships (CTs/PTs measuring equipment)CONTROLS: Control relationshipsPOWERED_BY: Power supply relationshipsLOCATED_ON: Physical location relationships
-
Special Nodes:
Metadata: Diagram metadata and source informationOntology: Node and edge type definitionsCalculations: Engineering calculation results
Find all transformers and their connections:
MATCH (t:Transformer)-[r:CONNECTS_TO]-(connected)
RETURN t.name, t.hv_kv, t.lv_kv, type(r), connected.nameFind protection schemes:
MATCH (relay:RelayFunction)-[r:PROTECTS]->(protected)
RETURN relay.device_code, relay.description, protected.name, protected.typeFind electrical paths between two buses:
MATCH path = (bus1:Busbar {id: "BUS1"})-[*]-(bus2:Busbar {id: "BUS2"})
WHERE ALL(r in relationships(path) WHERE type(r) = "CONNECTS_TO")
RETURN [node in nodes(path) | node.name] as pathFind all components connected to a specific bus:
MATCH (bus:Busbar {id: "BUS1"})-[r:CONNECTS_TO]-(component)
RETURN component.type, component.name, r.via, r.notesConfigure Neo4j connection using environment variables:
export NEO4J_URI="bolt://localhost:7687"
export NEO4J_USERNAME="neo4j"
export NEO4J_PASSWORD="your_password"
export NEO4J_DATABASE="neo4j"- Parse electrical diagram knowledge graphs from JSON files
- Extract structured data about electrical components (transformers, breakers, buses, etc.)
- Query and analyze electrical system topology
- Command-line interface for common operations
- Rich data models using Pydantic for validation
- Support for engineering calculations and specifications
- Flexible component and connection type definitions
- Comprehensive error handling and validation
EA-Parsing/
├── src/
│ └── ea_analyzer/ # Main Python package
│ ├── __init__.py # Package initialization
│ ├── models.py # Pydantic data models
│ ├── parser.py # JSON parsing and data extraction
│ └── cli.py # Command-line interface
├── tests/ # Unit tests
│ ├── __init__.py
│ └── test_parser.py # Parser tests
├── data/ # Sample data and images
│ ├── one-line-knowledge-graph.json # Sample electrical diagram
│ └── images/ # Diagram images
├── pyproject.toml # Project configuration
├── README.md # This file
└── .gitignore # Git ignore rules-
Clone and setup development environment:
git clone <repository-url> cd EA-Parsing # Create virtual environment uv venv source .venv/bin/activate # On Windows: .venv\Scripts\activate # Install with development dependencies uv pip install -e ".[dev]"
-
Run tests:
# Run all tests pytest # Run with coverage pytest --cov=ea_analyzer --cov-report=html # Run specific test file pytest tests/test_parser.py -v
-
Code quality checks:
# Format and lint code with ruff ruff check --fix src/ tests/ ruff format src/ tests/ # Type checking mypy src/
-
Create a feature branch:
git checkout -b feature/new-feature-name
-
Make your changes:
- Add new functionality to appropriate modules
- Update tests for new features
- Update documentation as needed
-
Test your changes:
pytest ruff check src/ tests/ ruff format --check src/ tests/ mypy src/
-
Submit a pull request with:
- Clear description of changes
- Tests for new functionality
- Updated documentation
This project follows modern Python best practices:
- Formatting & Linting: Ruff for comprehensive code analysis and formatting
- Type hints: Full type annotation support
- Documentation: Google-style docstrings
- Framework: pytest
- Coverage: pytest-cov
- Test structure: Mirror source structure in
tests/ - Fixtures: Use pytest fixtures for test data
- Mocking: Use unittest.mock for external dependencies
from ea_analyzer.parser import ElectricalDiagramParser
from pathlib import Path
# Load diagram
parser = ElectricalDiagramParser()
diagram = parser.load_from_file(Path("data/one-line-knowledge-graph.json"))
# Get overview
summary = parser.get_summary()
print(f"Diagram: {summary['metadata'].get('title', 'Unknown')}")
print(f"Components: {summary['total_nodes']}")
print(f"Connections: {summary['total_edges']}")
# Analyze transformers
transformers = diagram.get_nodes_by_type("Transformer")
for tx in transformers:
ratings = tx.extra_attrs.get('mva_ratings', [])
print(f"{tx.name}: {ratings} MVA")# Find all protection relationships
protection_edges = diagram.get_edges_by_type("PROTECTS")
for edge in protection_edges:
relay = diagram.get_node_by_id(edge.from_)
protected = diagram.get_node_by_id(edge.to)
if relay and protected:
print(f"{relay.extra_attrs.get('device_code', 'Unknown')} "
f"protects {protected.name or protected.id}")# Find all connections to a specific bus
bus_connections = diagram.get_edges_to_node("BUS1")
bus_connections.extend(diagram.get_edges_from_node("BUS1"))
print("Bus 1 connections:")
for conn in bus_connections:
other_node = conn.to if conn.from_ == "BUS1" else conn.from_
print(f" {other_node} ({conn.type})")# Export a stored diagram to PNG
./ea-analyzer-cli.sh neo4j export 1 --output my_diagram.png
# Export with custom layout and size
./ea-analyzer-cli.sh neo4j export 1 \
--output large_diagram.png \
--layout hierarchical \
--width 20 \
--height 16 \
--dpi 300
# Export with spring layout
./ea-analyzer-cli.sh neo4j export 1 \
--output spring_layout.png \
--layout springImportError: No module named 'ea_analyzer'
- Ensure you're in the project directory
- Activate the virtual environment:
source .venv/bin/activate - Install in development mode:
uv pip install -e .
FileNotFoundError when loading data
- Check that the data file exists
- Use absolute paths or ensure you're in the correct directory
- Verify file permissions
Validation errors when parsing JSON
- Check JSON syntax with a JSON validator
- Ensure required fields are present
- Verify data types match expected schema
CLI command not found
- Ensure virtual environment is activated
- Reinstall the package:
uv pip install -e . - Check that the package is properly installed:
pip list | grep ea-analyzer
- Documentation: Check this README and inline code documentation
- Issues: Report bugs and request features via GitHub issues
- Discussions: Use GitHub discussions for questions and ideas
We welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Run the test suite:
pytest - Format your code:
ruff format src/ tests/ - Commit your changes:
git commit -m 'Add amazing feature' - Push to your branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.

