Basic app with PyQt5

Published on Aug. 16, 2019, 10:43 p.m.

main.py

import sys
from PyQt5.QtWidgets import QApplication
from GUI.main_window import MainWindow


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dash_board = MainWindow()
    sys.exit(app.exec_())

main_window.py

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QMainWindow, QAction, qApp
from GUI.dash_board import DashBoard


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Net Data Generator')
        self.setWindowIcon(QIcon('doc icon.ico'))
        self.dash_board = DashBoard()
        self.setCentralWidget(self.dash_board)
        self.menu_bar = self.menuBar()
        self.init_ui()
        # self.showMaximized()
        self.show()

    def init_ui(self):
        self.create_file_menu()
        self.create_edit_menu()
        self.create_about_menu()

    def create_file_menu(self):
        file = self.menu_bar.addMenu('File')

        new_action = QAction('&New image set', self)
        new_action.setShortcut('Ctrl+N')
        file.addAction(new_action)
        new_action.triggered.connect(self.new_image_set)

        open_action = QAction('&Open image set...', self)
        open_action.setShortcut('Ctrl+O')
        file.addAction(open_action)
        open_action.triggered.connect(self.open_image_set)

        save_action = QAction('&Save image set...', self)
        save_action.setShortcut('Ctrl+S')
        file.addAction(save_action)
        save_action.triggered.connect(self.save_image_set)

        save_as_action = QAction('&Save as image set...', self)
        save_as_action.setShortcut('Ctrl+A')
        file.addAction(save_as_action)
        save_as_action.triggered.connect(self.save_as_image_set)

        reset_action = QAction('Reset image set...', self)
        reset_action.setShortcut('Ctrl+Shift+R')
        file.addAction(reset_action)
        reset_action.triggered.connect(self.reset_image_set)

        quit_action = QAction('Quit', self)
        quit_action.setShortcut('Ctrl+Q')
        file.addAction(quit_action)
        quit_action.triggered.connect(quit_program)

    def new_image_set(self):
        pass

    def open_image_set(self):
        pass

    def save_image_set(self):
        pass

    def save_as_image_set(self):
        pass

    def reset_image_set(self):
        pass

    def create_edit_menu(self):
        edit = self.menu_bar.addMenu('Edit')

        find_menu = edit.addMenu('Find')
        color_preferences = edit.addMenu('Configure color preferences')
        font_preferences = edit.addMenu('Configure font')

        find_action = QAction('Find...', self)
        find_menu.addAction(find_action)
        replace_action = QAction('Replace...', self)
        find_menu.addAction(replace_action)

        change_bar_colors = QAction('Bar colors', self)
        color_preferences.addAction(change_bar_colors)

        change_font = QAction('Change font', self)
        font_preferences.addAction(change_font)

    def create_about_menu(self):
        about = self.menu_bar.addMenu('About')
        help_menu = about.addMenu('Help')

        controls_help = QAction('Controls', self)
        help_menu.addAction(controls_help)

        info = QAction('Info', self)
        help_menu.addAction(info)


def quit_program():
    qApp.quit()

dash_board.py

import unicodedata
import os
import operator
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
import pandas as pd
import pickle as pkl
from functools import partial
from PyQt5.QtCore import QThread, QTimer
from PyQt5.QtWidgets import QWidget, QFileDialog, QMessageBox, QComboBox, QStatusBar, QVBoxLayout, QHBoxLayout, QLineEdit, QCheckBox, QPushButton, QRadioButton, QButtonGroup, QLabel, QProgressBar, QLCDNumber, QSizePolicy
from Objects.meta_data import MetaData
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from Functions.auxiliary_functions import get_file_extension, get_k_most_central_nodes
from Objects.net_data_obj import NetDataObj
from Objects.model_obj import Model
from win32api import GetSystemMetrics


