Skip to content

Commit 29717d8

Browse files
committed
[0.1.0] - 2025-06-22
Initial public release of MetriCalc - Added full PySide6 GUI for cross-platform support - Introduced dual processing modes: single file and batch folder - Implemented localized interface with real-time Czech/English switching - Developed core metric engine: - Precision (user accuracy) - Recall (producer accuracy) - F1-score - Overall accuracy - Kappa index - Enabled reading of 2x2 confusion matrices from semicolon-separated CSV - Built Excel export functionality with language-specific headers - Added support for: - One output file per CSV - One consolidated file with multiple sheets - Non-blocking batch processing with cancellation and progress dialog - Clean code structure divided into `core`, `ui`, `utils`, and `assets`
1 parent 1dd1965 commit 29717d8

17 files changed

+1111
-1
lines changed

.gitignore

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# macOS system files
2+
.DS_Store
3+
.AppleDouble
4+
.LSOverride
5+
Icon
6+
._*
7+
.DocumentRevisions-V100
8+
.fseventsd
9+
.Spotlight-V100
10+
.TemporaryItems
11+
.Trashes
12+
.VolumeIcon.icns
13+
.com.apple.timemachine.donotpresent
14+
15+
# Directories potentially created on remote AFP share
16+
.AppleDB
17+
.AppleDesktop
18+
Network Trash Folder
19+
Temporary Items
20+
.apdisk
21+
*.zip
22+
23+
# Python
24+
__pycache__/
25+
*.py[cod]
26+
*$py.class
27+
*.so
28+
.Python
29+
build/
30+
develop-eggs/
31+
dist/
32+
downloads/
33+
eggs/
34+
.eggs/
35+
lib/
36+
lib64/
37+
parts/
38+
sdist/
39+
var/
40+
wheels/
41+
*.egg-info/
42+
.installed.cfg
43+
*.egg
44+
.pytest_cache/
45+
.coverage
46+
htmlcov/
47+
.tox/
48+
.nox/
49+
.hypothesis/
50+
.pytest_cache/
51+
*.mo
52+
*.pot
53+
*.log
54+
local_settings.py
55+
db.sqlite3
56+
db.sqlite3-journal
57+
instance/
58+
.webassets-cache
59+
.env
60+
.venv
61+
env/
62+
venv/
63+
ENV/
64+
env.bak/
65+
venv.bak/
66+
.python-version
67+
68+
# Node.js
69+
node_modules/
70+
npm-debug.log
71+
yarn-debug.log
72+
yarn-error.log
73+
.pnpm-debug.log
74+
.npm
75+
.yarn-integrity
76+
77+
# Build outputs
78+
dist/
79+
build/
80+
out/
81+
.next/
82+
.nuxt/
83+
.output/
84+
85+
# IDE and editor files
86+
.idea/
87+
.vscode/
88+
*.swp
89+
*.swo
90+
*~
91+
.project
92+
.classpath
93+
.settings/
94+
*.sublime-workspace
95+
*.sublime-project
96+
97+
# Environment files
98+
.env
99+
.env.local
100+
.env.*.local
101+
.env.development
102+
.env.test
103+
.env.production
104+
105+
# Logs
106+
logs
107+
*.log
108+
npm-debug.log*
109+
yarn-debug.log*
110+
yarn-error.log*
111+
112+
# Testing
113+
coverage/
114+
.nyc_output/
115+
116+
# Misc
117+
.cache/
118+
.temp/
119+
.tmp/
120+
*.bak
121+
*.tmp
122+
*.temp

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Changelog
2+
3+
## [0.1.0] - 2025-06-22
4+
5+
### Added
6+
7+
- **Initial Release** of MetriCalc.
8+
- **Modern User Interface**: Application using PySide6 to provide a modern, responsive, and cross-platform user experience.
9+
- **Internationalization (i18n)**: Full UI and export support for Czech and English, with a simple dropdown to switch languages in real-time.
10+
- **Single File Processing**: Process a single confusion matrix from a `.csv` file and export results to an `.xlsx` file.
11+
- **Batch Processing**: Process all `.csv` files within a selected folder with two output options:
12+
- **Separate Files**: Generate an individual Excel file for each processed CSV.
13+
- **Single File**: Consolidate all results into a single Excel file, with each result on its own dedicated sheet.
14+
- **Core Metric Calculation**:
15+
- Reads 2x2 confusion matrices from semicolon-separated `.csv` files.
16+
- Calculates Precision (user accuracy), Recall (producer accuracy), F1-score, Overall Accuracy, and the Kappa Index.
17+
- Provides metrics for each class and a macro average.
18+
- **User Experience Enhancements**:
19+
- Asynchronous processing for batch operations to keep the UI responsive.
20+
- Progress dialog with a cancellation option for batch jobs.

