from tkinter import ttk
import csv
from PIL import Image
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
– це бібліотека для створення, обробки й візуалізації графів (мереж) ЇЇ основні властивості полягають в : Створенні графів:
- Підтримка як неорієнтованих, так і орієнтованих графів
- Робота з ваговими графами (кожному ребру можна призначити "вагу")
- Створення мультиграфів (декілька ребер між одними й тими ж вершинами
- Імпортування графів із файлів (наприклад, .gml, .graphml, .adjlist, .edgelist)
Модифікація графів:
-
Додавання/видалення вузлів і ребер G.add_node(1) – додає один вузол G.add_nodes_from([2, 3, 4, 5]) = додає кілька вузлів G.remove_node(5) – видаляє вузол pos = nx.spring_layout(G, k=0.8, iterations=100) – розсташування G.add_edge(1, 2) – одне ребро G.add_edges_from([(2, 3), (3, 4), (4, 5), (5, 1)]) – кілька ребер G.remove_edge(1, 2) – видаляє ребро
-
Зміна атрибутів вузлів або ребер (назви, ваги, кольори тощо) G.add_node(1, color='red', weight=5) – додати атрибут до вузла G.add_edge(1, 2, weight=3, label='A') – додати атрибут до ребра
-
Об'єднання, злиття графів або отримання їх підграфів
– бібліотека для створення графіків і візуалізацій
– модуль для роботи з кольорами, зокрема нормалізації значень для призначення кольорів.
– кастомізована обгортка для tkinter, стандартної бібліотеки для створення GUI (графічних інтерфейсів користувача) у Python. Вона додає сучасний вигляд і стилізацію до інтерфейсу, дозволяючи створювати теми, кастомізовані елементи управління ( кнопки, меню, етикетки та інше)
Використання у коді: CTk() створює головне вікно програми CTkLabel, CTkButton, CTkOptionMenu — сучасні аналоги елементів управління tkinter set_appearance_mode() дозволяє задавати світлу чи темну тему set_default_color_theme() — налаштування кольорової схеми
є частиною стандартної бібліотеки tkinter і надає елементи управління, що підтримують стилізацію. Використання у коді: Treeview використовується для створення таблиць (наприклад, для відображення результатів турніру). Налаштування стилю (ttk.Style()) застосовується до таблиці для коректного відображення тексту.
використовується для читання та запису даних у форматі CSV. У коді записується таблиця турніру у файл tournament.csv.
Підключено для роботи з зображеннями. В коді використовується для відкриття зображення графу (Image.open()), яке згодом виводиться у графічному інтерфейсі.
- Поняття вершин і ребер
- Поняття орієнтованого графа (DiGraph)
Використання функцій бібліотеки networkx для роботи з орієнтованими графами, таких як add_edges_from та spring_layout, дозволяє візуалізувати і аналізувати структуру взаємозв'язків між гравцями. Побудова візуалізації з використанням кольору для позначення властивостей графів (наприклад, рейтингу гравців).
Алгоритм PageRank в цьому коді використовується для визначення відносної важливості гравців у турнірі на основі результатів матчів. Ранжування ґрунтується на графовому поданні перемог і поразок між гравцями.
-
Зчитування даних турніру: Дані про турнір представлені у вигляді текстового файлу з турнірною таблицею і результатами кожної гри. Функція get_tournaments_dict() повертає словник, де ключі це назви турнірів, а значення, це шляхи до файлів з інформацією про турнір. Функція read_file() повертає кортеж з даними про турнір: • Назва турніру. • Список гравців так їхніх країн. • Список пар переможець/переможений.
-
Перетворення даних у граф: Дані про матчі представлені як список пар переможець/переможений (
games). Використовується функція to_dict() для створення словника, де кожен гравець має два набори: • Множина суперників, яких він переміг. • Множина суперників, від яких зазнав поразки. -
Ітеративне обчислення PageRank: • Алгоритм реалізовано у функції page_rank(graph). • Початковий рейтинг всіх гравців ініціалізується рівним значенням 1/N, де N- кількість гравців • Ітеративне обчислення відбувається допоки максимальна абсолютна різниця пейдж ранків між попередньою та даною ітерацією не буде менша або рівна заданому параметру, в даному випадку 0.01. • На кожній ітерації PageRank гравця обчислюється як сума внесків від його суперників, які на попередній ітерації поділили свій поточний рейтинг між усіма переможцями, від яких вони програли.
-
Сортування за рейтингом: • Функція sort_by_rank() упорядковує гравців за їхніми остаточними значеннями PageRank. • Результати подаються у вигляді словника, де ключ — ім'я гравця, а значення — його позиція у рейтингу.
-
Візуалізація графу: • Вузли графу (гравці) забарвлюються на основі їхніх PageRank значень: вищий рейтинг відповідає яскравішим вузлам. • Візуалізація здійснюється через бібліотеку networkx із використанням спрямованого графу (DiGraph).
• Алгоритм PageRank дозволяє автоматично ранжувати гравців за їхнім впливом у турнірі.
• Результати виводяться у вигляді таблиці та графу, що робить аналіз зрозумілим і наочним.
- Видалення старих даних із таблиці.
- Читання нового файлу даних турніру.
- Перетворення даних у формат для графа.
- Обчислення рангів PageRank для гравців.
- Побудова та збереження графа у вигляді зображення.
- Оновлення графічного інтерфейсу для відображення нового графа.
- Експорт результатів у CSV.
- Вивід результатів у таблицю для користувача.
- Зчитування даних турніру із файлу. Перетворення даних у структуру графа: Гравці — це вузли графа. Матчі — це спрямовані ребра між вузлами. 2)Обчислення PageRank для кожного гравця: 3)Алгоритм виконує кілька ітерацій, поки різниця між результатами ітерацій не стане меншою за заданий поріг (PAGE_RANK_DELTA). 4)Сортування гравців за їхніми фінальними рангами. Візуалізація графа: 5)Вузли графа фарбуються відповідно до їхнього рейтингу. 6)Результати відображаються у графічному інтерфейсі. Експорт результатів у CSV-файл.
read_file(): Зчитує дані турніру з текстового файлу
page_rank(): Реалізує алгоритм PageRank
sort_by_rank(): Ранжує гравців за оцінками PageRank
to_dict(): Перетворює результати ігор на словник
1)Назва турніру. 2) Дані про гравців та їх країни. 3) Результати ігор у форматі списку перемог і поразок.
- Зчитує перший рядок файлу як назву турніру.
- Пропускає зайві рядки, які не містять корисної інформації.
- Виділяє блок даних про гравців та результати матчів.
- Перетворює дані у формат, який зручно використовувати для побудови графа: players: список гравців із зазначенням їхніх країн. games: список матчів у форматі ("гравець_переможець", "гравець_програвший").
tournament_name, players_countries, games = read_file(file_path)
- Гравцями, яких він переміг.
- Гравцями, від яких він програв.
dict_games = to_dict(games)
Для кожного матчу додається зв'язок між переможцем та тим, хто програв. Створюється словник такого формату:
{
"гравець_А": ({"переміг_Б", "переміг_С"}, {"програв_Д"}),
"гравець_Б": ({"переміг_Д"}, {"програв_А"}),
...
}
global page_ranks
page_ranks = sort_by_rank(raw_prs)
- page_rank: Обчислює вагу (ранг) кожного гравця на основі взаємозв'язків у графі.
- sort_by_rank: Сортує гравців за їхнім фінальним рангом.
Як це працює:
Останнє значення кожного гравця у списку рангів береться за основу для сортування.
Створюється новий словник, де кожному гравцю привласнюється його позиція у рейтингу
{
"гравець_С": 1, # найвищий ранг
"гравець_Д": 2,
...
}
graph_visualize(games, page_ranks)
Створює зображення графа, де вузли представляють гравців, а ребра – їх взаємодії (хто кого переміг).
Побудова графа: Вузли — це гравці. Ребра — це результати матчів. Колір вузлів: Колір залежить від рангу гравця (більш високий ранг = більш насичений колір). Розташування вузлів: Використовується метод spring_layout, який імітує розташування вузлів як у пружній системі. Збереження графа: Граф зберігається як зображення PNG.
remove_graph()
show_graph()
Видаляє попередній граф із вікна і додає новий.
with open('tournament.csv', 'w', encoding='utf-8') as file:
file.write('Country,Name,PR,Raw Data\n')
for name in page_ranks.keys():
line = ','.join(map(str, [players_countries[name], name, page_ranks[name], round(raw_prs[name][-1], 3)]))
file.write(line + '\n')
Записує результати в CSV-файл, включаючи:
- Країну гравця.
- Ім'я.
- PageRank
with open('tournament.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
next(reader) # Пропускає заголовки
for row in reader:
table.insert("", "end", values=row)
- Павло Ружило - ініціатор та розробник алгоритму, допомога з UI процесами
- Цибрівський Олександр - аналітик з обробки даних, розробник алгоритму
- Мандрик Софія - робота з візуалізацією графів, написання звіту
- Довбенчук Олена - робота з UI, розробка презентації
- Мацелюх Максим - робота з UI
Павло:
"So far цей проєкт був найкрутішим з усіх курсів в 1 семестрі! Часом навіть ловив себе на тому, що хотілось робити швидше його, aніж будь-яке інше завдання. Дав змогу ознайомитись одразу з кількома корисними бібліотеками, пізнати новий алгоритм та підтягнути навички роботи в команді з GitHub."
Софія:
"Проект дав змогу ще раз попрактикувати навички роботи в команді, поєднюючи у собі практику з програмування та дискретної математики одночасно! Робота з новим алгоритмом дуже зацікавила! Дякую за таку перфект можливість нашим викладачам та асистентці, всі поради були справді корисними!"
Олександр:
"Цей проєкт удосконалив наші уміння використовувати систему контролю версій. Було дуже цікаво вивчити досить важливий алгоритм і реалізувати його в коді"
Олена:
"Це був справді корисний командний проєкт, який допоміг краще закріпити знання з дискретної математики. Особливо він допоміг краще розібратися з темою графів, також було дуже корисно розробити один з алгоритмів та надати йому практичного застосування. Ще одним важливим аспектом варто зазначити роботу з UI це розширило мої знання на невідомому мені раніше полі, що потім неодмінно буде корисним, тому добре, що ми навчились використовувати це саме зараз."
Максим:
"Було цікаво працювати над проектом, незважаючи на труднощі роботи в команді, ми старались працювати як одне єдине. Особисто мені сподобалось працювати з UI, вивчаючи його особливості, досліджуючи нові для мене напрямки і бібліотеки. І звсіно ж це безцінний досвід розробки проєктів і роботи з Github'ом."