class DashBoard(QWidget):
    def __init__(self):
        super().__init__()

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)

        self.meta_data_changed_flg = False

        self.screen_width = GetSystemMetrics(0)
        self.screen_height = GetSystemMetrics(1)

        self.line_height = 20
        self.line_width = 100

        self.index_input_line_width = 30

        self.edge_format_input_line_width = 50

        self.activity_format_input_line_width = 100

        self.preview_label_height = 100
        self.preview_label_width = 100

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)

        self.meta_data = MetaData()

        self.model_thread = QThread(self)
        self.model_obj = Model()

        # ============================== STRINGS ==============================
        self.title_label_font_style_str = '<span style=\' font-size:12pt; font-weight:1000; color:#767D92;\' > {} </span>'
        self.sub_title_label_font_style_str = '<span style=\' font-size:10pt; font-weight:1000; color:#767D92;\' > {} </span>'
        self.info_label_font_style_str = '<span style=\' font-size:8pt; font-weight:700;\' > {} </span>'

        self.cb_style_str = 'QCheckBox {color: #FAEBD7;}'
        self.le_style_str = 'QLineEdit {background-color: #202124; color: #FAEBD7;}'
        self.ddl_style_str = 'QComboBox {background-color: #202124; color: #FAEBD7;}'
        self.preview_label_style_str = 'QLabel {background-color: #202124; color: #FAEBD7;}'
        self.status_bar_style_str = 'QStatusBar {background-color: #900500; color: #FAEBD7;}'
        self.lcd_style_str = 'QLCDNumber {background-color: #4B0082; color: #FAEBD7;}'
        self.main_background_style_str = 'QWidget {background-color: #323639;}'

        self.action_button_style_str = 'QPushButton {background-color: #353C51; color: #767D92;}'
        self.browse_button_style_str = 'QPushButton {background-color: #353C51; color: #767D92;}'
        self.save_button_style_str = 'QPushButton {background-color: #353C51; color: #767D92;}'
        self.reset_button_style_str = 'QPushButton {background-color: #353C51; color: #767D92;}'
        self.disabled_button_style_str = 'QPushButton {background-color: #696969; color: #FAEBD7;}'

        self.mu_str = "<span style=\" font-size:8pt; font-weight:700; color:white;\" >" + unicodedata.lookup("GREEK SMALL LETTER MU") + '</span>'
        self.rho_str = "<span style=\" font-size:8pt; font-weight:700; color:white;\" >" + unicodedata.lookup("GREEK SMALL LETTER RHO") + '</span>'
        self.epsilon_str = "<span style=\" font-size:8pt; font-weight:700; color:white;\" >" + unicodedata.lookup("GREEK SMALL LETTER EPSILON") + '</span>'
        self.sigma_str = "<span style=\" font-size:8pt; font-weight:700; color:white;\" >" + unicodedata.lookup("GREEK SMALL LETTER SIGMA") + '</span>'
        self.alpha_str = "<span style=\" font-size:8pt; font-weight:700; color:white;\" >" + unicodedata.lookup("GREEK SMALL LETTER ALPHA") + '</span>'

        self.plain_mu_str = unicodedata.lookup("GREEK SMALL LETTER MU")
        self.plain_sigma_str = unicodedata.lookup("GREEK SMALL LETTER SIGMA")
        self.plain_rho_str = unicodedata.lookup("GREEK SMALL LETTER RHO")
        self.plain_epsilon_str = unicodedata.lookup("GREEK SMALL LETTER EPSILON")
        self.plain_alpha_str = unicodedata.lookup("GREEK SMALL LETTER ALPHA")
        self.plain_beta_str = unicodedata.lookup("GREEK SMALL LETTER BETA")

        self.red_mu_str = "<span style=\" font-size:10pt; font-weight:700; color:#FF0000;\" >" + unicodedata.lookup("GREEK SMALL LETTER MU") + '</span>'
        self.red_sigma_str = "<span style=\" font-size:10pt; font-weight:700; color:#FF0000;\" >" + unicodedata.lookup("GREEK SMALL LETTER SIGMA") + '</span>'

        self.green_mu_str = "<span style=\" font-size:10pt; font-weight:700; color:#708238;\" >" + unicodedata.lookup("GREEK SMALL LETTER MU") + '</span>'
        self.green_sigma_str = "<span style=\" font-size:10pt; font-weight:700; color:#708238;\" >" + unicodedata.lookup("GREEK SMALL LETTER SIGMA") + '</span>'

        self.blue_mu_str = "<span style=\" font-size:10pt; font-weight:700; color:#0000FF;\" >" + unicodedata.lookup("GREEK SMALL LETTER MU") + '</span>'
        self.blue_sigma_str = "<span style=\" font-size:10pt; font-weight:700; color:#0000FF;\" >" + unicodedata.lookup("GREEK SMALL LETTER SIGMA") + '</span>'

        self.null_hypothesis_str = "<span style=\" font-size:10pt; font-weight:700; color:#FF0000;\" >" + u'H\u2080' + '</span>'
        self.alternative_hypothesis_str = "<span style=\" font-size:10pt; font-weight:700; color:#00FF00;\" >" + u'H\u2081' + '</span>'

        self.edge_list_file_path = ''
        self.save_path_str = ''
        # ============================== STRINGS ==============================

        # ============================== COMBO BOXES ==============================
        self.save_format_ddl = QComboBox()
        self.model_ddl = QComboBox()
        self.sort_edges_by_ddl = QComboBox()
        self.sort_edges_by_ddl.setStyleSheet(self.ddl_style_str)
        self.sort_activity_by_ddl = QComboBox()
        self.sort_activity_by_ddl.setStyleSheet(self.ddl_style_str)
        self.filter_activity_by_ddl = QComboBox()
        self.filter_activity_by_ddl.setStyleSheet(self.ddl_style_str)
        # ============================== COMBO BOXES ==============================

        # ============================== LCD NUMBERS ==============================
        self.accuracy_lcd = QLCDNumber()
        # ============================== LCD NUMBERS ==============================

        # ============================== LINE EDITS ==============================
        self.edge_file_path_le = QLineEdit()
        self.edge_file_path_le.setStyleSheet(self.le_style_str)
        self.edge_file_src_index_le = QLineEdit()
        self.edge_file_src_index_le.setStyleSheet(self.le_style_str)
        self.edge_file_dst_index_le = QLineEdit()
        self.edge_file_dst_index_le.setStyleSheet(self.le_style_str)
        self.activity_file_line_format_le = QLineEdit()
        self.activity_file_line_format_le.setStyleSheet(self.le_style_str)
        self.activity_file_src_index_le = QLineEdit()
        self.activity_file_src_index_le.setStyleSheet(self.le_style_str)
        self.activity_file_dst_index_le = QLineEdit()
        self.activity_file_dst_index_le.setStyleSheet(self.le_style_str)
        self.activity_file_type_index_le = QLineEdit()
        self.activity_file_type_index_le.setStyleSheet(self.le_style_str)
        self.activity_file_ts_index_le = QLineEdit()
        self.activity_file_ts_index_le.setStyleSheet(self.le_style_str)
        self.activity_file_ts_interval_le = QLineEdit()
        self.activity_file_ts_interval_le.setStyleSheet(self.le_style_str)
        self.activity_file_path_le = QLineEdit()
        self.activity_file_path_le.setStyleSheet(self.le_style_str)
        self.output_folder_path_le = QLineEdit()
        self.output_folder_path_le.setStyleSheet(self.le_style_str)
        # ============================== LINE EDITS ==============================

        # ============================== CHECK BOXES ==============================
        self.reduce_ts_cb = QCheckBox('Reduce Time Stamps')
        self.reduce_ts_cb.setStyleSheet(self.cb_style_str)
        self.anonymize_edge_list_cb = QCheckBox('Anonymize Edges')
        self.anonymize_edge_list_cb.setStyleSheet(self.cb_style_str)
        self.anonymize_activity_list_cb = QCheckBox('Anonymize Activity')
        self.anonymize_activity_list_cb.setStyleSheet(self.cb_style_str)
        # ============================== CHECK BOXES ==============================

        # ============================== PUSH BUTTONS ==============================
        self.browse_edge_file_btn = QPushButton('Browse')
        self.browse_activity_file_btn = QPushButton('Browse')
        self.browse_output_folder_btn = QPushButton('Browse')

        self.generate_edge_data_btn = QPushButton('Generate')
        self.generate_activity_data_btn = QPushButton('Generate')

        self.save_edge_data_btn = QPushButton('Save')
        self.save_activity_data_btn = QPushButton('Save')
        # ============================== PUSH BUTTONS ==============================

        # ============================== LAYOUTS ==============================
        self.background_widget = QWidget(self)
        self.background_widget.setFixedHeight(self.screen_height)
        self.background_widget.setFixedWidth(self.screen_width)
        self.background_widget.setStyleSheet(self.main_background_style_str)

        self.main_v_box = QVBoxLayout(self.background_widget)
        # ============================== LAYOUTS ==============================

        # ============================== LABELS ==============================
        self.edge_file_prev_label = QLabel()
        self.follower_to_followee_data_prev_label = QLabel()
        self.followee_to_follower_data_prev_label = QLabel()
        self.influence_dict_prev_label = QLabel()

        self.activity_file_prev_label = QLabel()
        self.activity_file_data_prev_label = QLabel()
        self.activity_file_ts_dict_prev_label = QLabel()
        # ============================== LABELS ==============================

        # ============================== ELSE ==============================
        self.edge_file_parsing_progress_bar = QProgressBar()
        self.edge_file_fr_2_fe_progress_bar = QProgressBar()
        self.edge_file_fe_2_fr_progress_bar = QProgressBar()
        self.edge_file_inf_progress_bar = QProgressBar()

        self.activity_file_progress_bar = QProgressBar()
        self.activity_file_data_ext_progress_bar = QProgressBar()
        self.activity_ts_dict_progress_bar = QProgressBar()

        self.status_bar = QStatusBar()
        self.status_bar.setStyleSheet(self.status_bar_style_str)
        # ============================== ELSE ==============================
        self.init_ui()
        self.show()

