DiscreteMathematics/Lab_4/window.py

229 lines
9.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PyQt5 import QtCore, QtWidgets
import sys
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.colors as mcolours
import numpy as np
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class Window(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Вікно 1")
central_widget = QtWidgets.QWidget(self)
self.grid_layout = QtWidgets.QGridLayout(central_widget)
self.id_grid_layout = QtWidgets.QGridLayout()
self.full_name = QtWidgets.QLabel(central_widget)
self.full_name.setText("П. І. Б:")
self.full_name.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.id_grid_layout.addWidget(self.full_name, 0, 0, 1, 1)
self.full_name_answer = QtWidgets.QLabel(central_widget)
self.full_name_answer.setText("Швед Андрій Дмитрович")
self.id_grid_layout.addWidget(self.full_name_answer, 0, 1, 1, 1)
self.group = QtWidgets.QLabel(central_widget)
self.group.setText("Група:")
self.group.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.id_grid_layout.addWidget(self.group, 1, 0, 1, 1)
self.group_answer = QtWidgets.QLabel(central_widget)
self.group_answer.setText("ІО-23")
self.id_grid_layout.addWidget(self.group_answer, 1, 1, 1, 1)
self.list_number = QtWidgets.QLabel(central_widget)
self.list_number.setText("Номер в списку:")
self.list_number.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.id_grid_layout.addWidget(self.list_number, 2, 0, 1, 1)
self.list_number_answer = QtWidgets.QLabel(central_widget)
self.list_number_answer.setText("30")
self.id_grid_layout.addWidget(self.list_number_answer, 2, 1, 1, 1)
self.task_number = QtWidgets.QLabel(central_widget)
self.task_number.setText("Номер завдання:")
self.task_number.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.id_grid_layout.addWidget(self.task_number, 3, 0, 1, 1)
self.task_number_answer = QtWidgets.QLabel(central_widget)
self.task_number_answer.setText("1")
self.id_grid_layout.addWidget(self.task_number_answer, 3, 1, 1, 1)
self.grid_layout.addLayout(self.id_grid_layout, 0, 0, 1, 1)
self.graph_grid_layout = QtWidgets.QGridLayout()
self.adjacency_input_label = QtWidgets.QLabel(self)
self.adjacency_input_label.setText("Введіть матрицю суміжності графа")
self.graph_grid_layout.addWidget(self.adjacency_input_label, 0, 0, 1, 1)
self.adjacency_input = QtWidgets.QTextEdit(self)
self.graph_grid_layout.addWidget(self.adjacency_input, 1, 0, 2, 1)
self.graph_label = QtWidgets.QLabel(self)
self.graph_label.setText("Розфарбований граф")
self.graph_grid_layout.addWidget(self.graph_label, 0, 1, 1, 1)
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.graph_grid_layout.addWidget(self.canvas, 1, 1, 1, 1)
self.grid_layout.addLayout(self.graph_grid_layout, 1, 0, 1, 1)
self.buttons_grid_layout = QtWidgets.QGridLayout()
self.build_graph_button = QtWidgets.QPushButton(self)
self.build_graph_button.setText("Побудувати граф")
self.buttons_grid_layout.addWidget(self.build_graph_button, 0, 0, 1, 1)
self.open_file_button = QtWidgets.QPushButton(self)
self.open_file_button.setText("Відкрити файл")
self.buttons_grid_layout.addWidget(self.open_file_button, 0, 1, 1, 1)
self.grid_layout.addLayout(self.buttons_grid_layout, 2, 0, 1, 1)
self.setCentralWidget(central_widget)
self.menubar = QtWidgets.QMenuBar(self)
self.menubar.setGeometry(QtCore.QRect(0, 0, 362, 22))
self.menubar.setDefaultUp(False)
self.menu_Windows = QtWidgets.QMenu(self.menubar)
self.menu_Windows.setTitle("Вікна")
self.setMenuBar(self.menubar)
self.exit_action = QtWidgets.QAction(self)
self.exit_action.setText("Вихід")
self.menu_Windows.addAction(self.exit_action)
self.menubar.addAction(self.menu_Windows.menuAction())
self.set_menu()
self.set_functions()
QtCore.QMetaObject.connectSlotsByName(self)
def set_menu(self):
self.exit_action.triggered.connect(lambda: sys.exit())
@staticmethod
def is_square(matrix: list) -> bool:
return all(len(row) == len(matrix) for row in matrix)
@staticmethod
def validate_values(matrix: list) -> bool:
return all(all(("1" == element) or ("0" == element) for element in row) for row in matrix)
def parse_matrix(self) -> (np.ndarray | None, str | None):
text_matrix = list(map(lambda x: x.split(" "), self.adjacency_input.toPlainText().splitlines()))
if not self.is_square(text_matrix):
return None, "square_error"
elif not self.validate_values(text_matrix):
return None, "value_error"
elif not text_matrix:
return None, "empty_matrix"
else:
return np.array(list([list(map(int, row)) for row in text_matrix])), None
def build_graphs(self):
adjacency_matrix, error = self.parse_matrix()
if adjacency_matrix is None and error == "square_error":
self.show_error(
"Матриця суміжності має бути квадратною. Перевірте чи кожен елемент рядка відділений пробілом і чи "
"дорівнює кількість рядків кількості стовпців."
)
elif adjacency_matrix is None and error == "value_error":
self.show_error(
"Матриця суміжності мусить складатись лише з нулів і одиниць розділених пробілом. Перевірте ваш ввід."
)
elif adjacency_matrix is None and error == "empty_matrix":
self.show_error(
"Матриця суміжності не може бути пустою."
)
elif type(adjacency_matrix) is np.ndarray and error is None:
adjacency_graph = self.create_adjacency_graph(adjacency_matrix)
colours = self.brute_force_colour(adjacency_graph)
self.draw_graph(adjacency_graph, colours)
@staticmethod
def show_error(error_text: str):
error_message = QtWidgets.QMessageBox()
error_message.setIcon(QtWidgets.QMessageBox.Critical)
error_message.setText("Помилка вводу")
error_message.setInformativeText(error_text)
error_message.setWindowTitle("Помилка")
error_message.exec_()
@staticmethod
def create_adjacency_graph(adjacency_matrix: np.ndarray) -> nx.Graph:
graph = nx.Graph()
nodes = [f"{i}" for i in range(len(adjacency_matrix))]
edge_indices = np.argwhere(adjacency_matrix)
edges = [(nodes[edge_index[0]], nodes[edge_index[1]]) for edge_index in edge_indices]
graph.add_nodes_from(nodes)
graph.add_edges_from(edges)
return graph
def draw_graph(self, graph: nx.Graph, colour_map: list):
self.figure.clf()
nx.draw(
graph, with_labels=True, node_size=700, font_size=14, font_family="Ubuntu Mono", node_color=colour_map,
edgecolors="black", font_weight="bold", width=2
)
plt.margins(0.2)
self.canvas.draw_idle()
@staticmethod
def previous_neighbors(graph: nx.Graph, node: str):
neighbours = list(graph.neighbors(node))
nodes = list(graph.nodes)
previous = nodes[:nodes.index(node)]
res = [n for n in previous if n in neighbours]
return res
def brute_force_colour(self, graph: nx.Graph) -> list:
coloured_nodes = dict()
i = 0
for node in graph:
previous_colours = [coloured_nodes[f'{n}'] for n in self.previous_neighbors(graph, node)]
nodes_difference = sorted(list(set(coloured_nodes.values()) - set(previous_colours)))
if (not coloured_nodes) or (not nodes_difference):
coloured_nodes[f"{node}"] = i
i += 1
else:
coloured_nodes[f"{node}"] = nodes_difference[0]
colour_map = [list(mcolours.CSS4_COLORS.keys())[i] for i in coloured_nodes.values()]
return colour_map
def open_file(self):
file_name = QtWidgets.QFileDialog.getOpenFileName(self, "Відкрити файл", "~/", "Текстові файли (*.txt)")
with open(file_name[0]) as f:
text_read = f.read()
self.adjacency_input.setText(text_read)
def set_functions(self):
self.build_graph_button.clicked.connect(lambda: self.build_graphs())
self.open_file_button.clicked.connect(lambda: self.open_file())