diff --git a/README.md b/README.md index 9e98db7..865c703 100644 --- a/README.md +++ b/README.md @@ -1 +1,305 @@ -# RailNetworkGraph \ No newline at end of file +# RailNetworkGraph + +**RailNetworkGraph** is a desktop application (built with **CustomTkinter**) that **finds the fastest railway connections** based on **GTFS data**. +It calculates **route distance**, **ticket price**, and **visualizes the path** on an interactive map. + +The application supports: + +- Finding the **fastest route (including transfers)** using **Dijkstra’s algorithm** on a **time-expanded graph**. +- Calculating **ticket prices** based on the **physical railway track distance**, not as-the-crow-flies. +- Displaying an **interactive map** (Matplotlib) with stations, connections, and region borders. +- Showing a **timetable (nearest departures)** when a station is clicked. + +> **License:** `CC0-1.0` *(see [LICENSE](LICENSE) for details)* + +--- + +## ⚙️ Technologies + +### Runtime +- **Python** 3.12–3.14 +- **CustomTkinter** – GUI +- **Pandas** – GTFS data processing +- **Matplotlib / GeoPandas** – Interactive map plotting +- **NetworkX** – Railway graph analysis (in `distance_counter` module) + +### Production / Development +- **Poetry** – Dependency and package management +- **requirements.txt / requirements-dev.txt** – pip installation +- **mkdocs** – Documentation (`docs/`, `mkdocs.yml`) +- **pre-commit** – Auto-formatting and linting +- **CI/CD** – GitHub workflows (`.github/`) +- **logging_config** – Colored logs with environment detection +- **PyInstaller** – `.exe` build (`RailNetworkGraph.spec`) +- **mypy** – Static type checking +- **Black** – Code formatting +- **Ruff** – Linting and style enforcement + +--- + +## 🧠 How It Works + +### 1. Data Loading +- On startup, the app loads **GTFS timetable data**. +- It builds two graphs: + - **Time-Expanded Graph:** Nodes represent departure events (e.g. `(Station A, Train 123, 08:15)`), used by Dijkstra to find the fastest route. + - **Station Graph:** Nodes represent stations, used for map visualization and simple pathfinding (BFS). + +### 2. User Input +- The user provides **origin station**, **destination station**, and **start time**. +- Optionally selects a **discount**. + +### 3. Route Finding ("Search" Button) +- `SubmitHandler` launches `PathFinderDijkstra`. +- The algorithm finds the **fastest path** on the time-expanded graph, minimizing travel + transfer times. + +### 4. Analysis (Distance & Price) +- Retrieves **physical distance** by summing pre-computed segment lengths (`railway_segment_lengths.txt`). +- Calculates **ticket price** using distance (`base_price_table.txt`) and applies discount (`discounts_percentages.txt`). + +### 5. Presentation +- `TicketPopup` displays route, duration, distance, and price. +- The route is highlighted in red on the map. +- Clicking any station opens `StationInfoPopup` with nearest departures. + +--- + +## 🗂️ Project Structure + +``` +## 🗂️ Project Structure + +RailNetworkGraph/ +├─ .gitignore # Git ignore rules +├─ .pre-commit-config.yaml # pre-commit hooks (Black, Ruff, mypy, etc.) +├─ LICENSE # License (CC0-1.0, see exceptions inside) +├─ mkdocs.yml # MkDocs site configuration +├─ poetry.lock # Poetry lockfile +├─ pyproject.toml # Poetry project config (deps, tools) +├─ README.md # Project readme +├─ requirements.txt # runtime dependencies +├─ RailNetworkGraph.spec # PyInstaller build specification +│ +├─ .github/ +│ └─ workflows/ +│ ├─ build.yml # Build workflow (package/test build) +│ ├─ ci.yml # CI workflow (lint, tests) +│ └─ release.yml # Release workflow (PyInstaller, publish artifacts) +│ +├─ docs/ # Documentation (MkDocs site content) +│ ├─ index.md # Project introduction (homepage) +│ ├─ css/ +│ │ ├─ mkdocstrings.css # Styling for mkdocstrings plugin +│ │ └─ theme-variants.css # Additional theme variants +│ └─ gen_ref_pages/ # Scripts for generating API reference pages +│ ├─ config.py +│ ├─ context.py +│ ├─ generate.py +│ ├─ gen_ref_pages.py +│ ├─ helpers.py +│ └─ traverse.py +│ +└─ src/ + └─ rail_network_graph/ + ├─ app.py # Main application (data loading, graph init, GUI setup) + ├─ config.py # Project configuration (paths, constants, settings) + ├─ logging_config.py # logging config (colors, ANSI detection) + ├─ __main__.py # Entry point (python -m rail_network_graph) + │ + ├─ assets/ + │ ├─ data/ + │ │ ├─ gtfs_data/ + │ │ │ ├─ routes.txt # GTFS routes file (names) + │ │ │ ├─ stops.txt # GTFS stops file (locations, names, parent stations) + │ │ │ ├─ stop_times.txt # GTFS stop times file (schedule) + │ │ │ └─ trips.txt # GTFS trips file (links stop_times to routes) + │ │ ├─ railway_distances/ + │ │ │ └─ railway_segment_lengths.txt # Output file: station-pair distances (km) + │ │ ├─ tickets_price/ + │ │ │ ├─ base_price_table.txt # Distance-to-price lookup table + │ │ │ └─ discounts_percentages.txt # Discount types and percentages + │ │ └─ voivodeship_border/ + │ │ └─ dolnoslaskie.geojson # GeoJSON file for the region map boundary + │ └─ img/ + │ └─ icon.ico # Windows icon + │ + ├─ data_processing/ + │ ├─ data_loader.py # Loads raw GTFS .txt files into pandas DataFrames + │ └─ data_processor.py # Processes raw GTFS data (merging, mapping stops to stations) + │ + ├─ distance_counter/ + │ ├─ distance_counter.py # Main script to run the distance calculation pipeline + │ ├─ graph_snapper.py # Snaps station coordinates (lat/lon) to the nearest railway graph node + │ ├─ railway_graph_builder.py # Builds NetworkX graph from railway GeoJSON line data + │ ├─ railway_route_calculator.py # Calculates shortest path distances (km) on the railway graph + │ └─ results_exporter.py # Exports calculated distances to a .txt file + │ + ├─ graphs/ + │ ├─ base_graph.py # Base class for a simple directed graph + │ └─ stations_graph.py # Graph of station-to-station connections based on GTFS trip sequences + │ + ├─ GUI/ + │ ├─ gui_creator.py # Main GUI builder, initializes and connects all UI components + │ ├─ counter_panel/ + │ │ ├─ input_panel.py # UI for station/time inputs and discount selection + │ │ ├─ submit_handler.py # Logic for the 'Search' button (runs pathfinder, gets price, updates UI) + │ │ └─ ticket_popup.py # Popup window to display the final route, time, and price + │ ├─ map/ + │ │ ├─ map_canvas.py # The interactive Matplotlib canvas (handles zoom, pan, click) + │ │ └─ map_plotter.py # Logic for drawing stations, connections, and highlights on the map + │ └─ station_info/ + │ ├─ station_info_logic.py # Fetches connection data/timetable for a clicked station + │ └─ station_info_popup.py # Popup window to display timetable/info for a single station + │ + ├─ path_finder/ + │ ├─ cleaner.py # Cleans the raw path result (removes cycles, collapses duplicates) + │ ├─ graph.py # Builds the time-expanded graph for Dijkstra (nodes = departure events) + │ ├─ models.py # Data models (e.g., StopRow) for pathfinding + │ ├─ path_finder.py # Main Dijkstra algorithm implementation on the time-expanded graph + │ └─ time_utils.py # Utility functions for handling time (HH:MM:SS <-> minutes) + │ + └─ utils/ + ├─ distance_calculator.py # Calculates total route distance using pre-computed segment lengths + └─ price_calculator.py # Calculates ticket price based on distance and pricing table + + +``` +## 🔧 Installation + +### Option A — pip + +**Users (runtime only):** +```bash +python -m venv .venv +source .venv/bin/activate # Linux/macOS +.venv\Scripts\activate # Windows + +pip install --upgrade pip +pip install -r requirements.txt +pip install -e . +``` + +**Developers (runtime + dev):** +```bash +pip install -r requirements.txt -r requirements-dev.txt +pip install -e . +``` + +--- + +### Option B — Poetry + +**Users (without dev):** +```bash +poetry install --without dev +poetry run rail_network_graph +``` + +**Developers (with dev):** +```bash +poetry install +poetry run rail_network_graph +``` + +--- + +## 📚 Documentation + +Built with **mkdocs**. + +```bash +mkdocs serve # local preview (http://127.0.0.1:8000) +mkdocs build # build into site/ +``` + +--- + +## 🏗️ Build Executable + +To build a Windows `.exe` with **PyInstaller**: + +```bash +pyinstaller RailNetworkGraph.spec +``` + +The resulting binary will be in `dist/`. + +--- + +## 🛠️ Development Tools + +This project uses several tools to keep the codebase clean and consistent: + +### Type checking +```bash +mypy src/ +``` + +### Linting +```bash +ruff check src/ +``` + +### Auto-formatting +```bash +black src/ +``` + +### Run all pre-commit hooks locally +```bash +pre-commit run --all-files +``` + +--- + +## ▶️ Running the App + +### From source +```bash +python -m rail_network_graph +``` + +### With Poetry +```bash +poetry run rail_network_graph +``` + +### After installation +```bash +rail_network_graph +``` + +--- + +## 💻 Usage + +1. Launch the app (`rail_network_graph`). +2. Enter **Station 1** (origin), **Station 2** (destination), and **Start time** (`HH:MM:SS`). +3. Optionally, select a **discount**. +4. Click **Search**. +5. View route details (time, price, distance) in the popup window. +6. See the route highlighted on the map. +7. (Optional) Click any station on the map to view its nearest departures. + +--- + +## 🖼️ Screenshots + +**GIF:** +![Main GIF](screenshots/railnetworkgraph.gif) + +**Main application screen:** +![Main application screen:](screenshots/main_application_screen.png) + +**Search result (ticket popup):** +![Search result (ticket popup):](screenshots/search_result.png) + +**Station info (on-click):** +![Station info (on-click):](screenshots/station_info.png) + +--- + +## 📜 License + +Released under **CC0-1.0 (public domain)**. +You may copy, modify, distribute, and use it commercially without asking for permission. \ No newline at end of file diff --git a/screenshots/main_application_screen.png b/screenshots/main_application_screen.png new file mode 100644 index 0000000..ea51f38 Binary files /dev/null and b/screenshots/main_application_screen.png differ diff --git a/screenshots/railnetworkgraph.gif b/screenshots/railnetworkgraph.gif new file mode 100644 index 0000000..d6a4244 Binary files /dev/null and b/screenshots/railnetworkgraph.gif differ diff --git a/screenshots/search_result.png b/screenshots/search_result.png new file mode 100644 index 0000000..296afe6 Binary files /dev/null and b/screenshots/search_result.png differ diff --git a/screenshots/station_info.png b/screenshots/station_info.png new file mode 100644 index 0000000..19509c9 Binary files /dev/null and b/screenshots/station_info.png differ