# =================================================================== INIT FUNCTIONS ===================================================================
    def init_ui(self):
        self.init_threads()
        self.init_signals()
        self.init_layouts()
        self.init_buttons()
        self.init_progress_bars()
        self.init_labels()
        self.init_ddl()
        self.init_check_boxes()
        self.init_lcd()
        self.init_plot()
        self.pack()

    def init_threads(self):
        self.model_thread.start()
        self.model_obj.moveToThread(self.model_thread)

    def init_signals(self):
        # self.model_obj.model_start_signal.connect(self.edge_file_progress_bar.show)
        self.model_obj.model_start_signal.connect(partial(self.generate_edge_data_btn.setEnabled, False))
        self.model_obj.model_start_signal.connect(partial(self.save_edge_data_btn.setEnabled, False))
        # self.model_obj.model_start_signal.connect(partial(self.browse_save_path_btn.setEnabled, False))
        # self.model_obj.model_start_signal.connect(partial(self.browse_path_btn.setEnabled, False))
        # self.model_obj.model_start_signal.connect(partial(self.plot_centralities_rb.setEnabled, False))
        # self.path_tracer_obj.trace_start_signal.connect(partial(self.plot_network_sample_rb.setEnabled, False))
        # self.path_tracer_obj.trace_start_signal.connect(partial(self.plot_path_distribution_rb.setChecked, True))

        self.model_obj.model_end_signal.connect(partial(self.populate_ddl))
        self.model_obj.model_end_signal.connect(self.edge_file_parsing_progress_bar.hide)
        self.model_obj.model_end_signal.connect(partial(self.generate_edge_data_btn.setEnabled, True))
        self.model_obj.model_end_signal.connect(partial(self.save_edge_data_btn.setEnabled, True))
        # self.model_obj.model_end_signal.connect(partial(self.browse_path_btn.setEnabled, True))
        # self.model_obj.model_end_signal.connect(partial(self.browse_save_path_btn.setEnabled, True))
        # self.path_tracer_obj.trace_end_signal.connect(partial(self.plot_network_sample_rb.setEnabled, True))
        # self.model_obj.model_end_signal.connect(partial(self.plot_centralities_rb.setEnabled, True))
        self.model_obj.model_end_signal.connect(partial(self.edge_file_parsing_progress_bar.setValue, 100))
        # self.model_obj.model_end_signal.connect(partial(self.calculate_centralities))

        self.model_obj.in_model_signal.connect(self.update_gui)

        self.model_obj.data_load_start_signal.connect(self.data_load_status_update)
        self.model_obj.data_load_end_signal.connect(self.data_load_status_update)

        self.model_obj.error_signal.connect(self.show_status_error)

    def init_layouts(self):
        self.setLayout(self.main_v_box)
        self.status_bar.showMessage('Welcome to Net Data Generator ver. 0.1')

    def init_buttons(self):

        self.browse_output_folder_btn.setStyleSheet(self.browse_button_style_str)
        self.browse_output_folder_btn.setFixedHeight(self.line_height)

        self.browse_edge_file_btn.setStyleSheet(self.browse_button_style_str)
        self.browse_edge_file_btn.setFixedHeight(self.line_height)

        self.browse_activity_file_btn.setStyleSheet(self.browse_button_style_str)
        self.browse_activity_file_btn.setFixedHeight(self.line_height)

        self.generate_edge_data_btn.setStyleSheet(self.action_button_style_str)
        self.generate_activity_data_btn.setStyleSheet(self.action_button_style_str)

        self.save_edge_data_btn.setStyleSheet(self.save_button_style_str)
        self.save_edge_data_btn.clicked.connect(self.on_btn_click)

        self.save_activity_data_btn.setStyleSheet(self.save_button_style_str)
        self.save_activity_data_btn.clicked.connect(self.on_btn_click)

        # self.browse_save_path_btn.setStyleSheet(self.general_button_style_str)
        # self.browse_save_path_btn.clicked.connect(self.on_btn_click)

    def init_progress_bars(self):
        self.edge_file_parsing_progress_bar.hide()
        self.edge_file_fr_2_fe_progress_bar.hide()
        self.edge_file_fe_2_fr_progress_bar.hide()
        self.edge_file_inf_progress_bar.hide()

        self.activity_file_progress_bar.hide()
        self.activity_file_data_ext_progress_bar.hide()
        self.activity_ts_dict_progress_bar.hide()

    def init_check_boxes(self):
        self.reduce_ts_cb.setChecked(True)

    def init_labels(self):
        pass

    def init_ddl(self):
        self.save_format_ddl.addItem('*.pickle')
        self.save_format_ddl.addItem('*.csv')
        self.save_format_ddl.addItem('*.tsv')

        self.sort_edges_by_ddl.addItem('Source')
        self.sort_edges_by_ddl.addItem('Destination')

        self.sort_activity_by_ddl.addItem('Time Stamp')
        self.sort_activity_by_ddl.addItem('Source')
        self.sort_activity_by_ddl.addItem('Destination')
        self.sort_activity_by_ddl.addItem('Type')

    def init_lcd(self):
        self.accuracy_lcd.setStyleSheet(self.lcd_style_str)

    def init_plot(self):

        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.canvas.updateGeometry()

        self.line_plot(title='Prediction Error', x_label='Prediction #', y_label='Accuracy %', data_list=[])

