<reponame>guglielmosanchini/ClustVizGUI<gh_stars>0
from PyQt5.QtWidgets import (
    QPushButton,
    QLabel,
    QComboBox,
    QGridLayout,
    QGroupBox,
    QLineEdit,
    QPlainTextEdit,
    QWidget,
    QCheckBox,
    QMessageBox,
    QVBoxLayout,
    QMainWindow,
)
from PyQt5.QtCore import Qt, QLocale, QCoreApplication
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QPixmap
from imageio import mimsave, imread
import os
from shutil import rmtree
import numpy as np

from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure

from sklearn.datasets import make_blobs

from GUI_classes.utils_gui import LabeledSlider

from base import appctxt

# todo: PARAMETERS REGULARIZATION mettere a posto


class StartingGui(QWidget):
    def __init__(
        self,
        name,
        twinx,
        first_plot,
        second_plot,
        function,
        stretch_plot=False,
        extract=False,
    ):
        super().__init__()

        self.name = name
        self.function = function

        self.setWindowTitle(self.name)
        self.setGeometry(100, 100, 1290, 850)

        # otherwise Validators do not work properly
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))

        # upper plot
        if first_plot is True:
            self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax1 = self.canvas_up.figure.subplots()
            self.ax1.set_xticks([], [])
            self.ax1.set_yticks([], [])
            self.ax1.set_title(self.name + " procedure")
            if twinx is True:
                self.ax1_t = self.ax1.twinx()
                self.ax1_t.set_xticks([], [])
                self.ax1_t.set_yticks([], [])

        # lower plot
        if second_plot is True:
            self.canvas_down = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax = self.canvas_down.figure.subplots()
            self.ax.set_xticks([], [])
            self.ax.set_yticks([], [])
            if self.name == "OPTICS":
                self.ax.set_title(self.name + " Reachability Plot")
                self.ax.set_ylabel("reachability distance")
            if twinx is True:
                self.ax_t = self.ax.twinx()
                self.ax_t.set_xticks([], [])
                self.ax_t.set_yticks([], [])

        # influence plot for DENCLUE
        if self.name == "DENCLUE":
            self.canvas_infl = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax_infl = self.canvas_infl.figure.subplots()
            self.ax_infl.set_xticks([], [])
            self.ax_infl.set_yticks([], [])

        # parameters initialization
        self.parameter_initialization()

        # this is used to account for previously created folders in Images to set the self.ind_run correctly
        # fold_dir = appctxt.get_resource("Images/") + '/' + ''
        fold_dir = appctxt.get_resource("Images/")
        folders = [el for el in os.listdir(fold_dir) if el.startswith(self.name + "_")]
        folders.sort()
        if len(folders) == 0:
            self.ind_run = 0
        else:
            self.ind_run = int(folders[-1][(len(self.name) + 1) :]) + 1

        # grid where the two pictures, the log and the button box are inserted (row,column)
        self.gridlayout = QGridLayout(self)
        if (first_plot is True) and self.name != "CHAMELEON":
            if stretch_plot is False:
                self.gridlayout.addWidget(self.canvas_up, 0, 1)
            else:
                self.gridlayout.addWidget(self.canvas_up, 0, 1, 2, 1)

        if second_plot is True:
            self.gridlayout.addWidget(self.canvas_down, 1, 1)

        # START BUTTON
        self.button_run = QPushButton("START", self)
        self.button_run.clicked.connect(self.function)
        self.button_run.setToolTip("Perform clustering.")

        # SLIDER
        self.label_slider = QLabel(self)
        self.label_slider.setText("delay:")
        self.label_slider.setToolTip(
            "Delay each step of the algorithm for the desidered number of seconds."
        )

        self.slider = LabeledSlider(minimum=0, maximum=3, interval=1, single_step=0.5)
        self.slider.sl.valueChanged.connect(self.changedValue)
        self.slider.setFixedHeight(50)

        # EXTRACT BUTTON
        if extract is True:
            self.button_extract = QPushButton("EXTRACT", self)
            self.button_extract.clicked.connect(lambda: self.start_EXTRACT_OPTICS())
            self.button_extract.setEnabled(False)
            self.button_extract.setToolTip(
                "Extract clusters from OPTICS reachability plot in a"
                " DBSCAN way using eps_extr."
            )

        # CHECKBOX for saving images
        self.checkbox_saveimg = QCheckBox("save plots")
        self.checkbox_saveimg.setToolTip(
            "Check it to save all the plots generated by the algorithm. They are"
            " saved in the Images folder."
        )
        self.checkbox_saveimg.stateChanged.connect(self.checkBoxChangedAction)

        # CHECKBOX for generating GIF
        self.checkbox_gif = QCheckBox("make GIF")
        self.checkbox_gif.setToolTip(
            "Check it to build a GIF from the plots generated by the algorithm. GIF are not"
            " produced when new Extractions are performed, \nthey are only produced when the"
            " main clustering procedure is executed. The GIF is saved in the same folder of"
            " the plots it is composed of."
        )
        self.checkbox_gif.stateChanged.connect(self.GIFChangedAction)
        self.checkbox_gif.setEnabled(False)

        # BUTTON for removing generated pics and gifs
        self.button_delete_pics = QPushButton("DELETE PICs && GIFs", self)
        self.button_delete_pics.clicked.connect(self.delete_pics)
        self.button_delete_pics.setEnabled(True)
        self.button_delete_pics.setToolTip(
            "Delete all pictures and GIFs generated until now in the folder Images."
            " To avoid deleting specific files, just move them out of the folder"
            " Images."
        )

        # n_points LABEL
        self.label_np = QLabel(self)
        self.label_np.setText("n_points:")
        self.label_np.setToolTip(
            "Number of points of the dataset. It can lie between 5 and 200."
        )

        self.line_edit_np = QLineEdit(self)
        self.line_edit_np.setText(str(self.n_points))

        self.n_points_validator = QIntValidator(5, 200, self)
        self.line_edit_np.setValidator(self.n_points_validator)

        # dataset LABEL
        self.label_ds = QLabel(self)
        self.label_ds.setText("dataset:")
        self.label_ds.setToolTip(
            "Choose among four sklearn generated datasets to perform clustering."
        )

        # COMBOBOX of datasets
        self.combobox = QComboBox(self)
        self.combobox.addItem("blobs")
        self.combobox.addItem("moons")
        self.combobox.addItem("scatter")
        self.combobox.addItem("circle")

        # labels initialization
        self.label_initialization()

        # LOG
        self.log_initialization()

        # buttons in GROUPBOX (upper left corner)
        self.buttons_groupbox_initialization()

        self.show()

    def parameter_initialization(self):

        self.n_points = 30
        self.X = make_blobs(
            n_samples=self.n_points,
            centers=4,
            n_features=2,
            cluster_std=1.8,
            random_state=42,
        )[0]
        self.delay = 0
        self.ind_extr_fig = 0
        self.param_check = True
        self.save_plots = False
        self.first_run_occurred = False
        self.make_gif = False

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):
            self.eps = 2
            self.mp = 3
            self.eps_extr = 1
            self.ClustDist = {}
            self.ClustDict = {}
            self.CoreDist = {}

        elif self.name == "AGGLOMERATIVE":
            self.n_clust = 3
            self.linkage = "single"

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.n_clust = 2
            self.n_repr = 3
            self.alpha_cure = 0.5

            if self.name == "LARGE CURE":
                self.p_cure = 2
                self.q_cure = 2

        elif self.name == "CLARA":
            self.n_medoids = 3
            self.dist_clara = "fast_euclidean"

        elif self.name == "PAM":
            self.n_medoids = 3

        elif self.name == "CLARANS":
            self.n_medoids = 3
            self.numlocal_clarans = 5
            self.maxneighbors_clarans = 5

        elif self.name == "BIRCH":
            self.n_clust = 3
            self.branching_factor = 5
            self.max_node_entries = 5
            self.initial_diameter = 0.1

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            self.n_clust = 3
            self.knn_cham = 6
            self.init_clust_cham = 10
            self.alpha_cham = 2

            if self.name == "CHAMELEON2":
                self.beta_cham = 1
                self.m_fact = 1000

        elif self.name == "DENCLUE":
            self.sigma_denclue = 1
            self.xi_denclue = 2
            self.xi_c_denclue = 3
            self.tol_denclue = 2
            self.prec_denclue = 5

    def label_initialization(self):

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            # eps LABEL
            self.label_eps = QLabel(self)
            self.label_eps.setText("eps (\u03B5):")
            self.label_eps.setToolTip(
                "The maximum distance between two samples for one to be considered as in the neighborhood"
                " of the other."
            )

            self.line_edit_eps = QLineEdit(self)
            self.line_edit_eps.setText(str(self.eps))

            self.eps_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_eps.setValidator(self.eps_validator)

            # minPTS LABEL
            self.label_mp = QLabel(self)
            self.label_mp.setText("minPTS:")
            self.label_mp.setToolTip(
                "The number of samples in a neighborhood for a point to "
                "be considered as a core point."
            )

            self.line_edit_mp = QLineEdit(self)
            self.line_edit_mp.setText(str(self.mp))

            self.mp_validator = QIntValidator(1, 200, self)
            self.line_edit_mp.setValidator(self.mp_validator)

            # eps_extr LABEL
            if self.name == "OPTICS":
                self.label_eps_extr = QLabel(self)
                self.label_eps_extr.setText("eps_extr (\u03B5'):")
                self.label_eps_extr.setToolTip(
                    "The eps parameter to use to extract clusters from the reachability plot in a DBSCAN way."
                )

                self.line_edit_eps_extr = QLineEdit(self)
                self.line_edit_eps_extr.setText(str(self.eps_extr))

                self.eps_extr_validator = QDoubleValidator(0, 1000, 4, self)
                self.line_edit_eps_extr.setValidator(self.eps_extr_validator)

        elif self.name == "AGGLOMERATIVE":

            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # linkage method LABEL
            self.label_linkage = QLabel(self)
            self.label_linkage.setText("linkage:")
            self.label_linkage.setToolTip(
                "Choose among four linkage methods to perform hierarchical "
                "agglomerative clustering."
            )

            # COMBOBOX of linkage methods
            self.combobox_linkage = QComboBox(self)
            self.combobox_linkage.addItem("single")
            self.combobox_linkage.addItem("complete")
            self.combobox_linkage.addItem("average")
            self.combobox_linkage.addItem("ward")

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):

            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # n_repr LABEL
            self.label_n_repr = QLabel(self)
            self.label_n_repr.setText("n_repr:")
            self.label_n_repr.setToolTip(
                "The desired number of representative points for each cluster."
            )

            self.line_edit_n_repr = QLineEdit(self)
            self.line_edit_n_repr.setText(str(self.n_repr))

            self.n_repr_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_repr.setValidator(self.n_repr_validator)

            # alpha_cure LABEL
            self.label_alpha_cure = QLabel(self)
            self.label_alpha_cure.setText("alpha:")
            self.label_alpha_cure.setToolTip(
                "How much the representative points are shrunk towards the center of mass; if it is "
                "equal to 1, they collapse to the center of mass, if it is 0 they do not move."
            )

            self.line_edit_alpha_cure = QLineEdit(self)
            self.line_edit_alpha_cure.setText(str(self.alpha_cure))

            self.alpha_cure_validator = QDoubleValidator(0, 1, 4, self)
            # self.alpha_cure_validator.setNotation(QDoubleValidator.StandardNotation)
            self.line_edit_alpha_cure.setValidator(self.alpha_cure_validator)

            if self.name == "LARGE CURE":
                # p_cure LABEL
                self.label_p_cure = QLabel(self)
                self.label_p_cure.setText("p:")
                self.label_p_cure.setToolTip(
                    "The number of partitions to divide the dataset into, for the large dataset version."
                )

                self.line_edit_p_cure = QLineEdit(self)
                self.line_edit_p_cure.setText(str(self.p_cure))

                self.p_cure_validator = QIntValidator(2, 4, self)
                self.line_edit_p_cure.setValidator(self.p_cure_validator)

                # q_cure LABEL
                self.label_q_cure = QLabel(self)
                self.label_q_cure.setText("q:")
                self.label_q_cure.setToolTip(
                    "The number > 1 such that each partition reduces to n_points/(pq) clusters, "
                    "for the large dataset version."
                )

                self.line_edit_q_cure = QLineEdit(self)
                self.line_edit_q_cure.setText(str(self.q_cure))

                self.q_cure_validator = QIntValidator(2, 100, self)
                self.line_edit_q_cure.setValidator(self.q_cure_validator)

        elif (self.name == "CLARA") or (self.name == "PAM") or (self.name == "CLARANS"):

            # n_medoids LABEL
            self.label_n_medoids = QLabel(self)
            self.label_n_medoids.setText("n_medoids:")
            self.label_n_medoids.setToolTip(
                "The desired number of medoids to use "
                "(corresponding to the desired number of clusters)."
            )

            self.line_edit_n_medoids = QLineEdit(self)
            self.line_edit_n_medoids.setText(str(self.n_medoids))

            self.n_medoids_validator = QIntValidator(2, 1000, self)
            self.line_edit_n_medoids.setValidator(self.n_medoids_validator)

            if self.name == "CLARA":
                # distance LABEL
                self.label_distances_clara = QLabel(self)
                self.label_distances_clara.setText("distance:")
                self.label_distances_clara.setToolTip(
                    "Choose among four distances to perform CLARA."
                )

                # COMBOBOX of possible distances to use
                self.combobox_distances_clara = QComboBox(self)
                self.combobox_distances_clara.addItem("fast_euclidean")
                self.combobox_distances_clara.addItem("euclidean")
                self.combobox_distances_clara.addItem("manhattan")
                # self.combobox_distances_clara.addItem("cosine")

            if self.name == "CLARANS":
                # graph examples BUTTON
                self.button_examples_graph = QPushButton("GRAPH", self)
                self.button_examples_graph.setEnabled(True)
                self.button_examples_graph.setToolTip(
                    "See some examples of CLARANS graphs G_{k,n} as in the paper."
                )

                # numlocal_clarans LABEL
                self.label_numlocal_clarans = QLabel(self)
                self.label_numlocal_clarans.setText("num_iter:")
                self.label_numlocal_clarans.setToolTip(
                    "The number of local minima obtained (amount of iterations "
                    "for solving the problem)."
                )

                self.line_edit_numlocal_clarans = QLineEdit(self)
                self.line_edit_numlocal_clarans.setText(str(self.numlocal_clarans))

                self.numlocal_clarans_validator = QIntValidator(1, 1000, self)
                self.line_edit_numlocal_clarans.setValidator(
                    self.numlocal_clarans_validator
                )

                # maxneighbors_clarans LABEL
                self.label_maxneighbors_clarans = QLabel(self)
                self.label_maxneighbors_clarans.setText("max_neigh:")
                self.label_maxneighbors_clarans.setToolTip(
                    "The maximum number of neighbors examined. This heavily "
                    "affects runtime"
                )

                self.line_edit_maxneighbors_clarans = QLineEdit(self)
                self.line_edit_maxneighbors_clarans.setText(
                    str(self.maxneighbors_clarans)
                )

                self.maxneighbors_clarans_validator = QIntValidator(1, 1000, self)
                self.line_edit_maxneighbors_clarans.setValidator(
                    self.maxneighbors_clarans_validator
                )

        elif self.name == "BIRCH":
            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # branching_factor LABEL
            self.label_branching_factor = QLabel(self)
            self.label_branching_factor.setText("branch_fact:")
            self.label_branching_factor.setToolTip(
                "The branching factor is the maximum number of successor "
                "that might be contained by each non-leaf node in CF-Tree."
            )

            self.line_edit_branching_factor = QLineEdit(self)
            self.line_edit_branching_factor.setText(str(self.branching_factor))

            self.branching_factor_validator = QIntValidator(2, 10, self)
            self.line_edit_branching_factor.setValidator(
                self.branching_factor_validator
            )

            # max_node_entries LABEL
            self.label_max_node_entries = QLabel(self)
            self.label_max_node_entries.setText("max_node_ent:")
            self.label_max_node_entries.setToolTip(
                "The maximum number of entries that might be contained "
                "by each leaf node in CF-Tree."
            )

            self.line_edit_max_node_entries = QLineEdit(self)
            self.line_edit_max_node_entries.setText(str(self.max_node_entries))

            self.max_node_entries_validator = QIntValidator(1, 10, self)
            self.line_edit_max_node_entries.setValidator(
                self.max_node_entries_validator
            )

            # initial_diameter LABEL
            self.label_initial_diameter = QLabel(self)
            self.label_initial_diameter.setText("init_diam:")
            self.label_initial_diameter.setToolTip(
                "The initial diameter that is used for CF-Tree construction."
            )

            self.line_edit_initial_diameter = QLineEdit(self)
            self.line_edit_initial_diameter.setText(str(self.initial_diameter))

            self.initial_diameter_validator = QDoubleValidator(0, 1000, 4)
            # self.initial_diameter_validator.setNotation(QDoubleValidator.StandardNotation)
            self.line_edit_initial_diameter.setValidator(
                self.initial_diameter_validator
            )

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # knn_cham LABEL
            self.label_knn_cham = QLabel(self)
            self.label_knn_cham.setText("k of KNN:")
            self.label_knn_cham.setToolTip(
                "The number of neighbors to consider when building the KNN-Graph."
            )

            self.line_edit_knn_cham = QLineEdit(self)
            self.line_edit_knn_cham.setText(str(self.knn_cham))

            self.knn_cham_validator = QIntValidator(1, 1000, self)
            self.line_edit_knn_cham.setValidator(self.knn_cham_validator)

            # init_clust_cham LABEL
            self.label_init_clust_cham = QLabel(self)
            self.label_init_clust_cham.setText("init_clust:")
            self.label_init_clust_cham.setToolTip(
                "The number of clusters to reach in the initial phase."
            )

            self.line_edit_init_clust_cham = QLineEdit(self)
            self.line_edit_init_clust_cham.setText(str(self.init_clust_cham))

            self.init_clust_cham_validator = QIntValidator(1, 1000, self)
            self.line_edit_init_clust_cham.setValidator(self.init_clust_cham_validator)

            # alpha_cham LABEL
            self.label_alpha_cham = QLabel(self)
            self.label_alpha_cham.setText("alpha:")
            self.label_alpha_cham.setToolTip("The exponent of relative closeness.")

            self.line_edit_alpha_cham = QLineEdit(self)
            self.line_edit_alpha_cham.setText(str(self.alpha_cham))

            self.alpha_cham_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_alpha_cham.setValidator(self.alpha_cham_validator)

            if self.name == "CHAMELEON2":
                # beta_cham LABEL
                self.label_beta_cham = QLabel(self)
                self.label_beta_cham.setText("beta:")
                self.label_beta_cham.setToolTip(
                    "The exponent of relative connectivity."
                )

                self.line_edit_beta_cham = QLineEdit(self)
                self.line_edit_beta_cham.setText(str(self.beta_cham))

                self.beta_cham_validator = QDoubleValidator(0, 1000, 4, self)
                self.line_edit_beta_cham.setValidator(self.beta_cham_validator)

                # m_fact LABEL
                self.label_m_fact = QLabel(self)
                self.label_m_fact.setText("m_fact:")
                self.label_m_fact.setToolTip(
                    "The weight to assign to single-point clusters."
                )

                self.line_edit_m_fact = QLineEdit(self)
                self.line_edit_m_fact.setText(str(self.m_fact))

                self.m_fact_validator = QIntValidator(0, 1000000, self)
                self.line_edit_m_fact.setValidator(self.m_fact_validator)

        elif self.name == "DENCLUE":
            # sigma_denclue LABEL
            self.label_sigma_denclue = QLabel(self)
            self.label_sigma_denclue.setText("sigma (\u03C3):")
            self.label_sigma_denclue.setToolTip(
                "This parameter determines the influence of a point "
                "in its neighborhood. The higher sigma, the lower the influence."
            )

            self.line_edit_sigma_denclue = QLineEdit(self)
            self.line_edit_sigma_denclue.setText(str(self.sigma_denclue))

            self.sigma_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_sigma_denclue.setValidator(self.sigma_denclue_validator)

            # xi_denclue LABEL
            self.label_xi_denclue = QLabel(self)
            self.label_xi_denclue.setText("xi (\u03BE):")
            self.label_xi_denclue.setToolTip(
                "This parameter determines the minimum density level for "
                "a density attractor to be significant. The higher xi, the less clusters"
                "are obtained."
            )

            self.line_edit_xi_denclue = QLineEdit(self)
            self.line_edit_xi_denclue.setText(str(self.xi_denclue))

            self.xi_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_xi_denclue.setValidator(self.xi_denclue_validator)

            # xi_c_denclue LABEL
            self.label_xi_c_denclue = QLabel(self)
            self.label_xi_c_denclue.setText("xi_c (\u03BE_c) :")
            self.label_xi_c_denclue.setToolTip(
                "This parameter is a second outlier bound to determine which"
                "cubes are highly populated. The lower xi_c, the more highly "
                "populated cubes."
            )

            self.line_edit_xi_c_denclue = QLineEdit(self)
            self.line_edit_xi_c_denclue.setText(str(self.xi_c_denclue))

            self.xi_c_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_xi_c_denclue.setValidator(self.xi_c_denclue_validator)

            # tol_denclue LABEL
            self.label_tol_denclue = QLabel(self)
            self.label_tol_denclue.setText("tol :")
            self.label_tol_denclue.setToolTip(
                "Tolerance for the hill_climbing algorithm."
            )

            self.line_edit_tol_denclue = QLineEdit(self)
            self.line_edit_tol_denclue.setText(str(self.tol_denclue))

            self.tol_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_tol_denclue.setValidator(self.tol_denclue_validator)

            # prec_denclue LABEL
            self.label_prec_denclue = QLabel(self)
            self.label_prec_denclue.setText("prec :")
            self.label_prec_denclue.setToolTip(
                "Precision for plotting. The higher prec, the more precise the plots "
                "are, but it will take longer for them to be displayed. ALERT: it is "
                "best not to set this over 30."
            )

            self.line_edit_prec_denclue = QLineEdit(self)
            self.line_edit_prec_denclue.setText(str(self.prec_denclue))

            self.prec_denclue_validator = QIntValidator(0, 100, self)
            self.line_edit_prec_denclue.setValidator(self.prec_denclue_validator)

            # 4 checkboxes to choose which plots to display

            # self.checkbox_pop_cubes = QCheckBox("pop cubes")
            # self.checkbox_pop_cubes.setToolTip("Check it to show the plot of populated cubes.")

            self.checkbox_highly_pop_cubes = QCheckBox("highly pop cubes")
            self.checkbox_highly_pop_cubes.setToolTip(
                "Check it to show the picture of highly populated cubes."
            )

            self.checkbox_contour = QCheckBox("contour")
            self.checkbox_contour.setToolTip(
                "Check it to show the countour plot of the influence function."
            )

            self.checkbox_3dplot = QCheckBox("3d plot")
            self.checkbox_3dplot.setToolTip(
                "Check it to show a 3d plot of the influence function."
            )

            self.checkbox_clusters = QCheckBox("clusters")
            self.checkbox_clusters.setToolTip(
                "Check it show a final plot of the clusters found using DENCLUE."
            )

            # button for influence function plot
            self.button_infl_denclue = QPushButton("Influence", self)
            self.button_infl_denclue.setToolTip(
                "Show the influence function value for each point along with a "
                "density-attractors significance threshold determined by xi."
            )

    def log_initialization(self):
        log_list = ["DBSCAN", "CLARA", "PAM", "CLARANS"]
        log_list2 = [
            "OPTICS",
            "AGGLOMERATIVE",
            "BIRCH",
            "CHAMELEON",
            "CHAMELEON2",
            "DENCLUE",
        ]

        if self.name in log_list2:
            if self.name == "OPTICS":
                self.log = QPlainTextEdit("SEED QUEUE")
            elif self.name == "BIRCH":
                self.log = QPlainTextEdit(
                    "{} LOG".format(self.name)
                    + "\n"
                    + "You must have Graphviz installed on your Mac in order for BIRCH to work"
                )
            else:
                self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )

            if self.name != "DENCLUE":
                self.gridlayout.addWidget(self.log, 1, 0)
            elif self.name == "DENCLUE":
                self.log.setFixedWidth(220)
                self.gridlayout.addWidget(self.log, 2, 0, 1, 2)

        elif self.name in log_list:
            self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setGeometry(900, 60, 350, 400)
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )
            self.log.setFixedHeight(335)
            if self.name == "DBSCAN":
                self.gridlayout.addWidget(self.log, 1, 0)
            else:
                self.gridlayout.addWidget(self.log, 1, 1)

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )
            self.log.setFixedWidth(220)
            self.gridlayout.addWidget(self.log, 1, 0, 1, 2)

    def buttons_groupbox_initialization(self):

        self.groupbox_buttons = QGroupBox("Parameters")

        if self.name != "DENCLUE":
            self.groupbox_buttons.setFixedSize(220, 400)
        elif self.name == "DENCLUE":
            self.groupbox_buttons.setFixedWidth(220)

        if self.name == "CHAMELEON":
            self.groupbox_buttons.setFixedHeight(450)

        if self.name == "CHAMELEON2":
            self.groupbox_buttons.setFixedHeight(500)

        self.gridlayout.addWidget(self.groupbox_buttons, 0, 0)

        self.gridlayout_but = QGridLayout(self.groupbox_buttons)

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)

            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_eps, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_eps, 2, 1)
            self.gridlayout_but.addWidget(self.label_mp, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_mp, 3, 1)

            if self.name == "OPTICS":
                self.gridlayout_but.addWidget(self.label_eps_extr, 4, 0)
                self.gridlayout_but.addWidget(self.line_edit_eps_extr, 4, 1)
                self.gridlayout_but.addWidget(self.button_extract, 5, 1)

            self.gridlayout_but.addWidget(self.button_run, 5, 0)

            self.gridlayout_but.addWidget(self.label_slider, 6, 0)
            self.gridlayout_but.addWidget(self.slider, 6, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

        elif self.name == "AGGLOMERATIVE":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_linkage, 3, 0)
            self.gridlayout_but.addWidget(self.combobox_linkage, 3, 1)

            self.gridlayout_but.addWidget(self.button_run, 4, 0)

            self.gridlayout_but.addWidget(self.label_slider, 5, 0)
            self.gridlayout_but.addWidget(self.slider, 5, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 6, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 6, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 7, 0, 1, 0)

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.gridlayout_but.addWidget(self.label_ds, 0, 0, 1, 2)
            self.gridlayout_but.addWidget(self.combobox, 0, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_np, 1, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_n_repr, 3, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_n_repr, 3, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_alpha_cure, 4, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_alpha_cure, 4, 2, 1, 2)
            if self.name == "LARGE CURE":
                self.gridlayout_but.addWidget(self.label_p_cure, 5, 0)
                self.gridlayout_but.addWidget(self.line_edit_p_cure, 5, 1)
                self.gridlayout_but.addWidget(self.label_q_cure, 5, 2)
                self.gridlayout_but.addWidget(self.line_edit_q_cure, 5, 3)

                self.gridlayout_but.addWidget(self.button_run, 6, 0, 1, 2)

                self.gridlayout_but.addWidget(self.label_slider, 7, 0, 1, 2)
                self.gridlayout_but.addWidget(self.slider, 7, 2, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_gif, 8, 2, 1, 2)
                self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 4)
            elif self.name == "CURE":
                self.gridlayout_but.addWidget(self.button_run, 5, 0, 1, 2)

                self.gridlayout_but.addWidget(self.label_slider, 6, 0, 1, 2)
                self.gridlayout_but.addWidget(self.slider, 6, 2, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_gif, 7, 2, 1, 2)
                self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 4)

        elif self.name == "CLARA":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)
            self.gridlayout_but.addWidget(self.label_distances_clara, 3, 0)
            self.gridlayout_but.addWidget(self.combobox_distances_clara, 3, 1)

            self.gridlayout_but.addWidget(self.button_run, 4, 0)

            self.gridlayout_but.addWidget(self.label_slider, 5, 0)
            self.gridlayout_but.addWidget(self.slider, 5, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 6, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 6, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 7, 0, 1, 0)

        elif self.name == "PAM":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)

            self.gridlayout_but.addWidget(self.button_run, 3, 0)

            self.gridlayout_but.addWidget(self.label_slider, 4, 0)
            self.gridlayout_but.addWidget(self.slider, 4, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 5, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 5, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 6, 0, 1, 0)

        elif self.name == "CLARANS":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)
            self.gridlayout_but.addWidget(self.label_numlocal_clarans, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_numlocal_clarans, 3, 1)
            self.gridlayout_but.addWidget(self.label_maxneighbors_clarans, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_maxneighbors_clarans, 4, 1)

            self.gridlayout_but.addWidget(self.button_run, 5, 0)
            self.gridlayout_but.addWidget(self.button_examples_graph, 5, 1)

            self.gridlayout_but.addWidget(self.label_slider, 6, 0)
            self.gridlayout_but.addWidget(self.slider, 6, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

        elif self.name == "BIRCH":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_branching_factor, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_branching_factor, 3, 1)
            self.gridlayout_but.addWidget(self.label_max_node_entries, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_max_node_entries, 4, 1)
            self.gridlayout_but.addWidget(self.label_initial_diameter, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_initial_diameter, 5, 1)

            self.gridlayout_but.addWidget(self.button_run, 6, 0)

            self.gridlayout_but.addWidget(self.label_slider, 7, 0)
            self.gridlayout_but.addWidget(self.slider, 7, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 8, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 0)

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_knn_cham, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_knn_cham, 3, 1)
            self.gridlayout_but.addWidget(self.label_init_clust_cham, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_init_clust_cham, 4, 1)
            self.gridlayout_but.addWidget(self.label_alpha_cham, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_alpha_cham, 5, 1)

            if self.name == "CHAMELEON":

                self.gridlayout_but.addWidget(self.button_run, 6, 0)

                self.gridlayout_but.addWidget(self.label_slider, 7, 0)
                self.gridlayout_but.addWidget(self.slider, 7, 1)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0)
                self.gridlayout_but.addWidget(self.checkbox_gif, 8, 1)
                self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 0)

            elif self.name == "CHAMELEON2":
                self.gridlayout_but.addWidget(self.label_beta_cham, 6, 0)
                self.gridlayout_but.addWidget(self.line_edit_beta_cham, 6, 1)
                self.gridlayout_but.addWidget(self.label_m_fact, 7, 0)
                self.gridlayout_but.addWidget(self.line_edit_m_fact, 7, 1)

                self.gridlayout_but.addWidget(self.button_run, 8, 0)

                self.gridlayout_but.addWidget(self.label_slider, 9, 0)
                self.gridlayout_but.addWidget(self.slider, 9, 1)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 10, 0)
                self.gridlayout_but.addWidget(self.checkbox_gif, 10, 1)
                self.gridlayout_but.addWidget(self.button_delete_pics, 11, 0, 1, 0)

        elif self.name == "DENCLUE":

            self.groupbox_plots_denclue = QGroupBox("Plotting options")
            self.gridlayout.addWidget(self.groupbox_plots_denclue, 1, 0)
            self.groupbox_plots_denclue.setFixedWidth(220)
            self.gridlayout_plot_checkboxes = QGridLayout(self.groupbox_plots_denclue)

            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_sigma_denclue, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_sigma_denclue, 2, 1)
            self.gridlayout_but.addWidget(self.label_xi_denclue, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_xi_denclue, 3, 1)
            self.gridlayout_but.addWidget(self.label_xi_c_denclue, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_xi_c_denclue, 4, 1)
            self.gridlayout_but.addWidget(self.label_tol_denclue, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_tol_denclue, 5, 1)
            self.gridlayout_but.addWidget(self.label_prec_denclue, 6, 0)
            self.gridlayout_but.addWidget(self.line_edit_prec_denclue, 6, 1)

            self.gridlayout_but.addWidget(self.button_run, 7, 0)
            # self.gridlayout_but.addWidget(self.label_slider, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

            # self.gridlayout_plot_checkboxes.addWidget(self.checkbox_pop_cubes, 0, 0)
            self.gridlayout_plot_checkboxes.addWidget(
                self.checkbox_highly_pop_cubes, 0, 0
            )
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_contour, 0, 1)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_3dplot, 1, 0)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_clusters, 1, 1)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_saveimg, 2, 0)
            self.gridlayout_plot_checkboxes.addWidget(self.button_infl_denclue, 2, 1)

    def checkBoxChangedAction(self, state):
        if Qt.Checked == state:
            self.save_plots = True
            self.checkbox_gif.setEnabled(True)

            try:
                os.mkdir(
                    appctxt.get_resource("Images/")
                    + "/"
                    + "{}_{:02}".format(self.name, self.ind_run)
                )
                # print("new folder")

            except OSError as error:
                pass
                # print(error)
        else:
            self.checkbox_gif.setEnabled(False)
            self.save_plots = False

    def delete_pics(self):

        msg = "Do you really want to delete all PICs and GIFs generated by {} until now?".format(
            self.name
        )
        messagebox_reply = QMessageBox.question(
            self,
            "Images removal",
            msg,
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No,
        )

        if messagebox_reply == QMessageBox.Yes:

            folders = [
                fold
                for fold in os.listdir(appctxt.get_resource("Images/"))
                if fold.startswith("{}".format(self.name))
            ]
            for folder in folders:
                rmtree(appctxt.get_resource("Images/") + "/" + folder)
            self.ind_run = 0
            self.first_run_occurred = False

        elif messagebox_reply == QMessageBox.No:
            return

    def GIFChangedAction(self, state):
        if Qt.Checked == state:
            self.make_gif = True
        else:
            self.make_gif = False

    def generate_GIF(self):

        png_dir = (
            appctxt.get_resource("Images/")
            + "/"
            + "{}_{:02}".format(self.name, self.ind_run)
        )
        images = []
        fig_list = [
            pic
            for pic in os.listdir(png_dir)
            if (pic.startswith("fig")) & ("fin" not in pic)
        ]
        fig_list.sort()
        fin_list = [pic for pic in os.listdir(png_dir) if "graph" in pic]
        fin_list.sort()

        if self.name == "BIRCH":
            graphviz_list = [
                pic
                for pic in os.listdir(png_dir)
                if ("graph" in pic) and (pic.endswith(".png"))
            ]
            graphviz_list.sort()

        if len(fin_list) != 0:

            if (self.name != "LARGE CURE") and (self.name != "BIRCH"):
                list_for_gif = fig_list + [fin_list[-1]]
            elif self.name == "LARGE CURE":
                list_for_gif = fig_list + fin_list
            elif self.name == "BIRCH":
                list_for_gif = fig_list
        else:
            list_for_gif = fig_list

        for file_name in list_for_gif:
            file_path = os.path.join(png_dir, file_name)
            images.append(imread(file_path))

        if int(self.line_edit_np.text()) < 50:
            duration = 0.35
        else:
            duration = 0.25
        mimsave(png_dir + "/movie.gif", images, duration=duration)

        if self.name == "BIRCH":
            images = []
            for file_name in graphviz_list:
                file_path = os.path.join(png_dir, file_name)
                images.append(imread(file_path))

            mimsave(png_dir + "/movie2.gif", images, duration=duration)

    def changedValue(self):
        size = self.slider.sl.value()
        self.delay = size

    def show_error_message(self, check, msg):
        if check[0] != 2:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(msg)
            self.log.appendPlainText("")

        QCoreApplication.processEvents()

    def n_clust_error(self, medoids=False, init_clust=False):

        if medoids is False:

            cond = int(self.line_edit_n_clust.text()) >= int(self.line_edit_np.text())
            text = "clusters"

        else:

            cond = int(self.line_edit_n_medoids.text()) >= int(self.line_edit_np.text())
            text = "medoids"

        if cond == True:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(
                "The number of {} should be less than the number of points.".format(
                    text
                )
            )
            self.log.appendPlainText("")

        if init_clust == True:

            cond_2 = int(self.line_edit_n_clust.text()) >= int(
                self.line_edit_init_clust_cham.text()
            )
            text = "initial clusters"

            if cond_2 == True:

                if self.param_check is True:
                    self.log.clear()

                self.param_check = False
                self.log.appendPlainText("ERROR")
                self.log.appendPlainText("")
                self.log.appendPlainText(
                    "The number of {} should be greater than the "
                    "number of final clusters.".format(text)
                )
                self.log.appendPlainText("")

        QCoreApplication.processEvents()

    def comma_error(self, parameter):

        if parameter.find(",") != -1:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(
                "Using a comma (,) as decimal sepator is not accepted, use a dot (.) "
                "instead"
            )
            self.log.appendPlainText("")

    def verify_input_parameters(self, extract=False):

        self.param_check = True
        check_n_points = self.n_points_validator.validate(self.line_edit_np.text(), 0)
        self.show_error_message(
            check_n_points,
            "The parameter n_points must be an integer and lie between {0}"
            " and {1}.".format(5, 200),
        )

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            if extract is False:
                check_eps = self.eps_validator.validate(self.line_edit_eps.text(), 0)
                check_mp = self.mp_validator.validate(self.line_edit_mp.text(), 0)

                self.show_error_message(
                    check_eps,
                    "The parameter eps must lie between {0} and {1}, and can have a maximum of"
                    " {2} decimal places.".format(0, 1000, 4),
                )
                self.show_error_message(
                    check_mp,
                    "The parameter minPTS must be an integer and lie "
                    "between {0} and {1}.".format(1, 200),
                )

                self.comma_error(parameter=self.line_edit_eps.text())

            if self.name == "OPTICS":
                check_eps_extr = self.eps_extr_validator.validate(
                    self.line_edit_eps_extr.text(), 0
                )

                self.show_error_message(
                    check_eps_extr,
                    "The parameter eps_extr must lie between {0} and {1}, and can "
                    "have a maximum of {2} decimal places.".format(0, 1000, 4),
                )

                self.comma_error(parameter=self.line_edit_eps_extr.text())

        elif self.name == "AGGLOMERATIVE":

            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            # self.comma_error(parameter=self.line_edit_n_clust.text())
            try:
                self.n_clust_error()
            except:
                pass

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):

            check_n_repr = self.n_repr_validator.validate(
                self.line_edit_n_repr.text(), 0
            )
            check_alpha_cure = self.alpha_cure_validator.validate(
                self.line_edit_alpha_cure.text(), 0
            )
            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            self.show_error_message(
                check_n_repr,
                "The parameter n_repr must be an integer and lie between {0}"
                " and {1}.".format(1, 1000),
            )
            self.show_error_message(
                check_alpha_cure,
                "The parameter alpha must lie between {0} and {1}, and can "
                "have a maximum of {2} decimal places.".format(0, 1, 4),
            )

            self.comma_error(parameter=self.line_edit_alpha_cure.text())
            try:
                self.n_clust_error()
            except:
                pass

            if self.name == "LARGE CURE":
                check_p_cure = self.p_cure_validator.validate(
                    self.line_edit_p_cure.text(), 0
                )
                check_q_cure = self.q_cure_validator.validate(
                    self.line_edit_q_cure.text(), 0
                )
                self.show_error_message(
                    check_p_cure,
                    "The parameter p can be an {0}, {1} or {2}.".format(2, 3, 4),
                )
                self.show_error_message(
                    check_q_cure,
                    "The parameter q must be an integer and lie between {0}"
                    " and {1}.".format(2, 100),
                )

        elif (self.name == "CLARA") or (self.name == "PAM") or (self.name == "CLARANS"):
            check_n_medoids = self.n_medoids_validator.validate(
                self.line_edit_n_medoids.text(), 0
            )

            self.show_error_message(
                check_n_medoids,
                "The parameter n_medoids must be an integer and lie between "
                "{0} and {1}".format(2, 1000),
            )

            try:
                self.n_clust_error(medoids=True)
            except:
                pass

            if self.name == "CLARANS":
                check_numlocal_clarans = self.numlocal_clarans_validator.validate(
                    self.line_edit_numlocal_clarans.text(), 0
                )
                check_maxneighbors_clarans = self.maxneighbors_clarans_validator.validate(
                    self.line_edit_maxneighbors_clarans.text(), 0
                )

                self.show_error_message(
                    check_numlocal_clarans,
                    "The parameter num_iter must be an integer and lie between "
                    "{0} and {1}".format(1, 1000),
                )
                self.show_error_message(
                    check_maxneighbors_clarans,
                    "The parameter max_neigh must be an integer and lie between "
                    "{0} and {1}".format(1, 1000),
                )

        elif self.name == "BIRCH":
            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )
            check_branching_factor = self.branching_factor_validator.validate(
                self.line_edit_branching_factor.text(), 0
            )
            check_max_node_entries = self.max_node_entries_validator.validate(
                self.line_edit_max_node_entries.text(), 0
            )
            check_initial_diameter = self.initial_diameter_validator.validate(
                self.line_edit_initial_diameter.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            self.show_error_message(
                check_branching_factor,
                "The parameter branch_fact must be an integer and lie between "
                "{0} and {1}".format(2, 10),
            )

            self.show_error_message(
                check_max_node_entries,
                "The parameter max_nod_ent must be an integer and lie between "
                "{0} and {1}".format(1, 10),
            )

            self.show_error_message(
                check_initial_diameter,
                "The parameter init_diam must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )

            self.comma_error(parameter=self.line_edit_initial_diameter.text())

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):

            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )
            check_knn_cham = self.knn_cham_validator.validate(
                self.line_edit_knn_cham.text(), 0
            )
            check_init_clust_cham = self.init_clust_cham_validator.validate(
                self.line_edit_init_clust_cham.text(), 0
            )
            check_alpha_cham = self.alpha_cham_validator.validate(
                self.line_edit_alpha_cham.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_knn_cham,
                "The parameter k of Knn must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_init_clust_cham,
                "The parameter init_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_alpha_cham,
                "The parameter alpha must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )

            self.comma_error(parameter=self.line_edit_alpha_cham.text())
            try:
                self.n_clust_error(init_clust=True)
            except:
                pass

            if self.name == "CHAMELEON2":
                check_beta_cham = self.beta_cham_validator.validate(
                    self.line_edit_beta_cham.text(), 0
                )
                check_m_fact = self.m_fact_validator.validate(
                    self.line_edit_m_fact.text(), 0
                )

                self.show_error_message(
                    check_beta_cham,
                    "The parameter beta must lie between {0} and {1}, and can have a maximum of"
                    " {2} decimal places.".format(0, 1000, 4),
                )
                self.show_error_message(
                    check_m_fact,
                    "The parameter m_fact must be an integer and lie between "
                    "{0} and {1}".format(1, 1000000),
                )
                self.comma_error(parameter=self.line_edit_beta_cham.text())

        elif self.name == "DENCLUE":

            check_sigma_denclue = self.sigma_denclue_validator.validate(
                self.line_edit_sigma_denclue.text(), 0
            )
            check_xi_denclue = self.xi_denclue_validator.validate(
                self.line_edit_xi_denclue.text(), 0
            )
            check_xi_c_denclue = self.xi_c_denclue_validator.validate(
                self.line_edit_xi_c_denclue.text(), 0
            )
            check_tol_denclue = self.tol_denclue_validator.validate(
                self.line_edit_tol_denclue.text(), 0
            )
            check_prec_denclue = self.prec_denclue_validator.validate(
                self.line_edit_prec_denclue.text(), 0
            )

            self.show_error_message(
                check_sigma_denclue,
                "The parameter sigma must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_xi_denclue,
                "The parameter xi must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_xi_c_denclue,
                "The parameter xi_c must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_tol_denclue,
                "The parameter tol must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_prec_denclue,
                "The parameter prec must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 100, 4),
            )

            self.comma_error(parameter=self.line_edit_sigma_denclue.text())
            self.comma_error(parameter=self.line_edit_xi_denclue.text())
            self.comma_error(parameter=self.line_edit_xi_c_denclue.text())
            self.comma_error(parameter=self.line_edit_tol_denclue.text())
            self.comma_error(parameter=self.line_edit_prec_denclue.text())

    def SetWindows(self, number, first_run_boolean):
        """This is used for LARGE_CURE clustering algorithm: it serves the purpose of creating the right amount
        of subplots to display all the partitions, according to the user's input of p, which is here called number.

        :param number: how many subplots to do (can be 2, 3 or 4).
        :param first_run_boolean: if True, delete previous widgets (plots) before replotting."""

        self.ax1 = None
        self.ax2 = None
        self.ax3 = None
        self.ax4 = None

        self.canvas_3 = None
        self.canvas_4 = None

        self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax1 = self.canvas_up.figure.subplots()
        self.ax1.set_xticks([], [])
        self.ax1.set_yticks([], [])

        self.canvas_2 = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax2 = self.canvas_2.figure.subplots()
        self.ax2.set_xticks([], [])
        self.ax2.set_yticks([], [])

        if number >= 3:
            self.canvas_3 = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax3 = self.canvas_3.figure.subplots()
            self.ax3.set_xticks([], [])
            self.ax3.set_yticks([], [])
        if number == 4:
            self.canvas_4 = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax4 = self.canvas_4.figure.subplots()
            self.ax4.set_xticks([], [])
            self.ax4.set_yticks([], [])

        # this removes all widgets (plots) before replotting
        if first_run_boolean is True:
            for i in reversed(range(self.gridlayout_plots.count())):
                self.gridlayout_plots.itemAt(i).widget().setParent(None)

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)

        if number == 2:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
            self.gridlayout_plots.addWidget(self.canvas_2, 1, 0)

        elif number == 3:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 1)
            self.gridlayout_plots.addWidget(self.canvas_2, 0, 2)
            self.gridlayout_plots.addWidget(self.canvas_3, 0, 3)

        elif number == 4:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
            self.gridlayout_plots.addWidget(self.canvas_2, 0, 1)
            self.gridlayout_plots.addWidget(self.canvas_3, 1, 0)
            self.gridlayout_plots.addWidget(self.canvas_4, 1, 1)

    def SetWindowsDENCLUE(self, pic_list, first_run_boolean):
        """ Analogous of SetWindows but for DENCLUE algorithm."""

        self.canvas_list = []
        self.axes_list = []
        for i in range(4):
            self.canvas_list.append(FigureCanvas(Figure(figsize=(14, 6))))
            if i == 2:
                self.axes_list.append(
                    self.canvas_list[i].figure.add_subplot(111, projection="3d")
                )
            else:
                self.axes_list.append(self.canvas_list[i].figure.subplots())

            self.axes_list[i].set_xticks([], [])
            self.axes_list[i].set_yticks([], [])

        self.axes_list[0].set_title("Highly populated cubes")
        self.axes_list[1].set_title("Scatterplot with Countour plot")
        self.axes_list[2].set_title("3D surface with 2D contour plot projections")
        self.axes_list[3].set_title("DENCLUE clusters")

        canvas_list = self.canvas_list

        if first_run_boolean is True:
            for i in reversed(range(self.gridlayout_plots.count())):
                self.gridlayout_plots.itemAt(i).widget().setParent(None)

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)

        pic_indexes = [i for i, j in enumerate(pic_list) if j == 1]

        if np.sum(pic_list) == 1:
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)

        elif np.sum(pic_list) == 2:
            if 2 in pic_indexes:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 0, 1)
            else:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)

        elif np.sum(pic_list) == 3:
            if 2 in pic_indexes:
                if 3 in pic_indexes:
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[-1]], 1, 0)
                    # 2 outside
                else:
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
                    # 2 outside
            else:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
                # 3 outside

        elif np.sum(pic_list) == 4:
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
            # 2 and 3 outside

    def SetWindowsCHAMELEON(self):

        self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax1 = self.canvas_up.figure.subplots()
        self.ax1.set_xticks([], [])
        self.ax1.set_yticks([], [])
        self.ax1.set_title(self.name + " Graph Clustering")

        self.canvas_down = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax = self.canvas_down.figure.subplots()
        self.ax.set_xticks([], [])
        self.ax.set_yticks([], [])
        self.ax.set_title(self.name + " Merging")

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)
        self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
        self.gridlayout_plots.addWidget(self.canvas_down, 1, 0)