README.md

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,112 @@
1-
# MetriCalc
1+
<p align="center">
2+
<a href="https://i.ibb.co/0pyTV8nq/icon.png">
3+
<img src="https://i.ibb.co/0pyTV8nq/icon.png" alt="MetriCalc Logo" width="220"/>
4+
</a>
5+
</p>
6+
7+
<h1 align="center">MetriCalc</h1>
8+
<p align="center"><em>(Born4Flight | FlyCamCzech)</em></p>
9+
10+
## Overview
11+
MetriCalc is a clean, efficient tool designed to calculate key statistical metrics from confusion matrices exported from ArcGIS Pro or other platforms. With support for single and batch processing, multi-language output, and polished export to Excel, MetriCalc is ideal for rapid performance evaluation in classification tasks.
12+
13+
---
14+
15+
## ✨ Features
16+
17+
- **Modern & Responsive UI**
18+
- Built with PySide6 for a fast, native user experience
19+
- Segmented tabs for single and batch processing workflows
20+
21+
- **Internationalization (i18n)**
22+
- Toggle between **Czech** and **English** for both interface and output
23+
- Instant language switching without restart
24+
25+
- **Metric Computation**
26+
- Reads semicolon-delimited confusion matrix `.csv` files
27+
- Calculates:
28+
- Precision (User Accuracy)
29+
- Recall (Producer Accuracy)
30+
- F1-score
31+
- Overall Accuracy
32+
- Kappa Index
33+
- Reports metrics per class and macro average
34+
35+
- **Batch Processing**
36+
- Process all `.csv` files in a selected folder
37+
- Two export modes:
38+
- One Excel per file
39+
- One Excel file with multiple sheets
40+
41+
- **Excel Export**
42+
- XLSX output with localized metric headers
43+
- Two sheets per result:
44+
- **Metrics**: Computed values
45+
- **Data**: Raw confusion matrix
46+
47+
- **Performance**
48+
- Asynchronous background thread keeps the interface responsive
49+
- Real-time progress bar with cancel option
50+
51+
---
52+
53+
## 📦 Requirements
54+
55+
- Python 3.8+
56+
- PySide6 >= 6.5.0
57+
- pandas >= 1.5.0
58+
- scikit-learn >= 1.2.0
59+
- openpyxl >= 3.1.0
60+
61+
---
62+
63+
## 🚀 Installation
64+
65+
```bash
66+
git clone https://github.com/Jakub-Espandr/MetriCalc.git
67+
cd MetriCalc
68+
pip install -r requirements.txt
69+
python main.py
70+
```
71+
72+
---
73+
74+
## 🛠️ Usage
75+
76+
1. Open the app and select **Single** or **Batch** tab
77+
2. Load `.csv` confusion matrix or folder
78+
3. Choose output location
79+
4. Select language: 🇨🇿 Čeština / 🇺🇸 English
80+
5. Click **Start Processing**
81+
82+
---
83+
84+
## 📁 Project Structure
85+
86+
```
87+
MetriCalc/
88+
├── main.py
89+
├── core/ # Metric calculations and logic
90+
├── ui/ # PySide6 GUI components
91+
├── utils/ # Helpers and localization
92+
├── assets/
93+
│ ├── fonts/
94+
│ └── icons/
95+
├── requirements.txt
96+
└── LICENSE
97+
```
98+
99+
---
100+
101+
## 🔐 License
102+
103+
This project is licensed under the **MIT License**
104+
© 2025 Jakub Ešpandr – Born4Flight, FlyCamCzech
105+
106+
See the [LICENSE](https://github.com/Jakub-Espandr/MetriCalc/raw/main/LICENSE) file for full terms.
107+
108+
---
109+
110+
## 🙏 Acknowledgments
111+
112+
- Built with ❤️ using PySide6, pandas, and openpyxl

assets/fonts/fccTYPO-Bold.ttf

146 KB
Binary file not shown.

assets/fonts/fccTYPO-Regular.ttf

143 KB
Binary file not shown.

assets/icons/icon.icns

155 KB
Binary file not shown.

assets/icons/icon.ico

164 KB
Binary file not shown.

assets/icons/icon.png

70.5 KB
Loading

core/metrics.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import pandas as pd
2+
from pathlib import Path
3+
from openpyxl import Workbook
4+
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score, cohen_kappa_score
5+
from .translations import TRANSLATIONS
6+
7+
def compute_metrics(df, language='cs'):
8+
"""Compute metrics from confusion matrix data"""
9+
df = df.copy()
10+
df.columns = df.columns.astype(str)
11+
12+
# Filter for C_1 and C_2 rows
13+
df_cm = df[df['ClassValue'].isin(['C_1', 'C_2'])]
14+
15+
# Handle decimal commas
16+
df_cm['C_1'] = df_cm['C_1'].astype(str).str.replace(',', '.').astype(float).astype(int)
17+
df_cm['C_2'] = df_cm['C_2'].astype(str).str.replace(',', '.').astype(float).astype(int)
18+
19+
cm = df_cm[['C_1', 'C_2']].to_numpy()
20+
21+
y_true = [0] * int(cm[0, :].sum()) + [1] * int(cm[1, :].sum())
22+
y_pred = [0] * int(cm[0, 0]) + [1] * int(cm[0, 1]) + [0] * int(cm[1, 0]) + [1] * int(cm[1, 1])
23+
24+
precision = precision_score(y_true, y_pred, average=None, zero_division=0)
25+
recall = recall_score(y_true, y_pred, average=None, zero_division=0)
26+
f1 = f1_score(y_true, y_pred, average=None, zero_division=0)
27+
accuracy = round(accuracy_score(y_true, y_pred), 3)
28+
kappa = round(cohen_kappa_score(y_true, y_pred), 3)
29+
30+
avg_precision = round(precision_score(y_true, y_pred, average='macro', zero_division=0), 3)
31+
avg_recall = round(recall_score(y_true, y_pred, average='macro', zero_division=0), 3)
32+
avg_f1 = round(f1_score(y_true, y_pred, average='macro', zero_division=0), 3)
33+
34+
class_names = TRANSLATIONS[language]['class_names']
35+
return [
36+
[class_names[0], round(precision[0], 3), round(recall[0], 3), round(f1[0], 3), accuracy, kappa],
37+
[class_names[1], round(precision[1], 3), round(recall[1], 3), round(f1[1], 3), accuracy, kappa],
38+
[class_names[2], avg_precision, avg_recall, avg_f1, accuracy, kappa]
39+
]
40+
41+
def export_to_excel(input_path, output_path, language='cs'):
42+
"""Export metrics to Excel file"""
43+
try:
44+
df = pd.read_csv(input_path, sep=';')
45+
metrics = compute_metrics(df, language)
46+
wb = Workbook()
47+
sheetname = Path(input_path).stem
48+
49+
# Metrics sheet
50+
ws1 = wb.active
51+
ws1.title = f"{TRANSLATIONS[language]['excel_metrics_sheet']}_{sheetname}"
52+
headers = TRANSLATIONS[language]['headers']
53+
for col, header in enumerate(headers, start=1):
54+
ws1.cell(row=1, column=col).value = header
55+
for row_i, row_data in enumerate(metrics, start=2):
56+
for col_i, value in enumerate(row_data, start=1):
57+
ws1.cell(row=row_i, column=col_i).value = value
58+
59+
# Data sheet
60+
ws2 = wb.create_sheet(f"{TRANSLATIONS[language]['excel_data_sheet']}_{sheetname}")
61+
ws2.append(list(df.columns))
62+
for r in df.itertuples(index=False):
63+
ws2.append(list(r))
64+
65+
wb.save(output_path)
66+
return True, None, (metrics, df)
67+
except Exception as e:
68+
return False, str(e), None
69+
70+
def add_to_workbook(wb, input_path, metrics, df, language='cs'):
71+
"""Add data to existing workbook"""
72+
try:
73+
sheetname = Path(input_path).stem
74+
75+
# Metrics sheet
76+
ws1 = wb.create_sheet(f"{TRANSLATIONS[language]['excel_metrics_sheet']}_{sheetname}")
77+
headers = TRANSLATIONS[language]['headers']
78+
for col, header in enumerate(headers, start=1):
79+
ws1.cell(row=1, column=col).value = header
80+
for row_i, row_data in enumerate(metrics, start=2):
81+
for col_i, value in enumerate(row_data, start=1):
82+
ws1.cell(row=row_i, column=col_i).value = value
83+
84+
# Data sheet
85+
ws2 = wb.create_sheet(f"{TRANSLATIONS[language]['excel_data_sheet']}_{sheetname}")
86+
ws2.append(list(df.columns))
87+
for r in df.itertuples(index=False):
88+
ws2.append(list(r))
89+
90+
return True, None
91+
except Exception as e:
92+
return False, str(e)

0 commit comments

Comments
 (0)