# /////////////////////////////////////////////////////////////////// INIT FUNCTIONS ///////////////////////////////////////////////////////////////////

# =================================================================== ON ACTION FUNCTIONS ===================================================================

    def on_ddl_index_change(self):
        pass

    def on_btn_click(self):
        btn_id = self.sender()

        if btn_id == self.save_edge_data_btn:
            if os.path.exists(self.edge_list_file_path):
                self.source_node_limit = self.check_int_input(self.number_of_source_node_limit_ddl, 'The source node limit must be an integer or \"All\". Default value was set (All).')
                self.traced_edge_limit = self.check_int_input(self.number_of_paths_limit_ddl, 'The path limit must be an integer or \"All\". Default value was set (All).')

                if self.iterative_save_cb.isChecked():
                    if not os.path.exists(self.save_path_str):
                        QMessageBox.critical(self, 'Save Path Error', 'In order to use the iterative save option, a valid save folder path must be provided!')
                        self.save_path_str = self.browse_save_folder_path()
                        self.save_path_le.setText(self.save_path_str)
                        return

                edge_file_ext = get_file_extension(self.edge_list_file_path)
                if edge_file_ext == 'csv' or edge_file_ext == 'tsv':
                    if not os.path.exists(self.save_path_str):
                        save_data_as_pickle = QMessageBox.question(self, 'Save data for future use', 'Would you like to save the extracted data as .pickle file for faster future loading?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
                        if save_data_as_pickle == QMessageBox.Yes:
                            self.save_path_str = self.browse_save_folder_path()

                QTimer.singleShot(0, partial(self.model_obj.apply,
                                             edge_list_file_path=self.edge_list_file_path,
                                             source_node_limit=self.source_node_limit,
                                             edge_trace_limit=self.traced_edge_limit,
                                             save_path=self.save_path_str,
                                             save_file_type=get_file_extension(self.save_format_ddl.currentText()),
                                             iterative_save=self.iterative_save_cb.isChecked()
                                             )
                                  )
            else:
                QMessageBox.critical(self, 'File not found error', 'The path to the .pickled edge list is not valid!')
        elif btn_id == self.browse_path_btn:
            self.edge_list_file_path = self.browse_file('*.pickle;;*.tsv;;*.csv')
            self.edge_list_path_le.setText(self.edge_list_file_path)
        elif btn_id == self.browse_save_path_btn:
            self.save_path_str = self.browse_save_folder_path()
            self.save_path_le.setText(self.save_path_str)
        elif btn_id == self.save_edge_data_btn:
            if os.path.exists(self.save_path_str):
                try:
                    self.save_results(self.save_path_str, get_file_extension(self.save_format_ddl.currentText()))
                except:
                    self.status_bar.showMessage('Something went wrong when saving the data!')
            else:
                QMessageBox.critical(self, 'Save folder is not defined', 'The path to the save folder is not set!')

    def on_rb_change(self):
        rb_id = self.sender()
# /////////////////////////////////////////////////////////////////// ON ACTION FUNCTIONS ///////////////////////////////////////////////////////////////////

# =================================================================== GUI UPDATE FUNCTIONS ===================================================================
    def update_gui(self, total_number_of_edges, current_number_of_edges, current_source_node, path_count, path_length_distribution, path_length_histogram, path_edges, path_length_list, source_nodes_list):
        pass

    def calculate_centralities(self):
        pass

    def data_load_status_update(self, stage, file_extension, file_name=''):
        if stage == 'start':
            self.status_bar.showMessage('The data from .{} file is currently being loaded and converted.'.format(file_extension))
        elif stage == 'end' and os.path.exists(self.save_path_str):
            self.status_bar.showMessage('The data from .{} file is was loaded successfully, and saved at {} as {}.'.format(file_extension, self.save_path_str, file_name))
        elif stage == 'end':
            self.status_bar.showMessage('The data from .{} file is was loaded successfully.'.format(file_extension))

    def show_status_error(self, error_message):
        self.status_bar.showMessage(error_message)
# /////////////////////////////////////////////////////////////////// GUI UPDATE FUNCTIONS ///////////////////////////////////////////////////////////////////

# =================================================================== GENERAL FUNCTIONS ===================================================================
    def get_centrality_plot_data(self):
        pass

    def save_results(self, save_path, file_type):
        print('len(self.meta_data.path_list) = {}, save_path = {}, file_type = {}'.format(len(self.meta_data.path_list), save_path, file_type))
        # print('path_list = {}'.format(self.meta_data.path_list))
        # print('path_length_list = {}'.format(self.meta_data.path_length_list))
        if len(self.meta_data.path_list) > 0:
            if file_type == 'pickle':
                try:
                    with open(os.path.join(save_path, 'path_list.pickle'), 'wb') as pickle_out:
                        pkl.dump(self.meta_data.path_list, pickle_out)

                    with open(os.path.join(save_path, 'path_length_list.pickle'), 'wb') as pickle_out:
                        pkl.dump(self.meta_data.path_length_list, pickle_out)

                    with open(os.path.join(save_path, 'path_length_distribution_list.pickle'), 'wb') as pickle_out:
                        pkl.dump(self.meta_data.path_length_distribution, pickle_out)

                    with open(os.path.join(save_path, 'path_length_histogram_list.pickle'), 'wb') as pickle_out:
                        pkl.dump(self.meta_data.path_length_histogram, pickle_out)
                except:
                    self.status_bar.showMessage('Error on saving data as .pickle file!')
                    QMessageBox.critical(self, '.pickle save error', 'The data could not be saved as a .pickle file!')

            elif file_type == 'csv':
                try:
                    path_list_df = pd.DataFrame(self.meta_data.path_list)
                    path_length_list_df = pd.DataFrame(self.meta_data.path_length_list)
                    path_length_dist_df = pd.DataFrame(self.meta_data.path_length_distribution)
                    path_length_hist_df = pd.DataFrame(self.meta_data.path_length_histogram)

                    print('(csv) df path : {}'.format(path_list_df.head()))
                    print('(csv) df path length : {}'.format(path_length_list_df.head()))

                    path_list_df.to_csv(os.path.join(save_path, 'path_list.csv'))
                    path_length_list_df.to_csv(os.path.join(save_path, 'path_length_list.csv'))
                    path_length_dist_df.to_csv(os.path.join(save_path, 'path_length_distribution_list.csv'))
                    path_length_hist_df.to_csv(os.path.join(save_path, 'path_length_histogram_list.csv'))
                except:
                    self.status_bar.showMessage('Error on saving data as .pickle file!')
                    QMessageBox.critical(self, '.csv save error', 'The data could not be saved as a .csv file!')

            elif file_type == 'tsv':
                try:
                    path_list_df = pd.DataFrame(self.meta_data.path_list)
                    path_length_list_df = pd.DataFrame(self.meta_data.path_length_list)
                    path_length_dist_df = pd.DataFrame(self.meta_data.path_length_distribution)
                    path_length_hist_df = pd.DataFrame(self.meta_data.path_length_histogram)

                    print('(tsv) df path : {}'.format(path_list_df.head()))
                    print('(tsv) df path length : {}'.format(path_length_list_df.head()))

                    path_list_df.to_csv(os.path.join(save_path, 'path_list.tsv'), sep='\t')
                    path_length_list_df.to_csv(os.path.join(save_path, 'path_length_list.tsv'), sep='\t')
                    path_length_dist_df.to_csv(os.path.join(save_path, 'path_length_distribution_list.tsv'), sep='\t')
                    path_length_hist_df.to_csv(os.path.join(save_path, 'path_length_histogram_list.tsv'), sep='\t')
                except:
                    self.status_bar.showMessage('Error on saving data as .tsv file!')
                    QMessageBox.critical(self, '.tsv save error', 'The data could not be saved as a .tsv file!')
        else:
            QMessageBox.critical(self, 'Empty path list error', 'The is no data to save!')

    def check_int_input(self, ddl, error_message):
        int_value = -1
        try:
            int_value = int(ddl.currentText())
        except:
            if ddl.currentText() != 'All':
                QMessageBox.critical(self, 'Value Error', error_message)
        return int_value

    def browse_file(self, file_ext):
        file_path = QFileDialog.getOpenFileName(self, '.pickle files', os.getenv('HOME'), file_ext)[0]
        if os.path.exists(file_path):
            self.status_bar.showMessage('The chosen file is {}.'.format(file_path))
        else:
            self.status_bar.showMessage('No file were chosen.')
        return file_path

    def browse_save_folder_path(self):
        folder_path = QFileDialog.getExistingDirectory(self, 'Chose a save folder path', os.getenv('HOME'))
        if os.path.exists(folder_path):
            self.status_bar.showMessage('The chosen save folder is {}.'.format(folder_path))
        else:
            self.status_bar.showMessage('No save folder were chosen.')
        return folder_path

    def populate_ddl(self):
        pass

# /////////////////////////////////////////////////////////////////// GENERAL FUNCTIONS ///////////////////////////////////////////////////////////////////

# =================================================================== PLOTTING FUNCTIONS ===================================================================
    def line_plot(self, title, x_label, y_label, data_list):
        self.figure.clf()
        if data_list is not None and len(data_list) > 0:
            x = range(1, len(data_list) + 1)
            plt.plot(x, data_list, 'o:', markersize=5)

        plt.title(title)
        plt.xlabel(x_label)
        plt.ylabel(y_label)

        self.canvas.draw()

    def bar_plot(self, title, x_label, y_label, data_list):
        self.figure.clf()
        if data_list is not None and len(data_list) > 0:
            x = range(1, len(data_list) + 1)
            plt.bar(x, data_list, 0.35)

        plt.title(title)
        plt.xlabel(x_label)
        plt.ylabel(y_label)

        self.canvas.draw()

    def multi_bar_plot(self, title, x_label, y_label, tuple_data_list, legend):
        self.figure.clf()
        x = list(range(1, 11))
        for tuple_list in tuple_data_list:
            x = [tuple_data[0] for tuple_data in tuple_list]
            print(x)
            y = [tuple_data[1] for tuple_data in tuple_list]
            print(y)
            if y is not None and len(y) > 0:
                plt.bar(x, y, 5)

        plt.legend(legend)
        plt.xticks(x)
        plt.title(title)
        plt.xlabel(x_label)
        plt.ylabel(y_label)

        self.canvas.draw()

    def network_plot(self, title, edge_list):
        self.figure.clf()

        g = nx.Graph(edge_list)
        nx.draw_networkx(g)

        plt.title(title)
        self.canvas.draw()
# ///////////////////////////////////////////////////////////////////  PLOTTING FUNCTIONS ///////////////////////////////////////////////////////////////////

# =================================================================== PACKING FUNCTION ===================================================================
    def pack(self):
        # =========================================================== MAIN CONF ===========================================================
        top_v_cont = QVBoxLayout()
        bottom_v_cont = QVBoxLayout()

        edge_conf_v_cont = QVBoxLayout()
        activity_conf_v_cont = QVBoxLayout()

        output_path_h_cont = QHBoxLayout()
        output_path_h_cont.addWidget(QLabel(self.title_label_font_style_str.format('Output Folder Path : ')))
        output_path_h_cont.addWidget(self.output_folder_path_le)
        output_path_h_cont.addWidget(self.browse_output_folder_btn)
        top_v_cont.addLayout(output_path_h_cont)

        edge_conf_v_cont.addWidget(QLabel(self.title_label_font_style_str.format('Network Structure Configuration Box')))
        edge_conf_h_cont = QHBoxLayout()
        edge_conf_v_cont.addLayout(edge_conf_h_cont)

        edge_conf_col_1_v_cont = QVBoxLayout()
        edge_conf_col_2_v_cont = QVBoxLayout()
        # edge_conf_col_3_v_cont = QVBoxLayout()

        edge_conf_h_cont.addLayout(edge_conf_col_1_v_cont)
        # edge_conf_h_cont.addLayout(edge_conf_col_2_v_cont)
        # edge_conf_h_cont.addLayout(edge_conf_col_3_v_cont)

        activity_conf_v_cont.addWidget(QLabel(self.title_label_font_style_str.format('Network Activity Configuration Box')))
        activity_conf_h_cont = QHBoxLayout()
        activity_conf_col_1_v_cont = QVBoxLayout()
        # activity_conf_col_2_v_cont = QVBoxLayout()
        # activity_conf_col_3_v_cont = QVBoxLayout()
        activity_conf_h_cont.addLayout(activity_conf_col_1_v_cont)
        # activity_conf_h_cont.addLayout(activity_conf_col_2_v_cont)
        # activity_conf_h_cont.addLayout(activity_conf_col_3_v_cont)
        activity_conf_v_cont.addLayout(activity_conf_h_cont)

        top_v_cont.addLayout(edge_conf_v_cont)
        top_v_cont.addLayout(activity_conf_v_cont)
        top_v_cont.addStretch()

        self.main_v_box.addLayout(top_v_cont)
        self.main_v_box.addLayout(bottom_v_cont)
        self.main_v_box.addWidget(self.edge_file_parsing_progress_bar)
        self.main_v_box.addWidget(self.status_bar)
        # =========================================================== MAIN CONF ===========================================================
        # =========================================================== EDGE FILE INPUT BOX ===========================================================
        edge_file_path_h_cont = QHBoxLayout()
        edge_file_input_info_label = QLabel(self.sub_title_label_font_style_str.format('Edge file (.tsv/.csv/.pickle) path : '))
        edge_file_path_h_cont.addWidget(edge_file_input_info_label)
        edge_file_path_h_cont.addWidget(self.edge_file_path_le)
        edge_file_path_h_cont.addWidget(self.browse_edge_file_btn)

        edge_conf_col_1_v_cont.addLayout(edge_file_path_h_cont)

        edge_file_format_and_conf_h_cont = QHBoxLayout()
        edge_file_src_label = QLabel(self.sub_title_label_font_style_str.format('Source index : '))
        edge_file_format_and_conf_h_cont.addWidget(edge_file_src_label)
        self.edge_file_src_index_le.setFixedWidth(self.index_input_line_width)
        edge_file_format_and_conf_h_cont.addWidget(self.edge_file_src_index_le)

        edge_file_dst_label = QLabel(self.sub_title_label_font_style_str.format('Destination index : '))
        edge_file_format_and_conf_h_cont.addWidget(edge_file_dst_label)
        self.edge_file_dst_index_le.setFixedWidth(self.index_input_line_width)
        edge_file_format_and_conf_h_cont.addWidget(self.edge_file_dst_index_le)

        edge_file_format_and_conf_h_cont.addStretch()

        edge_file_sort_info_label = QLabel(self.sub_title_label_font_style_str.format('Sort edge data by : '))
        edge_file_format_and_conf_h_cont.addWidget(edge_file_sort_info_label)
        edge_file_format_and_conf_h_cont.addWidget(self.sort_edges_by_ddl)
        edge_file_format_and_conf_h_cont.addWidget(self.anonymize_edge_list_cb)

        edge_conf_col_1_v_cont.addLayout(edge_file_format_and_conf_h_cont)

        edge_file_prev_h_cont = QHBoxLayout()
        edge_file_prev_v_cont = QVBoxLayout()
        follower_to_followee_data_prev_v_cont = QVBoxLayout()
        followee_to_follower_data_prev_v_cont = QVBoxLayout()
        influence_dictionary_prev_v_cont = QVBoxLayout()

        edge_file_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Edge file')))
        edge_file_prev_v_cont.addWidget(self.edge_file_prev_label)
        edge_file_prev_v_cont.addWidget(self.edge_file_parsing_progress_bar)
        self.edge_file_prev_label.setText('Edge file preview here...\n...\n...\n...')
        self.edge_file_prev_label.setStyleSheet(self.preview_label_style_str)

        follower_to_followee_data_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Follower -> Followee dictionary')))
        follower_to_followee_data_prev_v_cont.addWidget(self.follower_to_followee_data_prev_label)
        follower_to_followee_data_prev_v_cont.addWidget(self.edge_file_fr_2_fe_progress_bar)
        self.follower_to_followee_data_prev_label.setText('Edge file data preview here...\n...\n...\n...')
        self.follower_to_followee_data_prev_label.setStyleSheet(self.preview_label_style_str)

        followee_to_follower_data_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Followee -> Follower dictionary')))
        followee_to_follower_data_prev_v_cont.addWidget(self.followee_to_follower_data_prev_label)
        followee_to_follower_data_prev_v_cont.addWidget(self.edge_file_fe_2_fr_progress_bar)
        self.followee_to_follower_data_prev_label.setText('Edge file data preview here...\n...\n...\n...')
        self.followee_to_follower_data_prev_label.setStyleSheet(self.preview_label_style_str)

        influence_dictionary_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Influence dictionary')))
        influence_dictionary_prev_v_cont.addWidget(self.influence_dict_prev_label)
        influence_dictionary_prev_v_cont.addWidget(self.edge_file_inf_progress_bar)
        self.influence_dict_prev_label.setText('Edge file data preview here...\n...\n...\n...')
        self.influence_dict_prev_label.setStyleSheet(self.preview_label_style_str)

        edge_file_prev_h_cont.addLayout(edge_file_prev_v_cont)
        edge_file_prev_h_cont.addLayout(follower_to_followee_data_prev_v_cont)
        edge_file_prev_h_cont.addLayout(followee_to_follower_data_prev_v_cont)
        edge_file_prev_h_cont.addLayout(influence_dictionary_prev_v_cont)

        edge_conf_col_1_v_cont.addLayout(edge_file_prev_h_cont)

        edge_file_button_h_cont = QHBoxLayout()
        edge_file_button_h_cont.addWidget(self.generate_edge_data_btn)
        edge_file_button_h_cont.addWidget(self.save_edge_data_btn)
        edge_conf_col_1_v_cont.addLayout(edge_file_button_h_cont)

        edge_conf_col_1_v_cont.addStretch()
        # =========================================================== EDGE FILE INPUT BOX ===========================================================
        # =========================================================== ACTIVITY FILE INPUT BOX ===========================================================
        activity_file_path_h_cont = QHBoxLayout()
        activity_file_input_info_label = QLabel(self.sub_title_label_font_style_str.format('Activity file (.tsv/.csv/.pickle) path : '))
        activity_file_path_h_cont.addWidget(activity_file_input_info_label)
        activity_file_path_h_cont.addWidget(self.activity_file_path_le)
        activity_file_path_h_cont.addWidget(self.browse_activity_file_btn)

        activity_conf_col_1_v_cont.addLayout(activity_file_path_h_cont)

        activity_file_line_format_v_cont = QVBoxLayout()
        activity_file_line_format_h_cont = QHBoxLayout()
        activity_file_line_format_info_label = QLabel(self.sub_title_label_font_style_str.format('Reformat lines ([int, int, int, int]) : '))
        activity_file_line_format_h_cont.addWidget(activity_file_line_format_info_label)
        self.activity_file_line_format_le.setFixedWidth(self.activity_format_input_line_width)
        activity_file_line_format_h_cont.addWidget(self.activity_file_line_format_le)

        activity_file_line_format_h_cont.addStretch()

        activity_file_sort_info_label = QLabel(self.sub_title_label_font_style_str.format('Sort activity data by : '))
        activity_file_line_format_h_cont.addWidget(activity_file_sort_info_label)
        activity_file_line_format_h_cont.addWidget(self.sort_activity_by_ddl)
        activity_file_line_format_h_cont.addWidget(self.anonymize_activity_list_cb)
        activity_file_line_format_h_cont.addWidget(self.reduce_ts_cb)

        activity_file_line_format_v_cont.addLayout(activity_file_line_format_h_cont)

        activity_file_data_index_and_conf_h_cont = QHBoxLayout()

        activity_file_src_index_label = QLabel(self.sub_title_label_font_style_str.format('Source index : '))
        activity_file_data_index_and_conf_h_cont.addWidget(activity_file_src_index_label)
        self.activity_file_src_index_le.setFixedWidth(self.index_input_line_width)
        activity_file_data_index_and_conf_h_cont.addWidget(self.activity_file_src_index_le)

        activity_file_dst_index_label = QLabel(self.sub_title_label_font_style_str.format('Destination index : '))
        activity_file_data_index_and_conf_h_cont.addWidget(activity_file_dst_index_label)
        self.activity_file_dst_index_le.setFixedWidth(self.index_input_line_width)
        activity_file_data_index_and_conf_h_cont.addWidget(self.activity_file_dst_index_le)

        activity_file_type_index_label = QLabel(self.sub_title_label_font_style_str.format('Type index : '))
        activity_file_data_index_and_conf_h_cont.addWidget(activity_file_type_index_label)
        self.activity_file_type_index_le.setFixedWidth(self.index_input_line_width)
        activity_file_data_index_and_conf_h_cont.addWidget(self.activity_file_type_index_le)

        activity_file_ts_index_label = QLabel(self.sub_title_label_font_style_str.format('TS index : '))
        activity_file_data_index_and_conf_h_cont.addWidget(activity_file_ts_index_label)
        self.activity_file_ts_index_le.setFixedWidth(self.index_input_line_width)
        activity_file_data_index_and_conf_h_cont.addWidget(self.activity_file_ts_index_le)

        activity_file_ts_interval_label = QLabel(self.sub_title_label_font_style_str.format('Time stamp interval : '))
        activity_file_data_index_and_conf_h_cont.addWidget(activity_file_ts_interval_label)
        activity_file_data_index_and_conf_h_cont.addWidget(self.activity_file_ts_interval_le)

        activity_file_line_format_v_cont.addLayout(activity_file_data_index_and_conf_h_cont)

        activity_conf_col_1_v_cont.addLayout(activity_file_line_format_v_cont)

        activity_file_prev_h_cont = QHBoxLayout()
        activity_file_prev_v_cont = QVBoxLayout()
        activity_file_data_prev_v_cont = QVBoxLayout()
        activity_file_ts_dict_prev_h_cont = QHBoxLayout()
        activity_file_ts_dict_prev_v_cont = QVBoxLayout()

        activity_file_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Activity file')))
        activity_file_prev_v_cont.addWidget(self.activity_file_prev_label)
        activity_file_prev_v_cont.addWidget(self.activity_file_progress_bar)
        self.activity_file_prev_label.setText('Activity file preview here...\n...\n...\n...')
        self.activity_file_prev_label.setStyleSheet(self.preview_label_style_str)

        activity_file_data_prev_v_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Activity data format')))
        activity_file_data_prev_v_cont.addWidget(self.activity_file_data_prev_label)
        activity_file_data_prev_v_cont.addWidget(self.activity_file_data_ext_progress_bar)
        self.activity_file_data_prev_label.setText('Activity file data preview here...\n...\n...\n...')
        self.activity_file_data_prev_label.setStyleSheet(self.preview_label_style_str)

        activity_file_ts_dict_prev_h_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('TS activity dictionary |')))
        activity_file_ts_dict_prev_h_cont.addWidget(QLabel(self.sub_title_label_font_style_str.format('Filter by : ')))
        activity_file_ts_dict_prev_h_cont.addWidget(self.filter_activity_by_ddl)
        activity_file_ts_dict_prev_v_cont.addLayout(activity_file_ts_dict_prev_h_cont)
        activity_file_ts_dict_prev_v_cont.addWidget(self.activity_file_ts_dict_prev_label)
        activity_file_ts_dict_prev_v_cont.addWidget(self.activity_ts_dict_progress_bar)
        self.activity_file_ts_dict_prev_label.setText('Activity file data preview here...\n...\n...\n...')
        self.activity_file_ts_dict_prev_label.setStyleSheet(self.preview_label_style_str)

        activity_file_prev_h_cont.addLayout(activity_file_prev_v_cont)
        activity_file_prev_h_cont.addLayout(activity_file_data_prev_v_cont)
        activity_file_prev_h_cont.addLayout(activity_file_ts_dict_prev_v_cont)

        activity_file_button_h_cont = QHBoxLayout()
        activity_file_button_h_cont.addWidget(self.generate_activity_data_btn)
        activity_file_button_h_cont.addWidget(self.save_activity_data_btn)

        edge_conf_col_1_v_cont.addLayout(edge_file_prev_h_cont)
        activity_conf_col_1_v_cont.addLayout(activity_file_line_format_v_cont)
        activity_conf_col_1_v_cont.addLayout(activity_file_prev_h_cont)
        activity_conf_col_1_v_cont.addLayout(activity_file_button_h_cont)

        # =========================================================== ACTIVITY FILE INPUT BOX ===========================================================

 

  • Basic app with PyQt5
    (currently viewing)