class GraphWindow(QMainWindow):
    def __init__(self, example_index):
        super().__init__()

        self.setWindowTitle("Graph example {}".format(example_index + 1))
        self.setGeometry(300, 200, 500, 400)
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        lay = QVBoxLayout(self.central_widget)

        self.label_graphviz = QLabel(self)
        self.label_graphviz.setFixedSize(500, 400)
        pixmap = QPixmap(
            appctxt.get_resource("Images/")
            + "/"
            + "ClaransGraphExamples/graph_{:02}.png".format(example_index)
        )
        self.label_graphviz.setScaledContents(True)
        self.label_graphviz.setPixmap(pixmap)

        lay.addWidget(self.label_graphviz)
        self.show()


class FinalStepWindow(QMainWindow):
    def __init__(self, canvas, window_title="Final Step"):
        super().__init__()
        self.setWindowTitle(window_title)
        self.setGeometry(300, 200, 1000, 400)

        self.setCentralWidget(canvas)
        canvas.draw()

from PyQt5.QtWidgets import (
    QPushButton,
    QLabel,
    QComboBox,
    QGridLayout,
    QGroupBox,
    QLineEdit,
    QPlainTextEdit,
    QWidget,
    QCheckBox,
    QMessageBox,
    QVBoxLayout,
    QMainWindow,
)
from PyQt5.QtCore import Qt, QLocale, QCoreApplication
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QPixmap
from imageio import mimsave, imread
import os
from shutil import rmtree
import numpy as np

from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure

from sklearn.datasets import make_blobs

from GUI_classes.utils_gui import LabeledSlider

from base import appctxt

# todo: PARAMETERS REGULARIZATION mettere a posto


class StartingGui(QWidget):
    def __init__(
        self,
        name,
        twinx,
        first_plot,
        second_plot,
        function,
        stretch_plot=False,
        extract=False,
    ):
        super().__init__()

        self.name = name
        self.function = function

        self.setWindowTitle(self.name)
        self.setGeometry(100, 100, 1290, 850)

        # otherwise Validators do not work properly
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))

        # upper plot
        if first_plot is True:
            self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax1 = self.canvas_up.figure.subplots()
            self.ax1.set_xticks([], [])
            self.ax1.set_yticks([], [])
            self.ax1.set_title(self.name + " procedure")
            if twinx is True:
                self.ax1_t = self.ax1.twinx()
                self.ax1_t.set_xticks([], [])
                self.ax1_t.set_yticks([], [])

        # lower plot
        if second_plot is True:
            self.canvas_down = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax = self.canvas_down.figure.subplots()
            self.ax.set_xticks([], [])
            self.ax.set_yticks([], [])
            if self.name == "OPTICS":
                self.ax.set_title(self.name + " Reachability Plot")
                self.ax.set_ylabel("reachability distance")
            if twinx is True:
                self.ax_t = self.ax.twinx()
                self.ax_t.set_xticks([], [])
                self.ax_t.set_yticks([], [])

        # influence plot for DENCLUE
        if self.name == "DENCLUE":
            self.canvas_infl = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax_infl = self.canvas_infl.figure.subplots()
            self.ax_infl.set_xticks([], [])
            self.ax_infl.set_yticks([], [])

        # parameters initialization
        self.parameter_initialization()

        # this is used to account for previously created folders in Images to set the self.ind_run correctly
        # fold_dir = appctxt.get_resource("Images/") + '/' + ''
        fold_dir = appctxt.get_resource("Images/")
        folders = [el for el in os.listdir(fold_dir) if el.startswith(self.name + "_")]
        folders.sort()
        if len(folders) == 0:
            self.ind_run = 0
        else:
            self.ind_run = int(folders[-1][(len(self.name) + 1) :]) + 1

        # grid where the two pictures, the log and the button box are inserted (row,column)
        self.gridlayout = QGridLayout(self)
        if (first_plot is True) and self.name != "CHAMELEON":
            if stretch_plot is False:
                self.gridlayout.addWidget(self.canvas_up, 0, 1)
            else:
                self.gridlayout.addWidget(self.canvas_up, 0, 1, 2, 1)

        if second_plot is True:
            self.gridlayout.addWidget(self.canvas_down, 1, 1)

        # START BUTTON
        self.button_run = QPushButton("START", self)
        self.button_run.clicked.connect(self.function)
        self.button_run.setToolTip("Perform clustering.")

        # SLIDER
        self.label_slider = QLabel(self)
        self.label_slider.setText("delay:")
        self.label_slider.setToolTip(
            "Delay each step of the algorithm for the desidered number of seconds."
        )

        self.slider = LabeledSlider(minimum=0, maximum=3, interval=1, single_step=0.5)
        self.slider.sl.valueChanged.connect(self.changedValue)
        self.slider.setFixedHeight(50)

        # EXTRACT BUTTON
        if extract is True:
            self.button_extract = QPushButton("EXTRACT", self)
            self.button_extract.clicked.connect(lambda: self.start_EXTRACT_OPTICS())
            self.button_extract.setEnabled(False)
            self.button_extract.setToolTip(
                "Extract clusters from OPTICS reachability plot in a"
                " DBSCAN way using eps_extr."
            )

        # CHECKBOX for saving images
        self.checkbox_saveimg = QCheckBox("save plots")
        self.checkbox_saveimg.setToolTip(
            "Check it to save all the plots generated by the algorithm. They are"
            " saved in the Images folder."
        )
        self.checkbox_saveimg.stateChanged.connect(self.checkBoxChangedAction)

        # CHECKBOX for generating GIF
        self.checkbox_gif = QCheckBox("make GIF")
        self.checkbox_gif.setToolTip(
            "Check it to build a GIF from the plots generated by the algorithm. GIF are not"
            " produced when new Extractions are performed, \nthey are only produced when the"
            " main clustering procedure is executed. The GIF is saved in the same folder of"
            " the plots it is composed of."
        )
        self.checkbox_gif.stateChanged.connect(self.GIFChangedAction)
        self.checkbox_gif.setEnabled(False)

        # BUTTON for removing generated pics and gifs
        self.button_delete_pics = QPushButton("DELETE PICs && GIFs", self)
        self.button_delete_pics.clicked.connect(self.delete_pics)
        self.button_delete_pics.setEnabled(True)
        self.button_delete_pics.setToolTip(
            "Delete all pictures and GIFs generated until now in the folder Images."
            " To avoid deleting specific files, just move them out of the folder"
            " Images."
        )

        # n_points LABEL
        self.label_np = QLabel(self)
        self.label_np.setText("n_points:")
        self.label_np.setToolTip(
            "Number of points of the dataset. It can lie between 5 and 200."
        )

        self.line_edit_np = QLineEdit(self)
        self.line_edit_np.setText(str(self.n_points))

        self.n_points_validator = QIntValidator(5, 200, self)
        self.line_edit_np.setValidator(self.n_points_validator)

        # dataset LABEL
        self.label_ds = QLabel(self)
        self.label_ds.setText("dataset:")
        self.label_ds.setToolTip(
            "Choose among four sklearn generated datasets to perform clustering."
        )

        # COMBOBOX of datasets
        self.combobox = QComboBox(self)
        self.combobox.addItem("blobs")
        self.combobox.addItem("moons")
        self.combobox.addItem("scatter")
        self.combobox.addItem("circle")

        # labels initialization
        self.label_initialization()

        # LOG
        self.log_initialization()

        # buttons in GROUPBOX (upper left corner)
        self.buttons_groupbox_initialization()

        self.show()

    def parameter_initialization(self):

        self.n_points = 30
        self.X = make_blobs(
            n_samples=self.n_points,
            centers=4,
            n_features=2,
            cluster_std=1.8,
            random_state=42,
        )[0]
        self.delay = 0
        self.ind_extr_fig = 0
        self.param_check = True
        self.save_plots = False
        self.first_run_occurred = False
        self.make_gif = False

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):
            self.eps = 2
            self.mp = 3
            self.eps_extr = 1
            self.ClustDist = {}
            self.ClustDict = {}
            self.CoreDist = {}

        elif self.name == "AGGLOMERATIVE":
            self.n_clust = 3
            self.linkage = "single"

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.n_clust = 2
            self.n_repr = 3
            self.alpha_cure = 0.5

            if self.name == "LARGE CURE":
                self.p_cure = 2
                self.q_cure = 2

        elif self.name == "CLARA":
            self.n_medoids = 3
            self.dist_clara = "fast_euclidean"

        elif self.name == "PAM":
            self.n_medoids = 3

        elif self.name == "CLARANS":
            self.n_medoids = 3
            self.numlocal_clarans = 5
            self.maxneighbors_clarans = 5

        elif self.name == "BIRCH":
            self.n_clust = 3
            self.branching_factor = 5
            self.max_node_entries = 5
            self.initial_diameter = 0.1

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            self.n_clust = 3
            self.knn_cham = 6
            self.init_clust_cham = 10
            self.alpha_cham = 2

            if self.name == "CHAMELEON2":
                self.beta_cham = 1
                self.m_fact = 1000

        elif self.name == "DENCLUE":
            self.sigma_denclue = 1
            self.xi_denclue = 2
            self.xi_c_denclue = 3
            self.tol_denclue = 2
            self.prec_denclue = 5

    def label_initialization(self):

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            # eps LABEL
            self.label_eps = QLabel(self)
            self.label_eps.setText("eps (\u03B5):")
            self.label_eps.setToolTip(
                "The maximum distance between two samples for one to be considered as in the neighborhood"
                " of the other."
            )

            self.line_edit_eps = QLineEdit(self)
            self.line_edit_eps.setText(str(self.eps))

            self.eps_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_eps.setValidator(self.eps_validator)

            # minPTS LABEL
            self.label_mp = QLabel(self)
            self.label_mp.setText("minPTS:")
            self.label_mp.setToolTip(
                "The number of samples in a neighborhood for a point to "
                "be considered as a core point."
            )

            self.line_edit_mp = QLineEdit(self)
            self.line_edit_mp.setText(str(self.mp))

            self.mp_validator = QIntValidator(1, 200, self)
            self.line_edit_mp.setValidator(self.mp_validator)

            # eps_extr LABEL
            if self.name == "OPTICS":
                self.label_eps_extr = QLabel(self)
                self.label_eps_extr.setText("eps_extr (\u03B5'):")
                self.label_eps_extr.setToolTip(
                    "The eps parameter to use to extract clusters from the reachability plot in a DBSCAN way."
                )

                self.line_edit_eps_extr = QLineEdit(self)
                self.line_edit_eps_extr.setText(str(self.eps_extr))

                self.eps_extr_validator = QDoubleValidator(0, 1000, 4, self)
                self.line_edit_eps_extr.setValidator(self.eps_extr_validator)

        elif self.name == "AGGLOMERATIVE":

            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # linkage method LABEL
            self.label_linkage = QLabel(self)
            self.label_linkage.setText("linkage:")
            self.label_linkage.setToolTip(
                "Choose among four linkage methods to perform hierarchical "
                "agglomerative clustering."
            )

            # COMBOBOX of linkage methods
            self.combobox_linkage = QComboBox(self)
            self.combobox_linkage.addItem("single")
            self.combobox_linkage.addItem("complete")
            self.combobox_linkage.addItem("average")
            self.combobox_linkage.addItem("ward")

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):

            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # n_repr LABEL
            self.label_n_repr = QLabel(self)
            self.label_n_repr.setText("n_repr:")
            self.label_n_repr.setToolTip(
                "The desired number of representative points for each cluster."
            )

            self.line_edit_n_repr = QLineEdit(self)
            self.line_edit_n_repr.setText(str(self.n_repr))

            self.n_repr_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_repr.setValidator(self.n_repr_validator)

            # alpha_cure LABEL
            self.label_alpha_cure = QLabel(self)
            self.label_alpha_cure.setText("alpha:")
            self.label_alpha_cure.setToolTip(
                "How much the representative points are shrunk towards the center of mass; if it is "
                "equal to 1, they collapse to the center of mass, if it is 0 they do not move."
            )

            self.line_edit_alpha_cure = QLineEdit(self)
            self.line_edit_alpha_cure.setText(str(self.alpha_cure))

            self.alpha_cure_validator = QDoubleValidator(0, 1, 4, self)
            # self.alpha_cure_validator.setNotation(QDoubleValidator.StandardNotation)
            self.line_edit_alpha_cure.setValidator(self.alpha_cure_validator)

            if self.name == "LARGE CURE":
                # p_cure LABEL
                self.label_p_cure = QLabel(self)
                self.label_p_cure.setText("p:")
                self.label_p_cure.setToolTip(
                    "The number of partitions to divide the dataset into, for the large dataset version."
                )

                self.line_edit_p_cure = QLineEdit(self)
                self.line_edit_p_cure.setText(str(self.p_cure))

                self.p_cure_validator = QIntValidator(2, 4, self)
                self.line_edit_p_cure.setValidator(self.p_cure_validator)

                # q_cure LABEL
                self.label_q_cure = QLabel(self)
                self.label_q_cure.setText("q:")
                self.label_q_cure.setToolTip(
                    "The number > 1 such that each partition reduces to n_points/(pq) clusters, "
                    "for the large dataset version."
                )

                self.line_edit_q_cure = QLineEdit(self)
                self.line_edit_q_cure.setText(str(self.q_cure))

                self.q_cure_validator = QIntValidator(2, 100, self)
                self.line_edit_q_cure.setValidator(self.q_cure_validator)

        elif (self.name == "CLARA") or (self.name == "PAM") or (self.name == "CLARANS"):

            # n_medoids LABEL
            self.label_n_medoids = QLabel(self)
            self.label_n_medoids.setText("n_medoids:")
            self.label_n_medoids.setToolTip(
                "The desired number of medoids to use "
                "(corresponding to the desired number of clusters)."
            )

            self.line_edit_n_medoids = QLineEdit(self)
            self.line_edit_n_medoids.setText(str(self.n_medoids))

            self.n_medoids_validator = QIntValidator(2, 1000, self)
            self.line_edit_n_medoids.setValidator(self.n_medoids_validator)

            if self.name == "CLARA":
                # distance LABEL
                self.label_distances_clara = QLabel(self)
                self.label_distances_clara.setText("distance:")
                self.label_distances_clara.setToolTip(
                    "Choose among four distances to perform CLARA."
                )

                # COMBOBOX of possible distances to use
                self.combobox_distances_clara = QComboBox(self)
                self.combobox_distances_clara.addItem("fast_euclidean")
                self.combobox_distances_clara.addItem("euclidean")
                self.combobox_distances_clara.addItem("manhattan")
                # self.combobox_distances_clara.addItem("cosine")

            if self.name == "CLARANS":
                # graph examples BUTTON
                self.button_examples_graph = QPushButton("GRAPH", self)
                self.button_examples_graph.setEnabled(True)
                self.button_examples_graph.setToolTip(
                    "See some examples of CLARANS graphs G_{k,n} as in the paper."
                )

                # numlocal_clarans LABEL
                self.label_numlocal_clarans = QLabel(self)
                self.label_numlocal_clarans.setText("num_iter:")
                self.label_numlocal_clarans.setToolTip(
                    "The number of local minima obtained (amount of iterations "
                    "for solving the problem)."
                )

                self.line_edit_numlocal_clarans = QLineEdit(self)
                self.line_edit_numlocal_clarans.setText(str(self.numlocal_clarans))

                self.numlocal_clarans_validator = QIntValidator(1, 1000, self)
                self.line_edit_numlocal_clarans.setValidator(
                    self.numlocal_clarans_validator
                )

                # maxneighbors_clarans LABEL
                self.label_maxneighbors_clarans = QLabel(self)
                self.label_maxneighbors_clarans.setText("max_neigh:")
                self.label_maxneighbors_clarans.setToolTip(
                    "The maximum number of neighbors examined. This heavily "
                    "affects runtime"
                )

                self.line_edit_maxneighbors_clarans = QLineEdit(self)
                self.line_edit_maxneighbors_clarans.setText(
                    str(self.maxneighbors_clarans)
                )

                self.maxneighbors_clarans_validator = QIntValidator(1, 1000, self)
                self.line_edit_maxneighbors_clarans.setValidator(
                    self.maxneighbors_clarans_validator
                )

        elif self.name == "BIRCH":
            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # branching_factor LABEL
            self.label_branching_factor = QLabel(self)
            self.label_branching_factor.setText("branch_fact:")
            self.label_branching_factor.setToolTip(
                "The branching factor is the maximum number of successor "
                "that might be contained by each non-leaf node in CF-Tree."
            )

            self.line_edit_branching_factor = QLineEdit(self)
            self.line_edit_branching_factor.setText(str(self.branching_factor))

            self.branching_factor_validator = QIntValidator(2, 10, self)
            self.line_edit_branching_factor.setValidator(
                self.branching_factor_validator
            )

            # max_node_entries LABEL
            self.label_max_node_entries = QLabel(self)
            self.label_max_node_entries.setText("max_node_ent:")
            self.label_max_node_entries.setToolTip(
                "The maximum number of entries that might be contained "
                "by each leaf node in CF-Tree."
            )

            self.line_edit_max_node_entries = QLineEdit(self)
            self.line_edit_max_node_entries.setText(str(self.max_node_entries))

            self.max_node_entries_validator = QIntValidator(1, 10, self)
            self.line_edit_max_node_entries.setValidator(
                self.max_node_entries_validator
            )

            # initial_diameter LABEL
            self.label_initial_diameter = QLabel(self)
            self.label_initial_diameter.setText("init_diam:")
            self.label_initial_diameter.setToolTip(
                "The initial diameter that is used for CF-Tree construction."
            )

            self.line_edit_initial_diameter = QLineEdit(self)
            self.line_edit_initial_diameter.setText(str(self.initial_diameter))

            self.initial_diameter_validator = QDoubleValidator(0, 1000, 4)
            # self.initial_diameter_validator.setNotation(QDoubleValidator.StandardNotation)
            self.line_edit_initial_diameter.setValidator(
                self.initial_diameter_validator
            )

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            # n_clust LABEL
            self.label_n_clust = QLabel(self)
            self.label_n_clust.setText("n_clust:")
            self.label_n_clust.setToolTip(
                "The desired number of clusters to partition the dataset into."
            )

            self.line_edit_n_clust = QLineEdit(self)
            self.line_edit_n_clust.setText(str(self.n_clust))

            self.n_clust_validator = QIntValidator(1, 1000, self)
            self.line_edit_n_clust.setValidator(self.n_clust_validator)

            # knn_cham LABEL
            self.label_knn_cham = QLabel(self)
            self.label_knn_cham.setText("k of KNN:")
            self.label_knn_cham.setToolTip(
                "The number of neighbors to consider when building the KNN-Graph."
            )

            self.line_edit_knn_cham = QLineEdit(self)
            self.line_edit_knn_cham.setText(str(self.knn_cham))

            self.knn_cham_validator = QIntValidator(1, 1000, self)
            self.line_edit_knn_cham.setValidator(self.knn_cham_validator)

            # init_clust_cham LABEL
            self.label_init_clust_cham = QLabel(self)
            self.label_init_clust_cham.setText("init_clust:")
            self.label_init_clust_cham.setToolTip(
                "The number of clusters to reach in the initial phase."
            )

            self.line_edit_init_clust_cham = QLineEdit(self)
            self.line_edit_init_clust_cham.setText(str(self.init_clust_cham))

            self.init_clust_cham_validator = QIntValidator(1, 1000, self)
            self.line_edit_init_clust_cham.setValidator(self.init_clust_cham_validator)

            # alpha_cham LABEL
            self.label_alpha_cham = QLabel(self)
            self.label_alpha_cham.setText("alpha:")
            self.label_alpha_cham.setToolTip("The exponent of relative closeness.")

            self.line_edit_alpha_cham = QLineEdit(self)
            self.line_edit_alpha_cham.setText(str(self.alpha_cham))

            self.alpha_cham_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_alpha_cham.setValidator(self.alpha_cham_validator)

            if self.name == "CHAMELEON2":
                # beta_cham LABEL
                self.label_beta_cham = QLabel(self)
                self.label_beta_cham.setText("beta:")
                self.label_beta_cham.setToolTip(
                    "The exponent of relative connectivity."
                )

                self.line_edit_beta_cham = QLineEdit(self)
                self.line_edit_beta_cham.setText(str(self.beta_cham))

                self.beta_cham_validator = QDoubleValidator(0, 1000, 4, self)
                self.line_edit_beta_cham.setValidator(self.beta_cham_validator)

                # m_fact LABEL
                self.label_m_fact = QLabel(self)
                self.label_m_fact.setText("m_fact:")
                self.label_m_fact.setToolTip(
                    "The weight to assign to single-point clusters."
                )

                self.line_edit_m_fact = QLineEdit(self)
                self.line_edit_m_fact.setText(str(self.m_fact))

                self.m_fact_validator = QIntValidator(0, 1000000, self)
                self.line_edit_m_fact.setValidator(self.m_fact_validator)

        elif self.name == "DENCLUE":
            # sigma_denclue LABEL
            self.label_sigma_denclue = QLabel(self)
            self.label_sigma_denclue.setText("sigma (\u03C3):")
            self.label_sigma_denclue.setToolTip(
                "This parameter determines the influence of a point "
                "in its neighborhood. The higher sigma, the lower the influence."
            )

            self.line_edit_sigma_denclue = QLineEdit(self)
            self.line_edit_sigma_denclue.setText(str(self.sigma_denclue))

            self.sigma_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_sigma_denclue.setValidator(self.sigma_denclue_validator)

            # xi_denclue LABEL
            self.label_xi_denclue = QLabel(self)
            self.label_xi_denclue.setText("xi (\u03BE):")
            self.label_xi_denclue.setToolTip(
                "This parameter determines the minimum density level for "
                "a density attractor to be significant. The higher xi, the less clusters"
                "are obtained."
            )

            self.line_edit_xi_denclue = QLineEdit(self)
            self.line_edit_xi_denclue.setText(str(self.xi_denclue))

            self.xi_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_xi_denclue.setValidator(self.xi_denclue_validator)

            # xi_c_denclue LABEL
            self.label_xi_c_denclue = QLabel(self)
            self.label_xi_c_denclue.setText("xi_c (\u03BE_c) :")
            self.label_xi_c_denclue.setToolTip(
                "This parameter is a second outlier bound to determine which"
                "cubes are highly populated. The lower xi_c, the more highly "
                "populated cubes."
            )

            self.line_edit_xi_c_denclue = QLineEdit(self)
            self.line_edit_xi_c_denclue.setText(str(self.xi_c_denclue))

            self.xi_c_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_xi_c_denclue.setValidator(self.xi_c_denclue_validator)

            # tol_denclue LABEL
            self.label_tol_denclue = QLabel(self)
            self.label_tol_denclue.setText("tol :")
            self.label_tol_denclue.setToolTip(
                "Tolerance for the hill_climbing algorithm."
            )

            self.line_edit_tol_denclue = QLineEdit(self)
            self.line_edit_tol_denclue.setText(str(self.tol_denclue))

            self.tol_denclue_validator = QDoubleValidator(0, 1000, 4, self)
            self.line_edit_tol_denclue.setValidator(self.tol_denclue_validator)

            # prec_denclue LABEL
            self.label_prec_denclue = QLabel(self)
            self.label_prec_denclue.setText("prec :")
            self.label_prec_denclue.setToolTip(
                "Precision for plotting. The higher prec, the more precise the plots "
                "are, but it will take longer for them to be displayed. ALERT: it is "
                "best not to set this over 30."
            )

            self.line_edit_prec_denclue = QLineEdit(self)
            self.line_edit_prec_denclue.setText(str(self.prec_denclue))

            self.prec_denclue_validator = QIntValidator(0, 100, self)
            self.line_edit_prec_denclue.setValidator(self.prec_denclue_validator)

            # 4 checkboxes to choose which plots to display

            # self.checkbox_pop_cubes = QCheckBox("pop cubes")
            # self.checkbox_pop_cubes.setToolTip("Check it to show the plot of populated cubes.")

            self.checkbox_highly_pop_cubes = QCheckBox("highly pop cubes")
            self.checkbox_highly_pop_cubes.setToolTip(
                "Check it to show the picture of highly populated cubes."
            )

            self.checkbox_contour = QCheckBox("contour")
            self.checkbox_contour.setToolTip(
                "Check it to show the countour plot of the influence function."
            )

            self.checkbox_3dplot = QCheckBox("3d plot")
            self.checkbox_3dplot.setToolTip(
                "Check it to show a 3d plot of the influence function."
            )

            self.checkbox_clusters = QCheckBox("clusters")
            self.checkbox_clusters.setToolTip(
                "Check it show a final plot of the clusters found using DENCLUE."
            )

            # button for influence function plot
            self.button_infl_denclue = QPushButton("Influence", self)
            self.button_infl_denclue.setToolTip(
                "Show the influence function value for each point along with a "
                "density-attractors significance threshold determined by xi."
            )

    def log_initialization(self):
        log_list = ["DBSCAN", "CLARA", "PAM", "CLARANS"]
        log_list2 = [
            "OPTICS",
            "AGGLOMERATIVE",
            "BIRCH",
            "CHAMELEON",
            "CHAMELEON2",
            "DENCLUE",
        ]

        if self.name in log_list2:
            if self.name == "OPTICS":
                self.log = QPlainTextEdit("SEED QUEUE")
            elif self.name == "BIRCH":
                self.log = QPlainTextEdit(
                    "{} LOG".format(self.name)
                    + "\n"
                    + "You must have Graphviz installed on your Mac in order for BIRCH to work"
                )
            else:
                self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )

            if self.name != "DENCLUE":
                self.gridlayout.addWidget(self.log, 1, 0)
            elif self.name == "DENCLUE":
                self.log.setFixedWidth(220)
                self.gridlayout.addWidget(self.log, 2, 0, 1, 2)

        elif self.name in log_list:
            self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setGeometry(900, 60, 350, 400)
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )
            self.log.setFixedHeight(335)
            if self.name == "DBSCAN":
                self.gridlayout.addWidget(self.log, 1, 0)
            else:
                self.gridlayout.addWidget(self.log, 1, 1)

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.log = QPlainTextEdit("{} LOG".format(self.name))
            self.log.setStyleSheet(
                """QPlainTextEdit {background-color: #FFF;
                                   color: #000000;
                                   font-family: Courier;}"""
            )
            self.log.setFixedWidth(220)
            self.gridlayout.addWidget(self.log, 1, 0, 1, 2)

    def buttons_groupbox_initialization(self):

        self.groupbox_buttons = QGroupBox("Parameters")

        if self.name != "DENCLUE":
            self.groupbox_buttons.setFixedSize(220, 400)
        elif self.name == "DENCLUE":
            self.groupbox_buttons.setFixedWidth(220)

        if self.name == "CHAMELEON":
            self.groupbox_buttons.setFixedHeight(450)

        if self.name == "CHAMELEON2":
            self.groupbox_buttons.setFixedHeight(500)

        self.gridlayout.addWidget(self.groupbox_buttons, 0, 0)

        self.gridlayout_but = QGridLayout(self.groupbox_buttons)

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)

            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_eps, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_eps, 2, 1)
            self.gridlayout_but.addWidget(self.label_mp, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_mp, 3, 1)

            if self.name == "OPTICS":
                self.gridlayout_but.addWidget(self.label_eps_extr, 4, 0)
                self.gridlayout_but.addWidget(self.line_edit_eps_extr, 4, 1)
                self.gridlayout_but.addWidget(self.button_extract, 5, 1)

            self.gridlayout_but.addWidget(self.button_run, 5, 0)

            self.gridlayout_but.addWidget(self.label_slider, 6, 0)
            self.gridlayout_but.addWidget(self.slider, 6, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

        elif self.name == "AGGLOMERATIVE":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_linkage, 3, 0)
            self.gridlayout_but.addWidget(self.combobox_linkage, 3, 1)

            self.gridlayout_but.addWidget(self.button_run, 4, 0)

            self.gridlayout_but.addWidget(self.label_slider, 5, 0)
            self.gridlayout_but.addWidget(self.slider, 5, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 6, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 6, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 7, 0, 1, 0)

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):
            self.gridlayout_but.addWidget(self.label_ds, 0, 0, 1, 2)
            self.gridlayout_but.addWidget(self.combobox, 0, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_np, 1, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_n_repr, 3, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_n_repr, 3, 2, 1, 2)
            self.gridlayout_but.addWidget(self.label_alpha_cure, 4, 0, 1, 2)
            self.gridlayout_but.addWidget(self.line_edit_alpha_cure, 4, 2, 1, 2)
            if self.name == "LARGE CURE":
                self.gridlayout_but.addWidget(self.label_p_cure, 5, 0)
                self.gridlayout_but.addWidget(self.line_edit_p_cure, 5, 1)
                self.gridlayout_but.addWidget(self.label_q_cure, 5, 2)
                self.gridlayout_but.addWidget(self.line_edit_q_cure, 5, 3)

                self.gridlayout_but.addWidget(self.button_run, 6, 0, 1, 2)

                self.gridlayout_but.addWidget(self.label_slider, 7, 0, 1, 2)
                self.gridlayout_but.addWidget(self.slider, 7, 2, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_gif, 8, 2, 1, 2)
                self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 4)
            elif self.name == "CURE":
                self.gridlayout_but.addWidget(self.button_run, 5, 0, 1, 2)

                self.gridlayout_but.addWidget(self.label_slider, 6, 0, 1, 2)
                self.gridlayout_but.addWidget(self.slider, 6, 2, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0, 1, 2)
                self.gridlayout_but.addWidget(self.checkbox_gif, 7, 2, 1, 2)
                self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 4)

        elif self.name == "CLARA":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)
            self.gridlayout_but.addWidget(self.label_distances_clara, 3, 0)
            self.gridlayout_but.addWidget(self.combobox_distances_clara, 3, 1)

            self.gridlayout_but.addWidget(self.button_run, 4, 0)

            self.gridlayout_but.addWidget(self.label_slider, 5, 0)
            self.gridlayout_but.addWidget(self.slider, 5, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 6, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 6, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 7, 0, 1, 0)

        elif self.name == "PAM":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)

            self.gridlayout_but.addWidget(self.button_run, 3, 0)

            self.gridlayout_but.addWidget(self.label_slider, 4, 0)
            self.gridlayout_but.addWidget(self.slider, 4, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 5, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 5, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 6, 0, 1, 0)

        elif self.name == "CLARANS":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_medoids, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_medoids, 2, 1)
            self.gridlayout_but.addWidget(self.label_numlocal_clarans, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_numlocal_clarans, 3, 1)
            self.gridlayout_but.addWidget(self.label_maxneighbors_clarans, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_maxneighbors_clarans, 4, 1)

            self.gridlayout_but.addWidget(self.button_run, 5, 0)
            self.gridlayout_but.addWidget(self.button_examples_graph, 5, 1)

            self.gridlayout_but.addWidget(self.label_slider, 6, 0)
            self.gridlayout_but.addWidget(self.slider, 6, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 7, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

        elif self.name == "BIRCH":
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_branching_factor, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_branching_factor, 3, 1)
            self.gridlayout_but.addWidget(self.label_max_node_entries, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_max_node_entries, 4, 1)
            self.gridlayout_but.addWidget(self.label_initial_diameter, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_initial_diameter, 5, 1)

            self.gridlayout_but.addWidget(self.button_run, 6, 0)

            self.gridlayout_but.addWidget(self.label_slider, 7, 0)
            self.gridlayout_but.addWidget(self.slider, 7, 1)
            self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0)
            self.gridlayout_but.addWidget(self.checkbox_gif, 8, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 0)

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):
            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_n_clust, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_n_clust, 2, 1)
            self.gridlayout_but.addWidget(self.label_knn_cham, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_knn_cham, 3, 1)
            self.gridlayout_but.addWidget(self.label_init_clust_cham, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_init_clust_cham, 4, 1)
            self.gridlayout_but.addWidget(self.label_alpha_cham, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_alpha_cham, 5, 1)

            if self.name == "CHAMELEON":

                self.gridlayout_but.addWidget(self.button_run, 6, 0)

                self.gridlayout_but.addWidget(self.label_slider, 7, 0)
                self.gridlayout_but.addWidget(self.slider, 7, 1)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 8, 0)
                self.gridlayout_but.addWidget(self.checkbox_gif, 8, 1)
                self.gridlayout_but.addWidget(self.button_delete_pics, 9, 0, 1, 0)

            elif self.name == "CHAMELEON2":
                self.gridlayout_but.addWidget(self.label_beta_cham, 6, 0)
                self.gridlayout_but.addWidget(self.line_edit_beta_cham, 6, 1)
                self.gridlayout_but.addWidget(self.label_m_fact, 7, 0)
                self.gridlayout_but.addWidget(self.line_edit_m_fact, 7, 1)

                self.gridlayout_but.addWidget(self.button_run, 8, 0)

                self.gridlayout_but.addWidget(self.label_slider, 9, 0)
                self.gridlayout_but.addWidget(self.slider, 9, 1)
                self.gridlayout_but.addWidget(self.checkbox_saveimg, 10, 0)
                self.gridlayout_but.addWidget(self.checkbox_gif, 10, 1)
                self.gridlayout_but.addWidget(self.button_delete_pics, 11, 0, 1, 0)

        elif self.name == "DENCLUE":

            self.groupbox_plots_denclue = QGroupBox("Plotting options")
            self.gridlayout.addWidget(self.groupbox_plots_denclue, 1, 0)
            self.groupbox_plots_denclue.setFixedWidth(220)
            self.gridlayout_plot_checkboxes = QGridLayout(self.groupbox_plots_denclue)

            self.gridlayout_but.addWidget(self.label_ds, 0, 0)
            self.gridlayout_but.addWidget(self.combobox, 0, 1)
            self.gridlayout_but.addWidget(self.label_np, 1, 0)
            self.gridlayout_but.addWidget(self.line_edit_np, 1, 1)
            self.gridlayout_but.addWidget(self.label_sigma_denclue, 2, 0)
            self.gridlayout_but.addWidget(self.line_edit_sigma_denclue, 2, 1)
            self.gridlayout_but.addWidget(self.label_xi_denclue, 3, 0)
            self.gridlayout_but.addWidget(self.line_edit_xi_denclue, 3, 1)
            self.gridlayout_but.addWidget(self.label_xi_c_denclue, 4, 0)
            self.gridlayout_but.addWidget(self.line_edit_xi_c_denclue, 4, 1)
            self.gridlayout_but.addWidget(self.label_tol_denclue, 5, 0)
            self.gridlayout_but.addWidget(self.line_edit_tol_denclue, 5, 1)
            self.gridlayout_but.addWidget(self.label_prec_denclue, 6, 0)
            self.gridlayout_but.addWidget(self.line_edit_prec_denclue, 6, 1)

            self.gridlayout_but.addWidget(self.button_run, 7, 0)
            # self.gridlayout_but.addWidget(self.label_slider, 7, 1)
            self.gridlayout_but.addWidget(self.button_delete_pics, 8, 0, 1, 0)

            # self.gridlayout_plot_checkboxes.addWidget(self.checkbox_pop_cubes, 0, 0)
            self.gridlayout_plot_checkboxes.addWidget(
                self.checkbox_highly_pop_cubes, 0, 0
            )
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_contour, 0, 1)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_3dplot, 1, 0)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_clusters, 1, 1)
            self.gridlayout_plot_checkboxes.addWidget(self.checkbox_saveimg, 2, 0)
            self.gridlayout_plot_checkboxes.addWidget(self.button_infl_denclue, 2, 1)

    def checkBoxChangedAction(self, state):
        if Qt.Checked == state:
            self.save_plots = True
            self.checkbox_gif.setEnabled(True)

            try:
                os.mkdir(
                    appctxt.get_resource("Images/")
                    + "/"
                    + "{}_{:02}".format(self.name, self.ind_run)
                )
                # print("new folder")

            except OSError as error:
                pass
                # print(error)
        else:
            self.checkbox_gif.setEnabled(False)
            self.save_plots = False

    def delete_pics(self):

        msg = "Do you really want to delete all PICs and GIFs generated by {} until now?".format(
            self.name
        )
        messagebox_reply = QMessageBox.question(
            self,
            "Images removal",
            msg,
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No,
        )

        if messagebox_reply == QMessageBox.Yes:

            folders = [
                fold
                for fold in os.listdir(appctxt.get_resource("Images/"))
                if fold.startswith("{}".format(self.name))
            ]
            for folder in folders:
                rmtree(appctxt.get_resource("Images/") + "/" + folder)
            self.ind_run = 0
            self.first_run_occurred = False

        elif messagebox_reply == QMessageBox.No:
            return

    def GIFChangedAction(self, state):
        if Qt.Checked == state:
            self.make_gif = True
        else:
            self.make_gif = False

    def generate_GIF(self):

        png_dir = (
            appctxt.get_resource("Images/")
            + "/"
            + "{}_{:02}".format(self.name, self.ind_run)
        )
        images = []
        fig_list = [
            pic
            for pic in os.listdir(png_dir)
            if (pic.startswith("fig")) & ("fin" not in pic)
        ]
        fig_list.sort()
        fin_list = [pic for pic in os.listdir(png_dir) if "graph" in pic]
        fin_list.sort()

        if self.name == "BIRCH":
            graphviz_list = [
                pic
                for pic in os.listdir(png_dir)
                if ("graph" in pic) and (pic.endswith(".png"))
            ]
            graphviz_list.sort()

        if len(fin_list) != 0:

            if (self.name != "LARGE CURE") and (self.name != "BIRCH"):
                list_for_gif = fig_list + [fin_list[-1]]
            elif self.name == "LARGE CURE":
                list_for_gif = fig_list + fin_list
            elif self.name == "BIRCH":
                list_for_gif = fig_list
        else:
            list_for_gif = fig_list

        for file_name in list_for_gif:
            file_path = os.path.join(png_dir, file_name)
            images.append(imread(file_path))

        if int(self.line_edit_np.text()) < 50:
            duration = 0.35
        else:
            duration = 0.25
        mimsave(png_dir + "/movie.gif", images, duration=duration)

        if self.name == "BIRCH":
            images = []
            for file_name in graphviz_list:
                file_path = os.path.join(png_dir, file_name)
                images.append(imread(file_path))

            mimsave(png_dir + "/movie2.gif", images, duration=duration)

    def changedValue(self):
        size = self.slider.sl.value()
        self.delay = size

    def show_error_message(self, check, msg):
        if check[0] != 2:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(msg)
            self.log.appendPlainText("")

        QCoreApplication.processEvents()

    def n_clust_error(self, medoids=False, init_clust=False):

        if medoids is False:

            cond = int(self.line_edit_n_clust.text()) >= int(self.line_edit_np.text())
            text = "clusters"

        else:

            cond = int(self.line_edit_n_medoids.text()) >= int(self.line_edit_np.text())
            text = "medoids"

        if cond == True:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(
                "The number of {} should be less than the number of points.".format(
                    text
                )
            )
            self.log.appendPlainText("")

        if init_clust == True:

            cond_2 = int(self.line_edit_n_clust.text()) >= int(
                self.line_edit_init_clust_cham.text()
            )
            text = "initial clusters"

            if cond_2 == True:

                if self.param_check is True:
                    self.log.clear()

                self.param_check = False
                self.log.appendPlainText("ERROR")
                self.log.appendPlainText("")
                self.log.appendPlainText(
                    "The number of {} should be greater than the "
                    "number of final clusters.".format(text)
                )
                self.log.appendPlainText("")

        QCoreApplication.processEvents()

    def comma_error(self, parameter):

        if parameter.find(",") != -1:

            if self.param_check is True:
                self.log.clear()

            self.param_check = False
            self.log.appendPlainText("ERROR")
            self.log.appendPlainText("")
            self.log.appendPlainText(
                "Using a comma (,) as decimal sepator is not accepted, use a dot (.) "
                "instead"
            )
            self.log.appendPlainText("")

    def verify_input_parameters(self, extract=False):

        self.param_check = True
        check_n_points = self.n_points_validator.validate(self.line_edit_np.text(), 0)
        self.show_error_message(
            check_n_points,
            "The parameter n_points must be an integer and lie between {0}"
            " and {1}.".format(5, 200),
        )

        if (self.name == "OPTICS") or (self.name == "DBSCAN"):

            if extract is False:
                check_eps = self.eps_validator.validate(self.line_edit_eps.text(), 0)
                check_mp = self.mp_validator.validate(self.line_edit_mp.text(), 0)

                self.show_error_message(
                    check_eps,
                    "The parameter eps must lie between {0} and {1}, and can have a maximum of"
                    " {2} decimal places.".format(0, 1000, 4),
                )
                self.show_error_message(
                    check_mp,
                    "The parameter minPTS must be an integer and lie "
                    "between {0} and {1}.".format(1, 200),
                )

                self.comma_error(parameter=self.line_edit_eps.text())

            if self.name == "OPTICS":
                check_eps_extr = self.eps_extr_validator.validate(
                    self.line_edit_eps_extr.text(), 0
                )

                self.show_error_message(
                    check_eps_extr,
                    "The parameter eps_extr must lie between {0} and {1}, and can "
                    "have a maximum of {2} decimal places.".format(0, 1000, 4),
                )

                self.comma_error(parameter=self.line_edit_eps_extr.text())

        elif self.name == "AGGLOMERATIVE":

            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            # self.comma_error(parameter=self.line_edit_n_clust.text())
            try:
                self.n_clust_error()
            except:
                pass

        elif (self.name == "CURE") or (self.name == "LARGE CURE"):

            check_n_repr = self.n_repr_validator.validate(
                self.line_edit_n_repr.text(), 0
            )
            check_alpha_cure = self.alpha_cure_validator.validate(
                self.line_edit_alpha_cure.text(), 0
            )
            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            self.show_error_message(
                check_n_repr,
                "The parameter n_repr must be an integer and lie between {0}"
                " and {1}.".format(1, 1000),
            )
            self.show_error_message(
                check_alpha_cure,
                "The parameter alpha must lie between {0} and {1}, and can "
                "have a maximum of {2} decimal places.".format(0, 1, 4),
            )

            self.comma_error(parameter=self.line_edit_alpha_cure.text())
            try:
                self.n_clust_error()
            except:
                pass

            if self.name == "LARGE CURE":
                check_p_cure = self.p_cure_validator.validate(
                    self.line_edit_p_cure.text(), 0
                )
                check_q_cure = self.q_cure_validator.validate(
                    self.line_edit_q_cure.text(), 0
                )
                self.show_error_message(
                    check_p_cure,
                    "The parameter p can be an {0}, {1} or {2}.".format(2, 3, 4),
                )
                self.show_error_message(
                    check_q_cure,
                    "The parameter q must be an integer and lie between {0}"
                    " and {1}.".format(2, 100),
                )

        elif (self.name == "CLARA") or (self.name == "PAM") or (self.name == "CLARANS"):
            check_n_medoids = self.n_medoids_validator.validate(
                self.line_edit_n_medoids.text(), 0
            )

            self.show_error_message(
                check_n_medoids,
                "The parameter n_medoids must be an integer and lie between "
                "{0} and {1}".format(2, 1000),
            )

            try:
                self.n_clust_error(medoids=True)
            except:
                pass

            if self.name == "CLARANS":
                check_numlocal_clarans = self.numlocal_clarans_validator.validate(
                    self.line_edit_numlocal_clarans.text(), 0
                )
                check_maxneighbors_clarans = self.maxneighbors_clarans_validator.validate(
                    self.line_edit_maxneighbors_clarans.text(), 0
                )

                self.show_error_message(
                    check_numlocal_clarans,
                    "The parameter num_iter must be an integer and lie between "
                    "{0} and {1}".format(1, 1000),
                )
                self.show_error_message(
                    check_maxneighbors_clarans,
                    "The parameter max_neigh must be an integer and lie between "
                    "{0} and {1}".format(1, 1000),
                )

        elif self.name == "BIRCH":
            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )
            check_branching_factor = self.branching_factor_validator.validate(
                self.line_edit_branching_factor.text(), 0
            )
            check_max_node_entries = self.max_node_entries_validator.validate(
                self.line_edit_max_node_entries.text(), 0
            )
            check_initial_diameter = self.initial_diameter_validator.validate(
                self.line_edit_initial_diameter.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )

            self.show_error_message(
                check_branching_factor,
                "The parameter branch_fact must be an integer and lie between "
                "{0} and {1}".format(2, 10),
            )

            self.show_error_message(
                check_max_node_entries,
                "The parameter max_nod_ent must be an integer and lie between "
                "{0} and {1}".format(1, 10),
            )

            self.show_error_message(
                check_initial_diameter,
                "The parameter init_diam must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )

            self.comma_error(parameter=self.line_edit_initial_diameter.text())

        elif (self.name == "CHAMELEON") or (self.name == "CHAMELEON2"):

            check_n_clust = self.n_clust_validator.validate(
                self.line_edit_n_clust.text(), 0
            )
            check_knn_cham = self.knn_cham_validator.validate(
                self.line_edit_knn_cham.text(), 0
            )
            check_init_clust_cham = self.init_clust_cham_validator.validate(
                self.line_edit_init_clust_cham.text(), 0
            )
            check_alpha_cham = self.alpha_cham_validator.validate(
                self.line_edit_alpha_cham.text(), 0
            )

            self.show_error_message(
                check_n_clust,
                "The parameter n_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_knn_cham,
                "The parameter k of Knn must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_init_clust_cham,
                "The parameter init_clust must be an integer and lie between "
                "{0} and {1}".format(1, 1000),
            )
            self.show_error_message(
                check_alpha_cham,
                "The parameter alpha must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )

            self.comma_error(parameter=self.line_edit_alpha_cham.text())
            try:
                self.n_clust_error(init_clust=True)
            except:
                pass

            if self.name == "CHAMELEON2":
                check_beta_cham = self.beta_cham_validator.validate(
                    self.line_edit_beta_cham.text(), 0
                )
                check_m_fact = self.m_fact_validator.validate(
                    self.line_edit_m_fact.text(), 0
                )

                self.show_error_message(
                    check_beta_cham,
                    "The parameter beta must lie between {0} and {1}, and can have a maximum of"
                    " {2} decimal places.".format(0, 1000, 4),
                )
                self.show_error_message(
                    check_m_fact,
                    "The parameter m_fact must be an integer and lie between "
                    "{0} and {1}".format(1, 1000000),
                )
                self.comma_error(parameter=self.line_edit_beta_cham.text())

        elif self.name == "DENCLUE":

            check_sigma_denclue = self.sigma_denclue_validator.validate(
                self.line_edit_sigma_denclue.text(), 0
            )
            check_xi_denclue = self.xi_denclue_validator.validate(
                self.line_edit_xi_denclue.text(), 0
            )
            check_xi_c_denclue = self.xi_c_denclue_validator.validate(
                self.line_edit_xi_c_denclue.text(), 0
            )
            check_tol_denclue = self.tol_denclue_validator.validate(
                self.line_edit_tol_denclue.text(), 0
            )
            check_prec_denclue = self.prec_denclue_validator.validate(
                self.line_edit_prec_denclue.text(), 0
            )

            self.show_error_message(
                check_sigma_denclue,
                "The parameter sigma must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_xi_denclue,
                "The parameter xi must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_xi_c_denclue,
                "The parameter xi_c must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_tol_denclue,
                "The parameter tol must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 1000, 4),
            )
            self.show_error_message(
                check_prec_denclue,
                "The parameter prec must lie between {0} and {1}, and can have a maximum of"
                " {2} decimal places.".format(0, 100, 4),
            )

            self.comma_error(parameter=self.line_edit_sigma_denclue.text())
            self.comma_error(parameter=self.line_edit_xi_denclue.text())
            self.comma_error(parameter=self.line_edit_xi_c_denclue.text())
            self.comma_error(parameter=self.line_edit_tol_denclue.text())
            self.comma_error(parameter=self.line_edit_prec_denclue.text())

    def SetWindows(self, number, first_run_boolean):
        """This is used for LARGE_CURE clustering algorithm: it serves the purpose of creating the right amount
        of subplots to display all the partitions, according to the user's input of p, which is here called number.

        :param number: how many subplots to do (can be 2, 3 or 4).
        :param first_run_boolean: if True, delete previous widgets (plots) before replotting."""

        self.ax1 = None
        self.ax2 = None
        self.ax3 = None
        self.ax4 = None

        self.canvas_3 = None
        self.canvas_4 = None

        self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax1 = self.canvas_up.figure.subplots()
        self.ax1.set_xticks([], [])
        self.ax1.set_yticks([], [])

        self.canvas_2 = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax2 = self.canvas_2.figure.subplots()
        self.ax2.set_xticks([], [])
        self.ax2.set_yticks([], [])

        if number >= 3:
            self.canvas_3 = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax3 = self.canvas_3.figure.subplots()
            self.ax3.set_xticks([], [])
            self.ax3.set_yticks([], [])
        if number == 4:
            self.canvas_4 = FigureCanvas(Figure(figsize=(12, 5)))
            self.ax4 = self.canvas_4.figure.subplots()
            self.ax4.set_xticks([], [])
            self.ax4.set_yticks([], [])

        # this removes all widgets (plots) before replotting
        if first_run_boolean is True:
            for i in reversed(range(self.gridlayout_plots.count())):
                self.gridlayout_plots.itemAt(i).widget().setParent(None)

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)

        if number == 2:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
            self.gridlayout_plots.addWidget(self.canvas_2, 1, 0)

        elif number == 3:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 1)
            self.gridlayout_plots.addWidget(self.canvas_2, 0, 2)
            self.gridlayout_plots.addWidget(self.canvas_3, 0, 3)

        elif number == 4:
            self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
            self.gridlayout_plots.addWidget(self.canvas_2, 0, 1)
            self.gridlayout_plots.addWidget(self.canvas_3, 1, 0)
            self.gridlayout_plots.addWidget(self.canvas_4, 1, 1)

    def SetWindowsDENCLUE(self, pic_list, first_run_boolean):
        """ Analogous of SetWindows but for DENCLUE algorithm."""

        self.canvas_list = []
        self.axes_list = []
        for i in range(4):
            self.canvas_list.append(FigureCanvas(Figure(figsize=(14, 6))))
            if i == 2:
                self.axes_list.append(
                    self.canvas_list[i].figure.add_subplot(111, projection="3d")
                )
            else:
                self.axes_list.append(self.canvas_list[i].figure.subplots())

            self.axes_list[i].set_xticks([], [])
            self.axes_list[i].set_yticks([], [])

        self.axes_list[0].set_title("Highly populated cubes")
        self.axes_list[1].set_title("Scatterplot with Countour plot")
        self.axes_list[2].set_title("3D surface with 2D contour plot projections")
        self.axes_list[3].set_title("DENCLUE clusters")

        canvas_list = self.canvas_list

        if first_run_boolean is True:
            for i in reversed(range(self.gridlayout_plots.count())):
                self.gridlayout_plots.itemAt(i).widget().setParent(None)

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)

        pic_indexes = [i for i, j in enumerate(pic_list) if j == 1]

        if np.sum(pic_list) == 1:
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)

        elif np.sum(pic_list) == 2:
            if 2 in pic_indexes:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 0, 1)
            else:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)

        elif np.sum(pic_list) == 3:
            if 2 in pic_indexes:
                if 3 in pic_indexes:
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[-1]], 1, 0)
                    # 2 outside
                else:
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                    self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
                    # 2 outside
            else:
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
                self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
                # 3 outside

        elif np.sum(pic_list) == 4:
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[0]], 0, 0)
            self.gridlayout_plots.addWidget(canvas_list[pic_indexes[1]], 1, 0)
            # 2 and 3 outside

    def SetWindowsCHAMELEON(self):

        self.canvas_up = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax1 = self.canvas_up.figure.subplots()
        self.ax1.set_xticks([], [])
        self.ax1.set_yticks([], [])
        self.ax1.set_title(self.name + " Graph Clustering")

        self.canvas_down = FigureCanvas(Figure(figsize=(12, 5)))
        self.ax = self.canvas_down.figure.subplots()
        self.ax.set_xticks([], [])
        self.ax.set_yticks([], [])
        self.ax.set_title(self.name + " Merging")

        self.gridlayout_plots = QGridLayout()
        self.gridlayout.addLayout(self.gridlayout_plots, 0, 1, 3, 2)
        self.gridlayout_plots.addWidget(self.canvas_up, 0, 0)
        self.gridlayout_plots.addWidget(self.canvas_down, 1, 0)


class GraphWindow(QMainWindow):
    def __init__(self, example_index):
        super().__init__()

        self.setWindowTitle("Graph example {}".format(example_index + 1))
        self.setGeometry(300, 200, 500, 400)
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        lay = QVBoxLayout(self.central_widget)

        self.label_graphviz = QLabel(self)
        self.label_graphviz.setFixedSize(500, 400)
        pixmap = QPixmap(
            appctxt.get_resource("Images/")
            + "/"
            + "ClaransGraphExamples/graph_{:02}.png".format(example_index)
        )
        self.label_graphviz.setScaledContents(True)
        self.label_graphviz.setPixmap(pixmap)

        lay.addWidget(self.label_graphviz)
        self.show()


class FinalStepWindow(QMainWindow):
    def __init__(self, canvas, window_title="Final Step"):
        super().__init__()
        self.setWindowTitle(window_title)
        self.setGeometry(300, 200, 1000, 400)

        self.setCentralWidget(canvas)
        canvas.draw()
# todo: PARAMETERS REGULARIZATION mettere a posto # otherwise Validators do not work properly # upper plot # lower plot # influence plot for DENCLUE # parameters initialization # this is used to account for previously created folders in Images to set the self.ind_run correctly # fold_dir = appctxt.get_resource("Images/") + '/' + '' # grid where the two pictures, the log and the button box are inserted (row,column) # START BUTTON # SLIDER # EXTRACT BUTTON # CHECKBOX for saving images # CHECKBOX for generating GIF # BUTTON for removing generated pics and gifs # n_points LABEL # dataset LABEL # COMBOBOX of datasets # labels initialization # LOG # buttons in GROUPBOX (upper left corner) # eps LABEL # minPTS LABEL # eps_extr LABEL # n_clust LABEL # linkage method LABEL # COMBOBOX of linkage methods # n_clust LABEL # n_repr LABEL # alpha_cure LABEL # self.alpha_cure_validator.setNotation(QDoubleValidator.StandardNotation) # p_cure LABEL # q_cure LABEL # n_medoids LABEL # distance LABEL # COMBOBOX of possible distances to use # self.combobox_distances_clara.addItem("cosine") # graph examples BUTTON # numlocal_clarans LABEL # maxneighbors_clarans LABEL # n_clust LABEL # branching_factor LABEL # max_node_entries LABEL # initial_diameter LABEL # self.initial_diameter_validator.setNotation(QDoubleValidator.StandardNotation) # n_clust LABEL # knn_cham LABEL # init_clust_cham LABEL # alpha_cham LABEL # beta_cham LABEL # m_fact LABEL # sigma_denclue LABEL # xi_denclue LABEL # xi_c_denclue LABEL # tol_denclue LABEL # prec_denclue LABEL # 4 checkboxes to choose which plots to display # self.checkbox_pop_cubes = QCheckBox("pop cubes") # self.checkbox_pop_cubes.setToolTip("Check it to show the plot of populated cubes.") # button for influence function plot QPlainTextEdit {background-color: #FFF;                                    color: #000000;                                    font-family: Courier;} QPlainTextEdit {background-color: #FFF;                                    color: #000000;                                    font-family: Courier;} QPlainTextEdit {background-color: #FFF;                                    color: #000000;                                    font-family: Courier;} # self.gridlayout_but.addWidget(self.label_slider, 7, 1) # self.gridlayout_plot_checkboxes.addWidget(self.checkbox_pop_cubes, 0, 0) # print("new folder") # print(error) # self.comma_error(parameter=self.line_edit_n_clust.text()) This is used for LARGE_CURE clustering algorithm: it serves the purpose of creating the right amount         of subplots to display all the partitions, according to the user's input of p, which is here called number.          :param number: how many subplots to do (can be 2, 3 or 4).         :param first_run_boolean: if True, delete previous widgets (plots) before replotting. # this removes all widgets (plots) before replotting Analogous of SetWindows but for DENCLUE algorithm. # 2 outside # 2 outside # 3 outside # 2 and 3 outside