# -*- coding: utf-8 -*-
"""
/***************************************************************************
 smart_map
                                 A QGIS plugin
 Interpolation using Kriging and Machine Learning and generate Management Zones for a set of soil samples
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2018-08-15
        git sha              : $Format:%H$
        copyright            : (C) 2018 by Gustavo Willam Pereira (IFSUDESTE-MG)/Domingos Sárvio Magalhães Valente (UFV)/
		                                   Daniel Marçal de Queiroz (UFV)/Andre Luiz de Freitas Coelho (UFV)/
                                           Sandro Manuel Carmelino Hurtado (UFU)
        email                : gustavowillam@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

from qgis.PyQt import QtCore, QtWidgets, QtGui 
from qgis.PyQt.QtCore import QTranslator, QCoreApplication, QVariant #, QSettings, qVersion
from qgis.PyQt.QtWidgets import QAction, QFileDialog, QMessageBox, QTableWidgetItem, QProgressDialog
from qgis.PyQt.QtGui import QIcon, QPixmap, QColor, QBrush 

from qgis.core import QgsProject             #get the directory for project QGIS  
from qgis.core import QgsProcessingFeedback  #generate LayerRaster Clipped 
from qgis.core import QgsVectorFileWriter    #Convert  .shp em .csv   ou  .csv  em .shp 
from qgis.core import QgsVectorLayer         #Create  VetorLayer   (.shp)
from qgis.core import QgsCoordinateReferenceSystem, QgsFields, QgsPointXY, QgsGeometry, QgsField, QgsWkbTypes, QgsFeature
from qgis.core import QgsMapLayerProxyModel, QgsMapLayerType, QgsLayerTreeLayer, QgsRasterLayer #Register VectorLayer no Qgis 
from qgis.core import QgsColorRampShader, QgsSingleBandPseudoColorRenderer, QgsRasterBandStats, QgsRasterShader, QgsStyle

import qgis.utils                            #check qgis version  

import processing
from processing.core.Processing import Processing
Processing.initialize()

from qgis.utils import plugins


#Initialize Qt resources from file resources.py
from . import resources

#import resources 
#from .resources import *


#Import the code for the dialog
from .Smart_Map_Dialog import smart_mapDialog
from .Smart_Map_About  import smart_mapAbout


import os, os.path
from os.path import expanduser
import re
import time             
import subprocess          
import math 
import platform

system = platform.system()  #[Windows, Linux, Darwin]

if system != 'Darwin':  #PIL do not is install in MacOS  
    from PIL import Image  


import matplotlib.path as mplPath 
import matplotlib.pyplot as plt1  #plot map of points Limite Area 
import matplotlib.pyplot as plt2  #plot the semivariogram 
import matplotlib.pyplot as plt3  #plot Map Interpolated (OK / SVM)
#import matplotlib.pyplot as plt4  #plot Map Interpolated (OK-SD)
import matplotlib.pyplot as plt5  #plot Grafic of Cross Validation (OK / SVM)
import matplotlib.pyplot as plt6  #plot Grafic of Number Ideal of Class - Performance Fuzzy Index (FPI), Normalised Classification Entropy (NCE)
import matplotlib.pyplot as plt7  #plot Management Zones

from scipy import spatial                                  #to calculate IDW com cKDTree.query, KDTree.query_ball_point


#import the code for the Utilities 
from .utils import install_deps                            #Install deps on QGIS: sklearn, skfuzzy, pysal 

import numpy as np
import pandas as pd 
#import sklearn 

from .utils import functions                               #Utility functions -> file functions.py 





#file semivariogram.py  (new version, with use of class) -> to generate semivariogram (Model, Range, Sill, Nugget)  
from .krig import semivariogram                                                 

#arquivo kriging.py     (new version, with use of class) -> to generate Kriging DAGAPy 
from .krig import kriging 


from sklearn import svm                                    #Import the model to use Support Vector Machine

from sklearn.model_selection import train_test_split       #Using Skicit-learn to split data into training and testing sets

from sklearn.preprocessing import scale                    #to normalize the data of different attributes to generate Management Zones  

from sklearn.preprocessing import StandardScaler           #to normalize the data of different attributes to generate ML with SVM   

#import skfuzzy as fuzz                                    #to define management zones using fuzzy-K-means
from .skfuzzy.cluster import _cmeans



'''
raster_value('Estatisticas_GO_OK_OK_Grid_Predictions_K_38_6d530038_b366_4829_8c4d_5cc9d87aff10', 1, make_point($x, $y))
pandas, scikit-learn, scikit-fuzzy, pysal, scikit-optimize, pyKrige do not work in the QGIS plugin.   
have to install from the OSGEO4W-shell as an administrator
In cmd of OSGEO4W- shell go to folder C:\Program Files\QGIS 3.10\apps\python37\

type 
  
python -m pip install pandas          // to install pandas    1.0.3        #qgis3
python -m pip install scikit-learn    // to install sklearn   0.22.2       #qgis3  //dependence of scipy 1.4.1 
python -m pip install scikit-fuzzy    // to install scikit-fuzzy 0.4.2.    #to generate management zones using fuzzy-k-means, from interpolated maps
python -m pip install pysal==2.0      // to calculate Index of Moran       #pysal 2.2  error during installation


if you install pip in the OSGEO4W-shell, the installation of libraries can be done via pip command
  
type: pip install pandas               // to install pandas        
type: pip install scikit-learn         // to install scikit-learn    
type: pip install scikit-fuzzy         // to install scikit-fuzzy 
type: pip install pysal==2.0           // to install pysal -> Calculate Índex of Moran 
'''



# Handle high resolution displays:
if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
   QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
   
if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'):
   QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)




class smart_map:
    """QGIS Plugin Implementation."""

    
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgisInterface
        """


        #Save reference to the QGIS interface
        self.iface = iface

        #initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        
        '''
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir,  'i18n',  'smart_map_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        '''

        f = open(os.path.join(self.plugin_dir, 'i18n', 'language.txt'), 'r')        
        self.language = f.read()
        f.close()     

        if self.language == 'Portuguese': #Plugin is configurated to Portuguese 
            
            locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_en_to_pt.qm')

        else:                             #Plugin is configurated to English
            
            locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_pt_to_en.qm')


        if os.path.exists(locale_path):
 
            self.translator = QTranslator()
            self.translator.load(locale_path)              
            QCoreApplication.installTranslator(self.translator)


                             
        # Create the dialog (after translation) and keep reference
        self.dlg = smart_mapDialog()
                
        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Smart-Map')

        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'Smart-Map')
        self.toolbar.setObjectName(u'Smart-Map')

        # Check if plugin was started the first time in current QGIS session  
        # Must be set in run() to survive plugin reloads  
        self.first_start = True
        self.Index_LayerAtual  = -1         #Index_LayerCurrent starts with a negative value -> was not defined at the beginning of the program

        
    def closeEvent(self, event):

        
        close = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr('Deseja realmente sair?'), QMessageBox.Yes | QMessageBox.No)

        if close == QMessageBox.Yes:
            
            try: 
                self.dlg.mMapLayerComboBox.currentIndexChanged.disconnect()    #desconecta event of combobox select Layer Qgis in Atributte Table
            except TypeError:
                pass  # Ignore the error if no connections exist               

          
           
            if self.language == 'Portuguese': #Plugin is configurated to Portuguese 
                
                locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_en_to_pt.qm')

            else: #Plugin is configurated to English
                
                locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_pt_to_en.qm')
       
            if os.path.exists(locale_path):
     
                self.translator = QTranslator()
                self.translator.load(locale_path)              
                QCoreApplication.installTranslator(self.translator)
            
            event.accept()
                
        else:
            event.ignore()        
       
        
    #noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """

        #to generate file .ts using GUI 
        #C:\ProgramData\Anaconda3\Library\bin>pylupdate5 Smart_Map_dialog.ui -ts Smart_Map_dialog.ts

        #to generate file  .qm using file .ts 
        #C:\ProgramData\Anaconda3\Library\bin>lrelease smart_map_pt_to_en.ts            


        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate("smart_mapDialogBase", message)



    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)

        return action


    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        self.icon_path = ':/plugins/Smart_Map/icon.png'
        
        self.add_action(
            self.icon_path,
            text=self.tr(u'Smart-Map'),
            callback=self.run,
            parent=self.iface.mainWindow())
      

    def unload(self):
        
        
        #if 'sklearn' in sys.modules:
        #    del sys.modules["sklearn"]
		
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&Smart-Map'), action)
            self.iface.removeToolBarIcon(action)

        # remove the toolbar
        del self.toolbar
              

    def run(self):
        """Run method that performs all the real work"""

        #check if plugin is running 
        isrunning = plugins["Smart_Map"]
        if (isrunning.dlg):
          if isrunning.dlg.isVisible():
             isrunning.dlg.activateWindow()
             return
 

        self.path_absolute = QgsProject.instance().readPath("./")  

        if self.path_absolute == './':  #there is no open QGIS project 

            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Não existe nenhum projeto QGIS aberto. Abra um projeto QGIS.') + '\n' + self.tr('Ou save o projeto atual antes de executar o plugin Smart-Map.'))
            msg_box.exec_()

        else: 
        
            
            if self.first_start == False:  #plugin sendo executado pela segunda vez    
               self.dlg = smart_mapDialog()
    
    
            if self.first_start == True:   #plugin running second time 
               self.first_start = False  
            
    
            # initialize plugin directory
            self.plugin_dir = os.path.dirname(__file__)
    
            pixmap_BRA = QPixmap(os.path.join(self.plugin_dir, 'icon_bra.png'))            
            self.dlg.label_language_PT.setPixmap(pixmap_BRA)
            self.dlg.label_language_PT.setScaledContents(True)
            self.dlg.label_language_PT.show()
    
            pixmap_USA = QPixmap(os.path.join(self.plugin_dir, 'icon_usa.png'))            
            self.dlg.label_language_USA.setPixmap(pixmap_USA)
            self.dlg.label_language_USA.setScaledContents(True)
            self.dlg.label_language_USA.show()


            #control number of executions of plugin 
            if os.path.isfile(os.path.join(self.plugin_dir, 'utils', 'execute_number.txt')): 
                f = open(os.path.join(self.plugin_dir, 'utils', 'execute_number.txt'), 'r')        
                exec_number = f.read()
                exec_number = int(exec_number) + 1 
                f.close()     
            else: 
                f = open(os.path.join(self.plugin_dir, 'utils', 'execute_number.txt'), 'w')        
                exec_number = 1    
                f.write(str(exec_number))          
                f.close()             

            
            #print('execute number: ', exec_number)
            f = open(os.path.join(self.plugin_dir, 'utils', 'execute_number.txt'), 'w')        
            f.write(str(exec_number))          
            f.close()             

           
            #read language of plugin 
            f = open(os.path.join(self.plugin_dir, 'i18n', 'language.txt'), 'r')            
            self.language = f.read()
            f.close()     
    
            if self.language == 'Portuguese':   #Plugin is configurated to Portuguese 
                
                locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_en_to_pt.qm')

            else:                               #Plugin is configurated to English
                
                locale_path = os.path.join(self.plugin_dir, 'i18n', 'smart_map_pt_to_en.qm')
    
    
            if os.path.exists(locale_path):
     
                self.translator = QTranslator()
                self.translator.load(locale_path)              
                QCoreApplication.installTranslator(self.translator)
    
                
            self.dlg.closeEvent = self.closeEvent                                                                       #closing the plugin on the button 'x' 
    
            self.dlg.setWindowFlag(QtCore.Qt.WindowMinimizeButtonHint, True)                                            #display option to minimize   QDialog
            self.dlg.setFixedSize(self.dlg.size())                                                                      #fix interface size           QDialog 
            self.dlg.setWindowIcon(QtGui.QIcon(self.icon_path))


			###################################################################
            #Main Tab            
            self.dlg.label_language_PT.mousePressEvent = self.label_language_PT_clicked
            self.dlg.label_language_USA.mousePressEvent = self.label_language_USA_clicked
            self.dlg.label_About.mousePressEvent = self.label_About_clicked


			###################################################################    
            #Attribute Table tab 
            self.dlg.pushButton_File_Save.clicked.connect(self.pushButton_File_Save_clicked)                            
            self.dlg.mMapLayerComboBox.currentIndexChanged.connect(self.mMapLayerComboBox_changed)
            self.dlg.pushButton_ImportQGIS.clicked.connect(self.pushButton_ImportQGIS_clicked)                          
            self.dlg.label_CRS_Layer.hide() 
            
            self.dlg.checkBox_Qgis_Raster.clicked.connect(self.checkBox_Qgis_Raster_clicked)  
            self.dlg.checkBox_Krigagem_Std_Desv.clicked.connect(self.checkBox_Krigagem_Std_Desv_clicked)                        
            self.dlg.checkBox_Qgis_Vector_Points.clicked.connect(self.checkBox_Qgis_Vector_Points_clicked)                        
            self.dlg.checkBox_Qgis_Vector_Polygons.clicked.connect(self.checkBox_Qgis_Vector_Polygons_clicked)                        



			###################################################################
            #Grid tab

            #hide the components that show the vertices (points) of the contour polygon 
            self.dlg.label_CordX_AreaCont.hide()
            self.dlg.label_CordY_AreaCont.hide()
            self.dlg.comboBox_CordX_AreaCont.hide()
            self.dlg.comboBox_CordY_AreaCont.hide()
            self.dlg.datatable_limite.hide()

            
            self.dlg.checkBox_Area_Contorno.clicked.connect(self.checkBox_Area_Contorno_clicked)                        
            self.dlg.mMapLayerComboBox_AreaCont.currentIndexChanged.connect(self.mMapLayerComboBox_AreaCont_changed)
            self.dlg.pushButton_Area_Contorno.clicked.connect(self.pushButton_Area_Contorno_clicked)                    

            self.dlg.SpinBox_Pixel_Size_X.valueChanged.connect(self.SpinBox_Pixel_Size_X_changed)  
            self.dlg.SpinBox_Pixel_Size_Y.valueChanged.connect(self.SpinBox_Pixel_Size_Y_changed)  

            self.dlg.lineEdit_XMin.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_XMin.editingFinished.connect(self.lineEdit_XMin_editingFinished)  

            self.dlg.lineEdit_XMax.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_XMax.editingFinished.connect(self.lineEdit_XMax_editingFinished)  

            self.dlg.lineEdit_YMin.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_YMin.editingFinished.connect(self.lineEdit_YMin_editingFinished)  

            self.dlg.lineEdit_YMax.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_YMax.editingFinished.connect(self.lineEdit_YMax_editingFinished)  
    
            self.dlg.label_pontos_limite.mousePressEvent = self.label_pontos_limite_clicked
    
    
			###################################################################
            #tab Interpolation -> Kriging
            self.dlg.datatable_semivariogramas.doubleClicked.connect(self.datatable_semivariogramas_doubleClicked)
            self.dlg.datatable_semivariogramas.itemClicked.connect(  self.datatable_semivariogramas_checkbox_clicked)    

          
            self.dlg.pushButton_VariogramaReset.clicked.connect(self.pushButton_VariogramaReset_clicked)                   
            self.dlg.pushButton_VariogramaAjust.clicked.connect(self.pushButton_VariogramaAjust_clicked)                
            self.dlg.pushButton_VariogramaSave.clicked.connect(self.pushButton_VariogramaSave_clicked)                  
            
            self.dlg.lineEdit_OK_DMax.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_OK_DMax.editingFinished.connect(self.lineEdit_OK_DMax_EditingFinished)  
            
            self.dlg.lineEdit_OK_lags_dist.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_OK_lags_dist.editingFinished.connect(self.lineEdit_OK_lags_dist_EditingFinished)  

            self.dlg.lineEdit_Nugget.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))
            self.dlg.lineEdit_Nugget.editingFinished.connect(self.lineEdit_Nugget_EditingFinished)  

            self.dlg.lineEdit_Sill.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))           
            self.dlg.lineEdit_Sill.editingFinished.connect(self.lineEdit_Sill_EditingFinished)  

            self.dlg.lineEdit_Range.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))           
            self.dlg.lineEdit_Range.editingFinished.connect(self.lineEdit_Range_EditingFinished)  

            self.dlg.lineEdit_OK_VBNumMax.setValidator(QtGui.QIntValidator())           
            self.dlg.lineEdit_OK_VBNumMax.editingFinished.connect(self.lineEdit_OK_VBNumMax_EditingFinished)  

            self.dlg.lineEdit_OK_VBRaio.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))           
            self.dlg.lineEdit_OK_VBRaio.editingFinished.connect(self.lineEdit_OK_VBRaio_EditingFinished)  

            self.dlg.checkBox_Krigagem_Alcance.clicked.connect(self.checkBox_Krigagem_Alcance_clicked)                  
    

            self.dlg.comboBox_Modelo.currentIndexChanged.connect(self.comboBox_Modelo_changed)                          
    
    
            self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)            
            self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)
            self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)
    
            self.dlg.pushButton_Krigagem.clicked.connect(self.pushButton_Krigagem_clicked)                              
            self.dlg.pushButton_Krigagem_All_Variables.clicked.connect(self.pushButton_Krigagem_All_Variables_clicked)  
            self.dlg.pushButton_Validacao_Cruzada_OK.clicked.connect(self.pushButton_Validacao_Cruzada_OK_clicked)      
    
            self.dlg.label_Variograma.mousePressEvent = self.label_Variograma_clicked
            self.dlg.label_Krigagem.mousePressEvent = self.label_Krigagem_clicked
            self.dlg.label_validacao_cruzada_OK.mousePressEvent = self.label_validacao_cruzada_OK_clicked


            self.dlg.datatable_validacao_cruzada_OK.doubleClicked.connect(self.datatable_validacao_cruzada_OK_doubleClicked)
            self.dlg.datatable_pontos_interpolados_OK.doubleClicked.connect(self.datatable_pontos_interpolados_OK_doubleClicked)
    
    
			###################################################################  
            #tab SVM 
            self.dlg.mMapLayerComboBox_DenseLayer.currentIndexChanged.connect(self.mMapLayerComboBox_DenseLayer_changed)
            self.dlg.comboBox_SVM_Fonte.currentIndexChanged.connect(self.comboBox_SVM_Fonte_changed)                    
            self.dlg.checkBox_Moran.clicked.connect(self.checkBox_Moran_clicked)                                        
            self.dlg.checkBox_RFE.clicked.connect(self.checkBox_RFE_clicked)                                            

            #self.dlg.tabWidget_Interpolacao_SVM.setTabEnabled(1,False)        #tab Test_Features                                           
            #self.dlg.tabWidget_Interpolacao_SVM.setStyleSheet("QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} ")        

            self.dlg.lineEdit_SVM_VBNumMax.setValidator(QtGui.QIntValidator())           
            self.dlg.lineEdit_SVM_VBNumMax.editingFinished.connect(self.lineEdit_SVM_VBNumMax_EditingFinished)          
    
            self.dlg.lineEdit_SVM_VBRaio.setValidator(QtGui.QDoubleValidator(notation=QtGui.QDoubleValidator.StandardNotation))           
            self.dlg.lineEdit_SVM_VBRaio.editingFinished.connect(self.lineEdit_SVM_VBRaio_EditingFinished)          


            self.dlg.pushButton_SVM_Add_Feature.clicked.connect(self.pushButton_SVM_Add_Feature_clicked)                
            self.dlg.pushButton_SVM_Add_Selected_Features.clicked.connect(self.pushButton_SVM_Add_Selected_Features_clicked)                
            self.dlg.pushButton_SVM_Remove_Feature.clicked.connect(self.pushButton_SVM_Remove_Feature_clicked)          
            self.dlg.pushButton_SVM.clicked.connect(self.pushButton_SVM_clicked)                                        
            self.dlg.pushButton_Validacao_Cruzada_SVM.clicked.connect(self.pushButton_Validacao_Cruzada_SVM_clicked)    
    
            self.dlg.label_SVM.mousePressEvent = self.label_SVM_clicked
            self.dlg.label_validacao_cruzada_SVM.mousePressEvent = self.label_validacao_cruzada_SVM_clicked

            self.dlg.datatable_SVM_Trainfeatures.doubleClicked.connect(self.datatable_SVM_Trainfeatures_doubleClicked)
            self.dlg.datatable_validacao_cruzada_SVM.doubleClicked.connect(self.datatable_validacao_cruzada_SVM_doubleClicked)
            self.dlg.datatable_pontos_interpolados_SVM.doubleClicked.connect(self.datatable_pontos_interpolados_SVM_doubleClicked)
            self.dlg.datatable_moran.itemClicked.connect(  self.datatable_moran_checkbox_clicked)    


			###################################################################    
            #tab Management Zone 
            self.dlg.pushButton_ZM_Add_Var.clicked.connect(self.pushButton_ZM_Add_Var_clicked)                          
            self.dlg.pushButton_ZM_Remove_Var.clicked.connect(self.pushButton_ZM_Remove_Var_clicked)                    
            self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.clicked.connect(self.pushButton_ZM_Calc_Nr_Ideal_ZM_clicked)        
            self.dlg.pushButton_ZM_Calcular.clicked.connect(self.pushButton_ZM_Calcular_clicked)                        
            self.dlg.spinBox_ZM_NrZonas.valueChanged.connect(self.spinBox_ZM_NrZonas_changed)                           
            self.dlg.pushButton_ZM_Add_All_Vars_Selected.clicked.connect(self.pushButton_ZM_Add_All_Vars_Selected_clicked)

            self.dlg.datatable_ZM_Maps.itemClicked.connect(self.datatable_ZM_Maps_checkbox_clicked)    

    
            self.dlg.label_ZM_FPI_NCE.mousePressEvent = self.label_ZM_FPI_NCE_clicked
            self.dlg.label_ZM.mousePressEvent = self.label_ZM_clicked


            self.dlg.datatable_ZM.doubleClicked.connect(self.datatable_ZM_doubleClicked)
            self.dlg.datatable_ZM_Classe.doubleClicked.connect(self.datatable_ZM_Classe_doubleClicked)


            #layer tabela de atributos             
            self.dlg.mMapLayerComboBox.setFilters(QgsMapLayerProxyModel.PointLayer)                                                 #filter layer PointLayer 
    
            #layer area de contorno
            self.dlg.mMapLayerComboBox_AreaCont.setFilters(QgsMapLayerProxyModel.PolygonLayer)                                      #filter layer PointLayer (QgsMapLayerProxyModel.PointLayer) / PolygonLayer  (QgsMapLayerProxyModel.PolygonLayer)  
    
    
            #layer Dense_Layer
            self.dlg.mMapLayerComboBox_DenseLayer.setFilters(QgsMapLayerProxyModel.PointLayer | QgsMapLayerProxyModel.RasterLayer)  #filter layer PointLayer/RasterLayer    
    
    
            # show the dialog
            self.dlg.show()
            # Run the dialog event loop
            

            if not os.path.isdir(os.path.join(self.path_absolute , 'Smart-Map' )):          #Create directory Smart-Map
                os.mkdir(os.path.join(self.path_absolute , 'Smart-Map'))


            self.dlg.lineEdit.setText(os.path.join(self.path_absolute , 'Smart-Map'))        
            self.path_absolute = os.path.join(self.path_absolute , 'Smart-Map')
   
            self.reset_gui()
                        
            self.v_target = ''                                                 #v_target was not defined at the beginning of the program
            self.VTarget_FileName = ''
            self.Index_LayerAtual  = -1                                        #Index_LayerCurrent starts with a negative value -> was not defined at the beginning of the program
            self.df_limite = pd.DataFrame(columns = ['Coord_X' , 'Coord_Y'])                    
            self.maximum_points_plugin = 5000                                  #max samples points to plugin work 

            if self.dlg.mMapLayerComboBox.currentIndex() >= 0:  

                self.mMapLayerComboBox_changed()                               #Event onchange of combobox Layer Atributte Table   


            self.load_maps_to_generate_ZM()                                                 

            
            result = self.dlg.exec_()                                          #button OK 
            # See if OK was pressed
    
           
            if result:
                # Do something useful here - delete the line containing pass and
                # substitute with your code.
                #code of button OK that already comes in the interface
                pass 



    def reset_gui(self):
 
                
			###################################################################    
            #tab Grid

            self.dlg.groupBox_Area_Contorno.setEnabled(False)            
            
            if not self.dlg.checkBox_Area_Contorno.isChecked():
                
                self.dlg.checkBox_Area_Contorno.setChecked(False)
                self.dlg.mMapLayerComboBox_AreaCont.setEnabled(False)

            if self.dlg.mMapLayerComboBox_AreaCont.currentIndex() < 0: 
               
                self.dlg.mMapLayerComboBox_AreaCont.setEnabled(False)
                self.dlg.checkBox_Area_Contorno.setEnabled(False)
                self.dlg.pushButton_Area_Contorno.setEnabled(False)               



            self.dlg.datatable_limite.setColumnCount(0)
            self.dlg.datatable_limite.setRowCount(0)
            self.dlg.label_pontos_limite.hide()
            self.dlg.label_CRS_Layer.hide() 

            self.dlg.groupBox_Interv_Interp.setEnabled(False)
           
			###################################################################    
            #tab Interpolation 
            self.dlg.tabWidget_Interpolacao.setCurrentIndex(0) 


			###################################################################    
            #tab Interpolation -> Kriging
            self.hide_horizontalSlider = False                                #limite máximo do GUI horizontalslider 

            self.dlg.horizontalSlider_Nugget.show()

            try: 
                self.dlg.horizontalSlider_Nugget.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                
            self.dlg.horizontalSlider_Nugget.setValue(0)
            self.dlg.lineEdit_Nugget.setText('0.000')
            self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)

            self.dlg.horizontalSlider_Sill.show()
            
            try:               
                self.dlg.horizontalSlider_Sill.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               

                
            self.dlg.horizontalSlider_Sill.setValue(0)
            self.dlg.lineEdit_Sill.setText('0.000')
            self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)

            self.dlg.horizontalSlider_Range.show()

            try: 
                self.dlg.horizontalSlider_Range.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                
            self.dlg.horizontalSlider_Range.setValue(0)
            self.dlg.lineEdit_Range.setText('0.001')
            self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)
            
                 
            self.dlg.groupBox_Variograma.setEnabled(False)
            self.dlg.pushButton_VariogramaReset.setEnabled(False) 
            self.dlg.pushButton_VariogramaSave.setEnabled(False)                      
            self.dlg.lineEdit_OK_DMax.setEnabled(False)                   
            self.dlg.lineEdit_OK_lags_dist.setEnabled(False)                   
            self.dlg.groupBox_Variograma_Model.setEnabled(False)                
            self.dlg.comboBox_Modelo.setCurrentIndex(0)

            self.dlg.lineEdit_Var_RMSE.setText('0.000')   
            self.dlg.lineEdit_Var_R2.setText('0.000')   
            self.dlg.lineEdit_OK_VBRaio.setEnabled(False)            
            self.dlg.groupBox_Krigagem.setEnabled(False)  
            self.dlg.pushButton_Krigagem.setEnabled(False)  
            self.dlg.checkBox_Krigagem_Std_Desv.setEnabled(False) 
    
            self.dlg.datatable_pontos_interpolados_OK.setColumnCount(0)
            self.dlg.datatable_pontos_interpolados_OK.setRowCount(0)
    
            self.dlg.datatable_validacao_cruzada_OK.setColumnCount(0)
            self.dlg.datatable_validacao_cruzada_OK.setRowCount(0)
        
            self.dlg.label_Variograma.hide()
            self.dlg.label_Krigagem.hide()
            self.dlg.label_validacao_cruzada_OK.hide()

            self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
    
    
			###################################################################    
            #tab Interpolation -> SVM            
            self.dlg.groupBox_SVM_Vars.setEnabled(False)
            self.dlg.groupBox_SVM.setEnabled(False)
            self.dlg.comboBox_SVM_Fonte.setEnabled(False)

            self.dlg.checkBox_Moran.setChecked(False)
            self.dlg.checkBox_Moran.setEnabled(False)

            self.dlg.checkBox_RFE.setChecked(False)
            self.dlg.checkBox_RFE.setEnabled(False)

            self.dlg.datatable_RFE.setColumnCount(0)
            self.dlg.datatable_RFE.setRowCount(0)

            self.dlg.checkBox_RFE.hide()
            self.dlg.datatable_RFE.hide()

            self.dlg.pushButton_SVM.setEnabled(False)
    
            self.dlg.comboBox_SVM_Fonte.setCurrentIndex(0)
            self.dlg.comboBox_SVM_Fonte.setEnabled(False)
    
            self.dlg.comboBox_SVM_Features.clear()                     
            self.dlg.comboBox_SVM_Features.setEnabled(False)

            self.dlg.comboBox_SVM_Features_Adds.clear()                     
            self.dlg.comboBox_SVM_Features_Adds.setEnabled(False)

            self.dlg.comboBox_SVM_Features_Adds.setEnabled(False)
            self.dlg.pushButton_SVM_Remove_Feature.setEnabled(False)
            self.dlg.label_SVM_DenseLayer.setEnabled(False)
            self.dlg.mMapLayerComboBox_DenseLayer.setEnabled(False)


            self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(0) 

            self.list_cov_SVM = []
            self.list_rows_moran = []
       
            self.dlg.datatable_SVM_Trainfeatures.setColumnCount(0)
            self.dlg.datatable_SVM_Trainfeatures.setRowCount(0)
    
            self.dlg.datatable_SVM_Trainlabels.setColumnCount(0)
            self.dlg.datatable_SVM_Trainlabels.setRowCount(0)
   
            self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
            self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
            self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
            self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)
    
            self.dlg.label_SVM.hide()
            self.dlg.label_validacao_cruzada_SVM.hide()
    
            self.dlg.pushButton_Validacao_Cruzada_SVM.setEnabled(False)

    
 			###################################################################    
            #Tab Management Zone
            self.dlg.tabWidget_ZM.setCurrentIndex(0) 

            self.dlg.pushButton_ZM_Add_Var.setEnabled(True)
            self.dlg.groupBox_ZM_Remove_Var.setEnabled(False)
            self.dlg.pushButton_ZM_Remove_Var.setEnabled(False)
            self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
            self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
            self.dlg.pushButton_ZM_Calcular.setEnabled(False)
            self.dlg.groupBox_ZM_Calcular.setEnabled(False)
            self.dlg.comboBox_ZM_var.clear()            
    
            self.dlg.datatable_ZM.setColumnCount(0)
            self.dlg.datatable_ZM.setRowCount(0)       
           
            self.dlg.datatable_ZM_Classe.setColumnCount(0)
            self.dlg.datatable_ZM_Classe.setRowCount(0)       
    
            self.dlg.label_ZM_FPI_NCE.hide()
            self.dlg.label_ZM.hide()


 			###################################################################    
            #Global Variables 

            self.ImportQGIS = False             #Empty Attribute Table 
    
            self.Var_Selected = False           #Not selected Variable V_target  
            
            self.list_index_outlier = []        #List of index to Outliers 

            self.list_index_out_polygon = []    #List of index to Point out polygon contourn

            self.Contorno_Definido = False      #Not selected Map Contourn 
    
            self.Variogram = False              #Not ajust variogram 
    
            self.Krigagem = False               #Not interpolated Kriging
    
            self.Validacao_Cruzada_OK = False   #Not do Cross Validation - Kriging
    
            self.SVM_Add_Coord = False          #Not added coordinates to the SVM model  
           
            self.SVM_Add_Feature = False        #Not added features to the SVM model
    
            self.SVM = False                    #Not interpolated SVM 
    
            self.Validacao_Cruzada_SVM = False  #Not do Cross Validation - SVM
            
            self.list_cov_SVM = []              #Covariables list of Model of Machine Learning 
            
            self.ZM_Add_Coord = False           #Not added coordinates to define management zones 
    
            self.ZM_Add_Var = False             #Not added variables to define management zones 
    
            self.Calc_Nr_Ideal_ZM = False       #Not calculate FPI / NCE      
    
            self.ZM_Calcular = False            #Not calculate management zones 

            self.list_cov_ZM        = []        #List of Variables to generate  management zones

            self.list_cov_ZM_metodo = []        #List of Variables to generate  management zones -> method (Krig, SVM) for each variable added
                         
            self.hide_horizontalSlider = False  #Hide the horizontal silder bar 

############################################################    Data import tab #################################################################



    def label_About_clicked(self, value):

        self.About = smart_mapAbout()  #Interface about credits of system
        #self.About.show()             #display como show 
        self.About.setWindowIcon(QtGui.QIcon(self.icon_path))        
        self.About.exec_()             #display como showmodal 
        
        
    def label_language_PT_clicked(self, value):

        msg_box = QMessageBox()
        msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
        msg_box.setIcon(QMessageBox.Warning)
        msg_box.setWindowTitle(self.tr('Mensagem'))
        msg_box.setText(self.tr('Feche e Abra o plugin novamente para aplicar o idioma selecionado!'))
        msg_box.exec_()
                    
        f = open(os.path.join(self.plugin_dir, 'i18n', 'language.txt'), 'w')        
        f.write('Portuguese')          
        f.close()             
        self.language = 'Portuguese'   


    
    def label_language_USA_clicked(self, value):


        msg_box = QMessageBox()
        msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
        msg_box.setIcon(QMessageBox.Warning)
        msg_box.setWindowTitle(self.tr('Mensagem'))
        msg_box.setText(self.tr('Feche e Abra o plugin novamente para aplicar o idioma selecionado!'))
        msg_box.exec_()
                    
        f = open(os.path.join(self.plugin_dir, 'i18n', 'language.txt'), 'w')        
        f.write('English')
        f.close()             
        self.language = 'English'
        

    def checkBox_Qgis_Vector_Points_clicked(self):
        
        
       if self.dlg.checkBox_Qgis_Vector_Points.isChecked(): 
           
          self.dlg.checkBox_Qgis_Raster.setChecked(True)  


    def checkBox_Qgis_Vector_Polygons_clicked(self):


       if self.dlg.checkBox_Qgis_Vector_Polygons.isChecked(): 
            
          self.dlg.checkBox_Qgis_Raster.setChecked(True)  


    def checkBox_Qgis_Raster_clicked(self):

       if not self.dlg.checkBox_Qgis_Raster.isChecked(): 

          self.dlg.checkBox_Qgis_Vector_Points.setChecked(False)
          
          self.dlg.checkBox_Qgis_Vector_Polygons.setChecked(False)


    def checkBox_Krigagem_Std_Desv_clicked(self):


       if self.dlg.checkBox_Krigagem_Std_Desv.isChecked(): 
            
          self.dlg.checkBox_Qgis_Raster.setChecked(True)  



 
    def mMapLayerComboBox_changed(self):                                       #evento onchange do combobox Layer da Tabela de Atributos   

      
        if self.dlg.mMapLayerComboBox.currentIndex() >= 0:  

            #Index_selectedLayer = self.dlg.mMapLayerComboBox.currentIndex()
            #self.LayerAtual -> variavel global 
            #selectedLayer -> variavel local indicando a layer selecionada
            #print('self.Index_LayerAtual ' , self.Index_LayerAtual)
            #print('Index_selectedLayer ' , Index_selectedLayer)
            
            #if (self.Index_LayerAtual != Index_selectedLayer):  

            #Reset Variables and components 
            self.reset_gui()                     


            selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()
            
            coordenate_reference = selectedLayer.crs().description()
            
            if 'SAD69' in coordenate_reference: 
                
                self.lyrCRS_table_atribute = QgsProject.instance().crs().authid()  #get CRS of project   EX: EPSG:32723
            
            else:      

                self.lyrCRS_table_atribute = selectedLayer.crs().authid()          #EPSG:32723  
           

            self.dlg.label_CRS_Layer.show() 
            self.dlg.label_CRS_Layer.setText('CRS Layer: ' + self.lyrCRS_table_atribute) 
            #print(self.lyrCRS_table_atribute)
            
            #try: 
            #self.dlg.comboBox_VTarget.currentIndexChanged.disconnect()                           #evento onchange do combobox v_target   
            #except TypeError:
            #    pass  # Ignore the error if no connections exist               

        
            self.cols_table_atribute = selectedLayer.fields().names() 

            self.dlg.comboBox_VTarget.setEnabled(True)           

            self.dlg.comboBox_VTarget.clear()
            self.dlg.comboBox_VTarget.addItems(self.cols_table_atribute)
            self.dlg.comboBox_VTarget.setCurrentIndex(0)
        
            #self.v_target =  self.dlg.comboBox_VTarget.currentText()              
            #self.dlg.comboBox_VTarget.currentIndexChanged.connect(self.comboBox_VTarget_changed)  #evento onchange do combobox v_target   

            #Aba Tabela de Atributos 
            self.dlg.datatable_atributos.setColumnCount(0)
            self.dlg.datatable_atributos.setRowCount(0)           
            self.dlg.comboBox_VTarget.setEnabled(True)
            self.dlg.pushButton_ImportQGIS.setEnabled(True)


    def resampling_of_points(self, df):


        if 'fid' in df.columns:
            df.drop('fid', axis=1, inplace=True)            

        #if 'CoordX_SM' in df.columns:
        #    df.drop('CoordX_SM', axis=1, inplace=True)            

        #if 'CoordY_SM' in df.columns:
        #    df.drop('CoordY_SM', axis=1, inplace=True)            


        list_cols_NaN = df.columns[df.isnull().any()].tolist()       #encontra as colunas com NaN no dataframe 


        #verificar por colunas que tem todos os valores nulos e apaga a coluna -> evitar de apgar todo o dataframe  
        for i in range (len(list_cols_NaN)):                    
            columnName = list_cols_NaN[i]
            tot_NaN_in_col = df[columnName].isnull().sum()
            if tot_NaN_in_col == len(df):
               df.drop(columnName, axis=1, inplace=True)            

        
        tot_nan = df.isnull().sum().sum()
        
        if tot_nan > 0: 
            
            df.dropna(inplace=True)                                            #drop lines with null values  
            df.reset_index(drop = True, inplace=True)                          #reset the index without create new colum index
        
        
        Cord_X   =  'CoordX_SM' #self.dlg.comboBox_CordX.currentText()  
        Cord_Y   =  'CoordY_SM' #self.dlg.comboBox_CordY.currentText() 
        weight_IDW =  self.dlg.doubleSpinBox_Weight_IDW.value()   
        cols = df.columns 
        
        if self.Contorno_Definido ==  False:                                   #boundary not defined -> use data of attribute table
            Cord_X_min = df[Cord_X].min() 
            Cord_Y_min = df[Cord_Y].min() 
            Cord_X_max = df[Cord_X].max() 
            Cord_Y_max = df[Cord_Y].max() 
        else: 
            Cord_X_min = self.df_limite['Coord_X'].min() 
            Cord_X_max = self.df_limite['Coord_X'].max() 
            Cord_Y_min = self.df_limite['Coord_Y'].min() 
            Cord_Y_max = self.df_limite['Coord_Y'].max() 
             

        area = (Cord_X_max - Cord_X_min) * (Cord_Y_max - Cord_Y_min)
        
        n = area / self.maximum_points_plugin 
        
        grid_size = math.sqrt(n)       
        #grid_size = 1 
       
        gridx = np.arange(Cord_X_min, Cord_X_max, grid_size)
        gridy = np.arange(Cord_Y_min, Cord_Y_max, grid_size)        
               
        nr_points = len(gridx) * len(gridy)
        #print(nr_points) 

        '''
        while (nr_points > self.maximum_points_plugin): 
        
            grid_size = grid_size + 1 
                
            gridx = np.arange(Cord_X_min, Cord_X_max, grid_size)
            gridy = np.arange(Cord_Y_min, Cord_Y_max, grid_size)        
        
            nr_points = len(gridx) * len(gridy)
        '''
        
        
        lista_xy = []
        for i in range(len(gridx)):
            for j in range(len(gridy)): 
                lista_xy.append([gridx[i], gridy[j]])   

        arr_xy = np.array(lista_xy)
        
       
        if self.dlg.checkBox_Area_Contorno.isChecked(): 

            if len(self.df_limite) <= 0:                                       #user selected the checkbox but not click in button to define boundary
                if (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0): 
                    self.pushButton_Area_Contorno_clicked()    
                    
            lista_cut_xy = []

            polygono = np.array(self.df_limite, dtype=float)                #define the polygon = area of boundary
            bbPath = mplPath.Path(polygono)

            for i in range(len(arr_xy)):
                ponto = (arr_xy[i,0], arr_xy[i,1])
                if bbPath.contains_point(ponto): 
                    lista_cut_xy.append([arr_xy[i,0], arr_xy[i,1]])

             
            arr_xy = np.array(lista_cut_xy)
                
        grid_xy = np.array(arr_xy) 
        

        features_dense = df[[Cord_X, Cord_Y]]     
        features_dense = np.array( features_dense, dtype=float )


        ####################################################################### 
        #definindo o dataframe df reamostrado

        gridxy_dense = np.c_[features_dense[:,0], features_dense[:,1]]         #array 2d (783,2) with values of x, y 

        ## ------------- Creating KDTree
        tree_dense = spatial.cKDTree(gridxy_dense)                             #object with distances between of points
        ## ------------- Creating empty grid matrix with np.zeros

        maximum = (len(cols)-3) 
        progress = QProgressDialog(self.tr('Reamostragem da tabela de atributos...'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                         #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)        #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                      #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)                #modal for application 
        time.sleep(0.1)

        for feat in range(len(cols)-3):                                        #-3 -> to discard coluns: CoordX_SM, CoordY_SM, ID_SM
        
            vt_dense = df.iloc[:,feat]                                         #Array 1d (783,) with the values of covariavel                
                    
            #z = np.zeros((gridx.shape[0], gridy.shape[0]), dtype=float)  #matrix (121, 104) of zeros create of points of gridx e gridy
               
            lista = []
            for cont in range(len(grid_xy)):                                   #cont between (1,141) for each point in features 
               
                   p = np.array([grid_xy[cont,0], grid_xy[cont,1]])            #p = point (x,y) of features 
            
                   raio_busca = float(grid_size/2)                             #search radius = 50% of lenght grid
                   neigs      = tree_dense.query_ball_point(p, raio_busca)     #neigs         = index of vector array of points to 50m of distance
            
                   if len(neigs) > 0: 
                       
                       distances, points_idx = tree_dense.query(p, k=len(neigs))      #distances     = distancia de p aos neigs pontos mais proximos em ordem crescente 
                                                                                      #points_idx    = indice no vetor de array dos 16 pontos mais proximos 
                       vt_vals_dense = vt_dense[points_idx]                           #vt_vals_dense = valores observados dos 16 pontos mais proximos         
               
                       value = functions.mean(distances, vt_vals_dense, weight_IDW)   #value = valor obtido por mena no ponto p apartir dos neigs vizinhos 
                                              
                   else: 
                       
                       value = -1 
            
                     
                   lista.append(value)   
        
        
            arr = np.array(lista)      #arr_cut com todas as coluna     
           
            if feat == 0:              #inicia a matriz de reamostragem
               arr_resample = np.copy(arr) 
            else:       
               arr_resample = np.column_stack((arr_resample, arr))             #concatena após ultima coluna.

            progress.setValue(feat)                        
            if progress.wasCanceled():                          
               progress.close() 
               return 
                   
        
        progress.close() 
        
        arr_resample  = np.column_stack((arr_resample, arr_xy))
        
        id_sm =  np.arange(1, len(arr_xy)+1, 1)
         
        arr_resample  = np.column_stack((arr_resample, id_sm))
        
        df_resample = pd.DataFrame(np.atleast_2d(arr_resample), columns=cols)
        
        df_resample.replace({-1: np.nan}, inplace=True)            #replace values -1 to nan  
        
        tot_nan = df_resample.isnull().sum().sum()
        
        if tot_nan > 0: 
            
            df_resample.dropna(inplace=True)                        #apaga linhas com valores nulos 
            df_resample.reset_index(drop = True, inplace=True)      #reset the index without new colum index
        
        df_resample['ID_SM'] = df_resample.index
        df_resample['ID_SM'] += 1 
        
        return df_resample



    def load_datatable_atribute_table(self): 


        df1 = self.df[['ID_SM', 'CoordX_SM', 'CoordY_SM', self.v_target]]            

        maximum = len(df1.index) * len(df1.columns)
        progress = QProgressDialog(self.tr('Importando tabela de atributos...'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                     #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
        time.sleep(0.1)

        self.dlg.datatable_atributos.setColumnCount(len(df1.columns))
        self.dlg.datatable_atributos.setRowCount(len(df1.index))

        #preencher o cabeçalho
        try:                       


            cols = ['ID', 'Coord X', 'Coord Y', self.v_target] 
            #cols = list(self.df.columns.values) 

            self.dlg.datatable_atributos.setHorizontalHeaderLabels(cols)
         

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()

            
        #preencher as linhas da planilha 
        cont = 1
        try:                       
            for i in range(len(df1.index)):         #linhas 
                for j in range(len(df1.columns)):   #colunas 
                    valor = df1.iloc[i,j]
                    
                    if j == 0: #Coluna[0] -> ID
                       valor = '%.0f' % valor                       
                    else:  
                        if valor.dtype == "float64": 
                           valor = '%.3f' % valor                       
                        
                    valor = QTableWidgetItem(str(valor))                  

                    if i in self.list_index_outlier: 
                        valor.setForeground(QBrush(QColor(255, 0, 0)))

                    
                    self.dlg.datatable_atributos.setItem(i,j, valor)                       
                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
                       #break


        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()
        
         
        self.dlg.datatable_atributos.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)   #read-only para as celulas do datatable

        progress.close() 

        
    def load_datatable_SVM_Trainfeatures(self): 


        maximum = len(self.df_SVM_Trainfeatures.index) * len(self.df_SVM_Trainfeatures.columns)
        progress = QProgressDialog(self.tr('Importando tabela de atributos...'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                     #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
        time.sleep(0.1)
        
        
        self.dlg.datatable_SVM_Trainfeatures.setColumnCount(len(self.df_SVM_Trainfeatures.columns))
        self.dlg.datatable_SVM_Trainfeatures.setRowCount(len(self.df_SVM_Trainfeatures.index))

        #preencher o cabeçalho do datatable_SVM_Trainfeatures 
        try:                       
            cols = [] 
            cols = list(self.df_SVM_Trainfeatures.columns.values)

            self.dlg.datatable_SVM_Trainfeatures.setHorizontalHeaderLabels(cols)

        except AttributeError: 
				
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        #preencher as linhas do datatable_SVM_Trainfeatures 
        cont = 1     
        try:                       
            for i in range(len(self.df_SVM_Trainfeatures.index)):          #linhas 
                for j in range(len(self.df_SVM_Trainfeatures.columns)):    #colunas 

                    valor = self.df_SVM_Trainfeatures.iloc[i,j]

                    if valor.dtype == "float64": 
                        valor = '%.3f' % valor                       
					
                    valor = QTableWidgetItem(str(valor))                  
                    self.dlg.datatable_SVM_Trainfeatures.setItem(i,j, valor)
                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
                    

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()

        self.dlg.datatable_SVM_Trainfeatures.resizeColumnsToContents();

        self.dlg.datatable_SVM_Trainfeatures.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

        progress.close() 
        

        
    def load_datatable_SVM_Trainlabels(self): 

        
        maximum = len(self.df_SVM_Trainlabels.index) * len(self.df_SVM_Trainlabels.columns)
        progress = QProgressDialog(self.tr('Importando tabela de atributos...'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                     #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
        time.sleep(0.1)
        

        self.dlg.datatable_SVM_Trainlabels.setColumnCount(len(self.df_SVM_Trainlabels.columns))
        self.dlg.datatable_SVM_Trainlabels.setRowCount(len(self.df_SVM_Trainlabels.index))

        #preencher o cabeçalho do datatable_SVM_Trainlabels
        try:                       
            cols = [] 
            cols = list(self.df_SVM_Trainlabels.columns.values)

            self.dlg.datatable_SVM_Trainlabels.setHorizontalHeaderLabels(cols)

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        #preencher as linhas do datatable_SVM_Trainlabels 
        cont = 1     
        try:                       
            for i in range(len(self.df_SVM_Trainlabels.index)):        #linhas 
                for j in range(len(self.df_SVM_Trainlabels.columns)):  #colunas 
                    valor = self.df_SVM_Trainlabels.iloc[i,j]
                    if valor.dtype == "float64": 
                        valor = '%.3f' % valor                       
					
                    valor = QTableWidgetItem(str(valor))                  
                    self.dlg.datatable_SVM_Trainlabels.setItem(i,j, valor)
                    cont = cont + 1 
                    progress.setValue(cont)
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 


        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        self.dlg.datatable_SVM_Trainlabels.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

        progress.close()         
        
        

    def pushButton_ImportQGIS_clicked(self):
        

        self.Cord_X   =  'CoordX_SM' #self.dlg.comboBox_CordX.currentText()  
        self.Cord_Y   =  'CoordY_SM' #self.dlg.comboBox_CordY.currentText() 

       
        if self.dlg.mMapLayerComboBox.currentIndex() >= 0:                     #existe layer selecionada de um projeto Qgis 

            
            #self.dlg.pushButton_ImportQGIS.setEnabled(False)

            #Reset Variables and components        
            self.reset_gui()                  

            selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()


            '''
            features = selectedLayer.getFeatures()
            for feature in features:
                geom= QgsGeometry.asPoint(feature.geometry())
                
            pxy=QgsPointXY(geom)
            long = pxy.x()
            lat  = pxy.y()
            
            if (((abs(long) >= 0) and (abs(long) <= 180)) or ((abs(lat) >= 0) and (abs(lat) <= 90))): 
            '''

            lyrCRS = selectedLayer.crs()
            
            if (lyrCRS.isGeographic() == True):  #layer é lat/long

                message =  self.tr('O Sistema de Coordenadas Geográficas deve estar em UTM.') + '\n' 
                message = message + self.tr('Realize a conversão da layer de entrada para a projeção UTM antes de importá-la no Smart-Map.') + '\n'


                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(message)
                msg_box.exec_()               

            else:      


                continue_prossessing = 'YES'
    
                if len(selectedLayer) > self.maximum_points_plugin * 1.2: 
    
                    message =  self.tr('A layer selecionada possui ') + str(len(selectedLayer)) + self.tr(' pontos amostrados.') + '\n' 
                    message = message + self.tr('O limite máximo suportado pelo plugin para a layer de entrada é: ') + str(self.maximum_points_plugin) + self.tr(' pontos.') + '\n'
                    message = message + self.tr('Deseja realizar uma reamostragem de pontos?') + '\n'
    
                    resample = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr(message) , QMessageBox.Yes | QMessageBox.No)
            
                    if resample == QMessageBox.No:
    
                        continue_prossessing = 'NO'
    
    
                if continue_prossessing == 'YES': 
    
    
                    # salvar a layer em um arquivo .csv
    
    
                    maximum = 10
                    progress = QProgressDialog(self.tr('Importando tabela de atributos...'), self.tr('Cancelar'),  1, maximum, self.dlg) 
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)
                    
                    progress.setMinimumDuration(1000) #1000ms  ==  1s 
                    progress.forceShow()
    
                    progress.setValue(0)
                    progress.setValue(1)
                    progress.setValue(2)               
    
                    lyrCRS = selectedLayer.crs() 
                    QgsVectorFileWriter.writeAsVectorFormat(selectedLayer, os.path.join(self.path_absolute , '0_Dados.csv'), "utf-8", lyrCRS, "CSV")  
    
                    progress.setValue(9)               
                    progress.close() 
    
                    filename = os.path.join(self.path_absolute , '0_Dados.csv')  
    
                    self.df  = pd.read_csv(filename, sep = ',')  
    
                    self.df  = self.df._get_numeric_data()  #filtrar as colunas só com números 
    
                    self.v_target =  self.dlg.comboBox_VTarget.currentText()   
    
                    cols_df = list(self.df.columns.values) 
    
                    if ((self.Cord_X not in cols_df) and (self.Cord_Y not in cols_df)):   
    
                        maximum = len(self.df) 
                        progress = QProgressDialog(self.tr('Calculando Coordenadas da Layer...'), self.tr('Cancelar'),  1, maximum, self.dlg)
                        progress.setWindowTitle('Smart-Map')
                        progress.show() 
                        progress.setCancelButton(None)                                     #remove button cancel 
                        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                        time.sleep(0.1)
        
                        
                        features = selectedLayer.getFeatures()                       
                        
                        features_Coordx = []
                        features_Coordy = []
                        cont = 1
                        for feat in features:
                            geom = QgsGeometry.asPoint(feat.geometry())
                            pxy=QgsPointXY(geom)
                            features_Coordx.append(pxy.x())                                #Valor da coordenada X calculada pelo Smart-Map     
                            features_Coordy.append(pxy.y())                                #Valor da coordenada Y calculada pelo Smart-Map
        
                            cont = cont + 1 
                            progress.setValue(cont)                        
                            if progress.wasCanceled():                          
                               progress.close() 
                               return 
                        
                        progress.close()               
            
                        features_Coordx = np.array(features_Coordx)
                        features_Coordy = np.array(features_Coordy)
        
                        arr_xy = np.column_stack([features_Coordx, features_Coordy])      
            
                        arr_xy_df = pd.DataFrame(np.atleast_2d(arr_xy), columns=['CoordX', 'CoordY'])
            
                        df_xy_id = pd.DataFrame({'CoordX_SM':arr_xy_df.CoordX, 'CoordY_SM':arr_xy_df.CoordY, 'ID_SM':arr_xy_df.index})
                        df_xy_id['ID_SM'] += 1 
            
                        self.df = pd.concat([self.df, df_xy_id], axis=1)  
                        
                        self.df.to_csv(os.path.join(self.path_absolute , '0_Dados.csv'), sep=',', index=False, encoding='utf-8')
        
    
        			#######################################################################    
                    #eliminar valores NaN da coluna v_target  
    
                    self.VTarget_FileName  = self.v_target    
                    for ch in [' ', ')', '(', 'á', '?', '/', 'é', '.', 'í', 'ú', '-']:
                        if ch in self.VTarget_FileName:
                            self.VTarget_FileName = self.VTarget_FileName.replace(ch,"_")
            
            
                    is_NaN = self.df.isnull()
                    row_has_NaN = is_NaN.any(axis=1)
                   
                   
                    df_with_NaN = self.df[row_has_NaN]
                    
                    list_rows_NaN = list(df_with_NaN.index.values)
            
                    list_cols_NaN = df_with_NaN.columns[df_with_NaN.isnull().any()].tolist()
            
            
                    if self.v_target in list_cols_NaN:                                 #o atributo v_target selecionado possui valores nulos  -> apagar as linhas  
            
                        
                        df_with_NaN = self.df[self.df[self.v_target].isnull()]
                        list_rows_NaN = list(df_with_NaN.index.values)
            
                        self.df.drop(index=list_rows_NaN, inplace = True)              #apaga linhas com valores nulos 
                        self.df.reset_index(drop = True, inplace=True)                 #reset the index without new colum index    
        
                        #mensagem de retorno ao usuário             
                        msg_box = QMessageBox()
                        msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                        msg_box.setIcon(QMessageBox.Warning)
                        msg_box.setWindowTitle(self.tr('Mensagem'))
                        msg_box.setText(self.tr('Existem') + ' : ' + str(len(list_rows_NaN)) + ' ' + self.tr('valores nulos na tabela.') + '\n' + self.tr('Linha(s)') + ': ' + str(list_rows_NaN) + ' ' + self.tr('foram excluídas.'))
                        msg_box.exec_()               
    
    
              
    
        			#######################################################################    
                    #resampling datatable da tabela de atributos 
                    if len(self.df) > self.maximum_points_plugin * 1.2: 
    
                        self.df = self.resampling_of_points(self.df)
    
                        message = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr('Deseja salvar os pontos reamostrados em uma nova layer Qgis?') , QMessageBox.Yes | QMessageBox.No)
                
                        if message == QMessageBox.Yes:
    
                            
                            self.df.to_csv(os.path.join(self.path_absolute , '0_Dados_Resample.csv'), sep=',', index=False, encoding='utf-8')
                            
                            try: 
                              self.dlg.mMapLayerComboBox.currentIndexChanged.disconnect()    #desconecta evento do combobox select Layer Qgis na tabela de atributos 
                            except TypeError:
                                pass  # Ignore the error if no connections exist               
                            
                            
                            Input_Table            = os.path.join(self.path_absolute , '0_Dados_Resample.csv') #set the filepath for the input CSV
                            Output_Layer_File_shp  = os.path.join(self.path_absolute , selectedLayer.name() + '_Resample.shp') #set the filepath for the output shapefile
                            Output_Layer_Name      =                                   selectedLayer.name() + '_Resample'
    
    
                            self.export_shapefile_resampled_to_qgis(Input_Table, Output_Layer_File_shp, Output_Layer_Name) 
    
                            
                            self.dlg.mMapLayerComboBox.currentIndexChanged.connect(self.mMapLayerComboBox_changed) #connecta evento do combobox select Layer Qgis na tabela de atributos 
    
    
               
                   	###############################################################
                    #localizar Outliers 
                   
                        
                    if self.dlg.checkBox_Eliminate_Outilier.isChecked(): 
                       #self.df = functions.eliminar_outlier(self.df, self.v_target)
                       self.list_index_outlier = functions.localizar_outlier(self.df, self.v_target)
    
    
    
        			###############################################################
                    #preencher datatable da tabela de atributos 
        
    
                    self.load_datatable_atribute_table()
                    
        
    
        			###############################################################
                    #excluir Outliers da tabela de atributos 
    
                    if len(self.list_index_outlier) > 0: 
            
                        df_outlier = self.df.loc[self.df.index[self.list_index_outlier]]
    
                        self.data_outlier = df_outlier[[self.Cord_X, self.Cord_Y, self.v_target]] 
                        self.data_outlier = np.array( self.data_outlier, dtype=float )
    
                        self.df.drop(self.df.index[self.list_index_outlier], inplace=True)
                        self.df.reset_index(drop = True, inplace=True)
    
    
                        #print('list_index_outlier', self.list_index_outlier)
    
    
                    
        			#######################################################################    
                    #Calculando Max e Min para o mapa de contorno  
        
                    self.data = self.df[[self.Cord_X, self.Cord_Y, self.v_target]] 
                    self.data = np.array( self.data, dtype=float )
        
                    self.Pixel_Size_X = self.dlg.SpinBox_Pixel_Size_X.value() 
        
                    self.Pixel_Size_Y = self.dlg.SpinBox_Pixel_Size_Y.value() 
        
                        
                    if self.Contorno_Definido ==  False:                           #contorno não foi definido -> utilizar dados da tabela de atributos 
                        self.Cord_X_min = self.df[self.Cord_X].min() 
                        self.Cord_Y_min = self.df[self.Cord_Y].min() 
                        self.Cord_X_max = self.df[self.Cord_X].max() 
                        self.Cord_Y_max = self.df[self.Cord_Y].max() 
        
                    self.dlg.lineEdit_XMin.setText('%.3f' % self.Cord_X_min)                        
                    self.dlg.lineEdit_XMax.setText('%.3f' % self.Cord_X_max)                            
                    self.dlg.lineEdit_YMin.setText('%.3f' % self.Cord_Y_min)                            
                    self.dlg.lineEdit_YMax.setText('%.3f' % self.Cord_Y_max)                        
        
        			   
                    self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X))         
                    self.Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y))         
        
        
                    self.dlg.lineEdit_Num_Points_X.setText(str(self.Num_Points_X)) 
                    self.dlg.lineEdit_Num_Points_Y.setText(str(self.Num_Points_Y)) 
        
                    self.dlg.label_VTargetOK.setText( self.tr('Z') + ': ' + self.v_target)
                    self.dlg.label_VTargetSVM.setText(self.tr('Z') + ': ' + self.v_target)
                    self.dlg.label_VTargetSVM.setEnabled(True)        
        
        
        
        			###############################################################
        			#calculando o Indice de Moran para os pontos amostrados da tabela de atributos 
        
                    df_pontos_amostrados = pd.DataFrame(np.atleast_2d(self.data), columns=[self.Cord_X, self.Cord_Y, self.v_target])
        
                    Moran_Index, P_Value = functions.calculate_index_moran(df_pontos_amostrados, self.Cord_X, self.Cord_Y, self.v_target) 
        
                    self.moran_index = '%.3f' % Moran_Index                          
                    self.p_value =  '%.3f' % P_Value                                     
        
        
        			###############################################################
        			#plotar mapa de pontos amostrados    
        
                    plt1.close()
                    plt1.title('I.Moran: ' + str(self.moran_index) + ' P.Value: ' + str(self.p_value))
                    plt1.xlabel('Longitude (X)')
                    plt1.ylabel('Latitude  (Y)') 
        
                    plt1.xlim(float(self.Cord_X_min-100), float(self.Cord_X_max+100))
                    plt1.ylim(float(self.Cord_Y_min-100), float(self.Cord_Y_max+100))        
        
    
                    interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
                    
                    if interval_x == 0:
                        interval_x = 1   #int((self.Cord_X_max-self.Cord_X_min))
    
                    xmarks=[i for i in range(int(self.Cord_X_min),int(self.Cord_X_max) , interval_x)]          
                    plt1.xticks(xmarks)
        
    
                    interval_y = int((self.Cord_Y_max-self.Cord_Y_min)/7)      

                    
                    if interval_y == 0:
                        interval_y = 1 #int((self.Cord_Y_max-self.Cord_Y_min))  

            
                    ymarks=[i for i in range(int(self.Cord_Y_min),int(self.Cord_Y_max) , interval_y)]          
                    plt1.yticks(ymarks)
        
                    if len(self.list_index_outlier) > 0: 
                       plt1.scatter(self.data_outlier[:,0], self.data_outlier[:,1], c=self.data_outlier[:,2], marker="x", cmap='RdYlGn')

                    #plt1.scatter(self.data[:,0], self.data[:,1])
                    plt1.scatter(self.data[:,0], self.data[:,1], c=self.data[:,2], cmap='RdYlGn', vmin = min(self.data[:,2]), vmax = max(self.data[:,2]))
    
    
                    clb = plt1.colorbar(aspect=20)                                     #expessura do colorbar 
                
                    clb.ax.set_title(self.v_target)
                    
        
                    plt1.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)
        			  
                    plt1.savefig(     os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                    pixmap1 = QPixmap(os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                    self.dlg.label_pontos_limite.show()
                    self.dlg.label_pontos_limite.setPixmap(pixmap1)
        
        
        
                    ####################################################################### 
                    #Calculando dados para gerar semivariograma 
        
                    self.xy     = self.df[[self.Cord_X, self.Cord_Y]]  
                    self.z      = self.df[self.v_target]  
        
                    #xyz    = self.df[[Cord_X, Cord_Y, v_target]] 
        
                    ###Constrõe o objeto
                    #Entrada: xy e z
                    #Calcula distancias calculadas entre os pares de pontos x, y  #self.var['lag']
                    #Calcula a semivariância entre os pares de pontos x, y        #self.var['gamma']            
                    #Calcula a distância máxima entre os lags                     #self.max_dist=self.var['lag'].max()
                    #Calcula a distância mínima entre os lags                     #self.min_dist=self.var['lag'].min()
                    #Calcula a variância amostral                                 #self.sample_variance=z.var() 
                    Semiv = semivariogram.Semivariogram(self.xy, self.z)
        
        
                    #Obtem a máxima distância entre pontos
                    self.max_dist = Semiv.max_dist                                                  #distância máxima da matriz de distâncias
        
                    #Obtem a mínima distância entre pontos
                    self.min_dist = Semiv.min_dist                                                  #distância minima da matriz de distâncias
        
        
                    max_dist_factor = 0.6                                                           #fator de maxima distancia entre os pontos para construir o lag (60%) 
                    self.active_distance_ini = max_dist_factor * self.max_dist                      #60% da maior distancia entre dois pontos amostrais
                    #self.lag_distance_ini = self.active_distance_ini / 15                           #ver como calcular isso automaticamente   -> ANDRE COELHO
                    self.lag_distance_ini    = Semiv.var['lag'][len(self.z)]
        
    
                    if self.lag_distance_ini < self.min_dist:                                       #lag_distance_ini é menor que min_dist -> Ajustar para mim_dist. 
                       self.lag_distance_ini = self.min_dist
    
        
                    #set Distância Máxima -> valor mínimo        
                    i = 5   
                    while (self.max_dist < self.min_dist*i): 
                        i = i - 1 
                    
                    self.DMax_Minimum = self.min_dist*i                                             #distância minima*5 da matriz de distâncias
                    
                    self.dlg.lineEdit_OK_DMax.setText('%.3f'  % self.active_distance_ini)   
        
                    #set Distância (h) - lag 
                    self.dlg.lineEdit_OK_lags_dist.setText('%.3f'  % self.lag_distance_ini)   
        
        
                    #set neighbors 
                    self.VB_OK_Minimum = 4                                                          #self.dlg.lineEdit_OK_VBNumMax.setMinimum(4)              #número mínimo de vizinhos
                    self.VB_OK_Maximum = len(self.data)                                             #self.dlg.lineEdit_OK_VBNumMax.setMaximum(len(self.data)) #número máximo de vizinhos
        
                    if len(self.data) >= 16: 
                        self.dlg.lineEdit_OK_VBNumMax.setText('16')                                 #vizinhança de 16 pontos  
                    else: 
                        self.dlg.lineEdit_OK_VBNumMax.setText(str(round(len(self.data)/2)))         #vizinhança = nr. de amostras / 2
        
        
                    #set Raio de busca 
                    self.Raio_OK_Minimum = self.min_dist                                            #self.dlg.lineEdit_OK_VBRaio.setMinimum(self.min_dist)     #distância minima na matriz de distâncias 
                    self.Raio_OK_Maximum = self.max_dist                                            #self.dlg.lineEdit_OK_VBRaio.setMaximum(self.max_dist)     #distância máxima na matriz de distâncias 
                    self.dlg.lineEdit_OK_VBRaio.setText('%.3f'  % self.max_dist)                    #self.active_distance_ini #60% da maior distancia entre dois pontos amostrais
        
        
                    ###############################################################
                    #Support Vector Machine  
        
        
                    #set neighbors 
                    self.VB_SVM_Minimum = 1                                                         #self.dlg.lineEdit_SVM_VBNumMax.setMinimum(1)              #número mínimo de vizinhos
                    self.VB_SVM_Maximum = len(self.data)                                            #self.dlg.lineEdit_SVM_VBNumMax.setMaximum(len(self.data)) #número máximo de vizinhos
        
                    #set the search radius 
                    if len(self.data) >= 16: 
                        self.dlg.lineEdit_SVM_VBNumMax.setText('16')                                #vizinhança de 16 pontos  
                    else: 
                        self.dlg.lineEdit_SVM_VBNumMax.setText(str(round(len(self.data)/2)))        #vizinhança = nr. de amostras / 2
        
                    #set Raio de Busca
                    self.Raio_SVM_Minimum = self.min_dist                                           #self.dlg.lineEdit_SVM_VBRaio.setMinimum(self.min_dist)     #distância minima na matriz de distâncias 
                    self.Raio_SVM_Maximum = self.max_dist                                           #self.dlg.lineEdit_SVM_VBRaio.setMaximum(self.max_dist)     #distância máxima na matriz de distâncias 
                    self.dlg.lineEdit_SVM_VBRaio.setText('%.3f'  % self.max_dist)                   #maior distancia entre dois pontos amostrais 
        
        
        
                    ###############################################################
                    #definido o dataframe df_SVM_Trainfeatures -> Colunas: (x, y)
        									  
                    self.df_SVM_Trainfeatures = self.df[[self.Cord_X, self.Cord_Y]] 
        
                    self.list_cov_SVM = [self.Cord_X, self.Cord_Y]   #lista de covariáveis possui X, Y
        
                    self.dlg.comboBox_SVM_Features_Adds.clear()
                    self.dlg.comboBox_SVM_Features_Adds.addItems(self.list_cov_SVM)   
        
    
                    #preenchendo o datatable Trainfeatures -> Colunas: (x, y)
                    self.load_datatable_SVM_Trainfeatures()    
    
        
                    ###############################################################
                    #definido o dataframe df_SVM_Trainlabels -> Coluna: V_target
        
        						
                    self.df_SVM_Trainlabels    = self.df[[self.v_target]] 
       
                    #preenchendo o datatable Trainlabels -> Coluna: V_target 
                    self.load_datatable_SVM_Trainlabels()     
    
        
                    #self.dlg.checkBox_Moran.setChecked(False)
                    #self.checkBox_Moran_clicked()   #exibe correlação de Moran 
        
        
                    if self.dlg.checkBox_Area_Contorno.isChecked():        
                        self.pushButton_Area_Contorno_clicked() 
        
    
                    ###############################################################
                    #definido o dataframe df_SVM_Testfeatures -> Colunas : Colunas: (x, y)
    
                    self.df_SVM_Testfeatures = pd.DataFrame(columns=[self.Cord_X, self.Cord_Y])      #dataframe vazio só com o nome das colunas 
    
        
         			###############################################################  
                    #Aba Dados
                    self.dlg.label_CRS_Layer.show() 
                    self.dlg.label_CRS_Layer.setText('CRS Layer: ' + self.lyrCRS_table_atribute) 
                    #print(self.lyrCRS_table_atribute)
        
         			###############################################################
                    #Aba Parametros e Contorno  
                    self.dlg.groupBox_Area_Contorno.setEnabled(True)
                    self.dlg.datatable_limite.setEnabled(True)
                    self.dlg.groupBox_Interv_Interp.setEnabled(True)
                    self.dlg.SpinBox_Pixel_Size_X.setEnabled(True)
                    self.dlg.SpinBox_Pixel_Size_Y.setEnabled(True)     
                    self.dlg.lineEdit_XMin.setEnabled(True)     
                    self.dlg.lineEdit_XMax.setEnabled(True)     
                    self.dlg.lineEdit_YMin.setEnabled(True)     
                    self.dlg.lineEdit_YMax.setEnabled(True)     
         
                   
         			###############################################################
                    #Aba Interpolação -> Krigagem  
                    self.dlg.groupBox_Variograma.setEnabled(True)
                    self.dlg.pushButton_VariogramaReset.setEnabled(False)  
                    self.dlg.pushButton_VariogramaAjust.setEnabled(True)  
                    self.dlg.pushButton_VariogramaSave.setEnabled(False)          
                    self.dlg.lineEdit_OK_DMax.setEnabled(True)
                    self.dlg.lineEdit_OK_lags_dist.setEnabled(True) 
                    
        
            
         			###############################################################
                    #Aba Interpolação -> SVM              
                    self.dlg.groupBox_SVM_Vars.setEnabled(True)
                    self.dlg.groupBox_SVM.setEnabled(True)
                    self.dlg.lineEdit_SVM_VBNumMax.setEnabled(True)
                    self.dlg.lineEdit_SVM_VBRaio.setEnabled(True)        
                    self.dlg.doubleSpinBox_Weight_IDW.setEnabled(True)
                    self.dlg.comboBox_SVM_Fonte.setEnabled(True)
                    
                    self.dlg.checkBox_Moran.setEnabled(True)
                    self.dlg.checkBox_RFE.setEnabled(True)
            
                    self.dlg.comboBox_SVM_Features.setEnabled(True)
                    self.dlg.comboBox_SVM_Features.addItems(self.cols_table_atribute)
                    self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                    self.dlg.pushButton_SVM.setEnabled(True)
                    self.dlg.pushButton_Validacao_Cruzada_SVM.setEnabled(True)  
        
        
         			###############################################################
                    #Aba Zona de Manejo       
                    self.dlg.pushButton_ZM_Add_Var.setEnabled(True)
        
        			
                    self.ImportQGIS = True          #Tabela de Atributos com dados da Layer do QGIS foi carregada  
        
                    self.Var_Selected = True        #Definiu a variavel para interpolação 
        
                    self.Variogram = False          #Carregou Tabela de Atributos, mas ainda não gerou semivariograma 
    
                    self.SVM_Add_Coord = False 
       
                    self.load_semivariograms()                              
        
                    self.load_maps_to_generate_ZM()                              
        
                    
                    if self.dlg.checkBox_Area_Contorno.isChecked(): 
                    
                        self.pushButton_Area_Contorno_clicked() 
        
                    #self.dlg.pushButton_ImportQGIS.setEnabled(True)
                    #progress.close() 
                
        else: 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Nenhuma Layer Qgis selecionada. Selecione uma Layer Qgis.'))
            msg_box.exec_()
 



############################################################    Aba para definição dos parâmetros  ######################################################
       
           
    def SpinBox_Pixel_Size_X_changed(self):    


            self.Cord_X_min = float(self.dlg.lineEdit_XMin.text())
            self.Cord_X_max = float(self.dlg.lineEdit_XMax.text()) 
             
            #lê o tamanho dos pixels para gerar o grid     
            self.Pixel_Size_X = self.dlg.SpinBox_Pixel_Size_X.value() 
            
            #calcula o número de intervalos em x e y 
            self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X))             
            self.dlg.lineEdit_Num_Points_X.setText(str(self.Num_Points_X)) 

            self.SVM_Add_Coord = False                                         #set False to recalculate Test_Features in SVM 

            self.df_SVM_Testfeatures = pd.DataFrame(columns=[self.Cord_X, self.Cord_Y])      #dataframe vazio só com o nome das colunas 

            self.dlg.label_SVM.hide()           
            self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
            self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
            self.dlg.label_validacao_cruzada_SVM.hide()
            self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
            self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)



    def SpinBox_Pixel_Size_Y_changed(self):    
        

            self.Cord_Y_min = float(self.dlg.lineEdit_YMin.text())
            self.Cord_Y_max = float(self.dlg.lineEdit_YMax.text()) 
             
            #lê o tamanho dos pixels para gerar o grid     
            self.Pixel_Size_Y = self.dlg.SpinBox_Pixel_Size_Y.value() 
            
            #calcula o número de intervalos em x e y 
            Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y))         
            self.dlg.lineEdit_Num_Points_Y.setText(str(Num_Points_Y)) 

            self.SVM_Add_Coord = False                                         #set False to recalculate Test_Features in SVM 
        
            self.df_SVM_Testfeatures = pd.DataFrame(columns=[self.Cord_X, self.Cord_Y])      #dataframe vazio só com o nome das colunas 

            self.dlg.label_SVM.hide()           
            self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
            self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
            self.dlg.label_validacao_cruzada_SVM.hide()
            self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
            self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)



    def lineEdit_XMin_editingFinished(self):    

        
        if float(self.dlg.lineEdit_XMin.text()) > float(self.dlg.lineEdit_XMax.text()):  #Xmin > Xmax 
            self.dlg.lineEdit_XMin.setText('%.3f' % float(self.dlg.lineEdit_XMax.text()))            
        else: 
            self.dlg.lineEdit_XMin.setText('%.3f' % float(self.dlg.lineEdit_XMin.text()))            
            
        self.SpinBox_Pixel_Size_X_changed() 
            
            
    def lineEdit_XMax_editingFinished(self):    

        
        if float(self.dlg.lineEdit_XMax.text()) < float(self.dlg.lineEdit_XMin.text()):  #Xmax < Xmin 
            self.dlg.lineEdit_XMax.setText('%.3f' % float(self.dlg.lineEdit_XMin.text()))            
        else: 
            self.dlg.lineEdit_XMax.setText('%.3f' % float(self.dlg.lineEdit_XMax.text()))            
            
        self.SpinBox_Pixel_Size_X_changed() 


    def lineEdit_YMin_editingFinished(self):    


        if float(self.dlg.lineEdit_YMin.text()) > float(self.dlg.lineEdit_YMax.text()):  #Ymin > Ymax 
            self.dlg.lineEdit_YMin.setText('%.3f' % float(self.dlg.lineEdit_YMax.text()))            
        else: 
            self.dlg.lineEdit_YMin.setText('%.3f' % float(self.dlg.lineEdit_YMin.text()))            
        
        self.SpinBox_Pixel_Size_Y_changed() 


    def lineEdit_YMax_editingFinished(self):    

        
        if float(self.dlg.lineEdit_YMax.text()) < float(self.dlg.lineEdit_YMin.text()):  #Ymax < Ymin 
            self.dlg.lineEdit_YMax.setText('%.3f' % float(self.dlg.lineEdit_YMin.text()))            
        else: 
            self.dlg.lineEdit_YMax.setText('%.3f' % float(self.dlg.lineEdit_YMax.text()))            

        self.SpinBox_Pixel_Size_Y_changed() 


            

    def checkBox_Area_Contorno_clicked(self):
        
        
        self.SVM_Add_Coord = False                                             #set False to recalculate Test_Features in SVM   

        self.df_SVM_Testfeatures = pd.DataFrame(columns=[self.Cord_X, self.Cord_Y])      #dataframe vazio só com o nome das colunas 
        
        if self.dlg.checkBox_Area_Contorno.isChecked(): 

                self.dlg.mMapLayerComboBox_AreaCont.setEnabled(True)
                self.dlg.pushButton_Area_Contorno.setEnabled(True) 
                self.dlg.comboBox_CordX_AreaCont.setEnabled(True) 
                self.dlg.comboBox_CordY_AreaCont.setEnabled(True) 
            
        else: 

            self.dlg.mMapLayerComboBox_AreaCont.setEnabled(False)
            self.dlg.pushButton_Area_Contorno.setEnabled(False)           
            self.dlg.comboBox_CordX_AreaCont.setEnabled(False) 
            self.dlg.comboBox_CordY_AreaCont.setEnabled(False) 
            if len(self.df_limite) > 0:                                        #limite foi preenchido -> tirar o limite do mapa 
                self.df_limite = pd.DataFrame(columns = ['Coord_X' , 'Coord_Y'])                    
                self.Contorno_Definido =  False                                #contorno não foi definido -> utilizar dados da tabela de atributos 


            if self.Contorno_Definido ==  False:                               #contorno não foi definido -> utilizar dados da tabela de atributos 
                self.Cord_X_min = self.df[self.Cord_X].min() 
                self.Cord_Y_min = self.df[self.Cord_Y].min() 
                self.Cord_X_max = self.df[self.Cord_X].max() 
                self.Cord_Y_max = self.df[self.Cord_Y].max() 

    
                self.dlg.lineEdit_XMin.setText('%.3f' % self.Cord_X_min)                        
                self.dlg.lineEdit_XMax.setText('%.3f' % self.Cord_X_max)                            
                self.dlg.lineEdit_YMin.setText('%.3f' % self.Cord_Y_min)                            
                self.dlg.lineEdit_YMax.setText('%.3f' % self.Cord_Y_max)                        
   
                self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X))         
                self.Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y))         

                self.dlg.lineEdit_Num_Points_X.setText(str(self.Num_Points_X)) 
                self.dlg.lineEdit_Num_Points_Y.setText(str(self.Num_Points_Y)) 
    

    			###############################################################
    			#plotar mapa de pontos amostrados    
     
                plt1.close()
                plt1.title('I.Moran: ' + str(self.moran_index) + ' P.Value: ' + str(self.p_value))
                plt1.xlabel('Longitude (X)')
                plt1.ylabel('Latitude  (Y)') 
    
                plt1.xlim(float(self.Cord_X_min-100), float(self.Cord_X_max+100))
                plt1.ylim(float(self.Cord_Y_min-100), float(self.Cord_Y_max+100))        
    

                interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
                
                if interval_x == 0:
                    interval_x = 1 #int((self.Cord_X_max-self.Cord_X_min))

                xmarks=[i for i in range(int(self.Cord_X_min),int(self.Cord_X_max) , interval_x)]          
                plt1.xticks(xmarks)
    

                interval_y = int((self.Cord_Y_max-self.Cord_Y_min)/7)

                if interval_y == 0:
                    interval_y = 1 #int((self.Cord_X_max-self.Cord_X_min))

                ymarks=[i for i in range(int(self.Cord_Y_min),int(self.Cord_Y_max) , interval_y)]          
                plt1.yticks(ymarks)

    
                if len(self.list_index_outlier) > 0: 
                   plt1.scatter(self.data_outlier[:,0], self.data_outlier[:,1], c=self.data_outlier[:,2], marker="x", cmap='RdYlGn')

                #plt1.scatter(self.data[:,0], self.data[:,1])
                plt1.scatter(self.data[:,0], self.data[:,1], c=self.data[:,2], cmap='RdYlGn', vmin = min(self.data[:,2]), vmax = max(self.data[:,2]))


                clb = plt1.colorbar(aspect=20)                                 #expessura do colorbar 
                clb.ax.set_title(self.v_target)
    
                plt1.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)
    			  
                plt1.savefig(     os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                pixmap1 = QPixmap(os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                self.dlg.label_pontos_limite.show()
                self.dlg.label_pontos_limite.setPixmap(pixmap1)

                
            

    def mMapLayerComboBox_AreaCont_changed(self):                              #evento onchange do combobox  Area Contorno  

        
        if self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0:  
            
            selectedLayer = self.dlg.mMapLayerComboBox_AreaCont.currentLayer()

            if selectedLayer.geometryType() == 0:                              #vector layer 
                
                self.cols_table_area_contorno = selectedLayer.fields().names() 
    
                self.dlg.comboBox_CordX_AreaCont.clear()
                self.dlg.comboBox_CordX_AreaCont.setEnabled(True)     
                self.dlg.comboBox_CordX_AreaCont.addItems(self.cols_table_area_contorno)
                self.dlg.comboBox_CordX_AreaCont.setCurrentIndex(0)
    
                self.dlg.comboBox_CordY_AreaCont.clear()
                self.dlg.comboBox_CordY_AreaCont.setEnabled(True) 
                self.dlg.comboBox_CordY_AreaCont.addItems(self.cols_table_area_contorno)            
                self.dlg.comboBox_CordY_AreaCont.setCurrentIndex(1)

            else:                                                              #polygon layer   
                self.dlg.comboBox_CordX_AreaCont.clear()
                self.dlg.comboBox_CordX_AreaCont.setEnabled(False) 
                self.dlg.comboBox_CordY_AreaCont.clear()
                self.dlg.comboBox_CordY_AreaCont.setEnabled(False) 
                
                
        
            
    def pushButton_Area_Contorno_clicked(self):
        
            
        selectedLayer = self.dlg.mMapLayerComboBox_AreaCont.currentLayer()     


        coordenate_reference = selectedLayer.crs().description()
        
        if 'SAD69' in coordenate_reference: 
            
            lyrCRS = QgsProject.instance().crs().authid()  #get CRS of project   EX: EPSG:32723
        
        else:      

            lyrCRS = selectedLayer.crs().authid() 


        if (lyrCRS != self.lyrCRS_table_atribute):  


            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('O CRS da Layer de Contorno é diferente do CRS da Layer da Tabela de Atributos.'))
            msg_box.exec_()


        elif (selectedLayer.geometryType() != 0) and (selectedLayer.geometryType() != 2):  #PoligonLayer 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Layer QGIS Inválida! Selecione uma Layer QGIS tipo: PointLayer ou PoligonLayer.'))
            msg_box.exec_()

        else: 

            lyrCRS = selectedLayer.crs()

            if (lyrCRS.isGeographic() == True):  #layer é lat/long

                message =  self.tr('O Sistema de Coordenadas Geográficas deve estar em UTM.') + '\n' 
                message = message + self.tr('Realize a conversão da layer de entrada para a projeção UTM antes de importá-la no Smart-Map.') + '\n'


                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(message)
                msg_box.exec_()               

            else:      

                          
                if selectedLayer.geometryType() == 2:                              #PoligonLayer 
                                      
                    
                    features = selectedLayer.getFeatures()   
                    for feature in features:
                        geom = feature.geometry()
                        
                        points = geom.asMultiPolygon()
    
    
                    list_points = points[0][0]
                    #print('list_points00:', points[0][0])    
                    
                    #points[0][0]
                    list_x = []
                    list_y = []
                    for i in range(len(list_points)): 
                        list_x.append(list_points[i].x())
                        list_y.append(list_points[i].y())
    
    
                    if len(points) > 1: 
    
                        list_points = points[1][0]
                        #print('list_points10:', points[1][0])    
     
                        for i in range(len(list_points)): 
                            list_x.append(list_points[i].x())
                            list_y.append(list_points[i].y())
                        
    
    
                    zippedList =  list(zip(list_x, list_y))                    
                                         
                    self.df_limite = pd.DataFrame(zippedList, columns = ['Coord_X' , 'Coord_Y'])                    
    
                    self.df_limite.to_csv(os.path.join(self.path_absolute , '0_Limite_Contorno.csv'), sep=',', index=False, encoding='utf-8')
                    
    
                if selectedLayer.geometryType() == 0:                              #PointLayer 
                
                
                    QgsVectorFileWriter.writeAsVectorFormat(selectedLayer, os.path.join(self.path_absolute , '0_Limite_Contorno.csv'), "utf-8", lyrCRS, "CSV")  
            
                    filename = os.path.join(self.path_absolute , '0_Limite_Contorno.csv')  
               
        
                    self.df_limite = pd.read_csv(filename, sep = ',')  
            
                    Cord_X_cont =   self.dlg.comboBox_CordX_AreaCont.currentText()    
                    Cord_Y_cont =   self.dlg.comboBox_CordY_AreaCont.currentText()     
        
                    self.df_limite = self.df_limite[[Cord_X_cont, Cord_Y_cont]] 
                
                    tot_nan = self.df_limite.isnull().sum().sum()
        
                    if tot_nan > 0: 
                        
                        self.df_limite.dropna(inplace=True)                        #apaga linhas com valores nulos 
                        self.df_limite.reset_index(drop = True, inplace=True)      #reset the index without new colum index    
            
                
                #monta o datatable dflimite         
                cols = [] 
                cols = list(self.df_limite.columns.values)  
                
                self.df_limite.rename({cols[0]: 'Coord_X', cols[1]: 'Coord_Y'}, axis=1, inplace=True)                #renomeia as colunas do df_limite
                                
                self.df_limite = pd.concat([self.df_limite, self.df_limite.iloc[[0]]], ignore_index=True, axis = 0)  #concantena depois da ultima linha a primeira linha para fechar a area de contorno
                
                
                self.data_limite = np.array( self.df_limite, dtype=float )       
                
                self.dlg.datatable_limite.setColumnCount(len(self.df_limite.columns))
                self.dlg.datatable_limite.setRowCount(len(self.df_limite.index))
                
                #preencher o cabeçalho
                try:                       
                               
                    cols = [] 
                    cols = list(self.df_limite.columns.values)                        
                    self.dlg.datatable_limite.setHorizontalHeaderLabels(cols)
    
                except AttributeError: 
    
                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                    msg_box.exec_()
                    
                
                #preencher as linhas da planilha 
                try:                       
                    for i in range(len(self.df_limite.index)):          #linhas 
                        for j in range(len(self.df_limite.columns)):    #colunas 
    
                            valor = self.df_limite.iloc[i,j]
    
                            if valor.dtype == "float64": 
                                valor = '%.3f' % valor                       
                            
                            valor = QTableWidgetItem(str(valor))                  
                            self.dlg.datatable_limite.setItem(i,j, valor)
    
                except AttributeError: 
    
                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                    msg_box.exec_()
        
    
                self.dlg.datatable_limite.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable
                
                             
    
                #lê as coordenadas X e Y da área de contorno 
                
                self.Cord_X_min = self.df_limite['Coord_X'].min() 
                self.Cord_X_max = self.df_limite['Coord_X'].max() 
                self.Cord_Y_min = self.df_limite['Coord_Y'].min() 
                self.Cord_Y_max = self.df_limite['Coord_Y'].max() 
    
    
                self.dlg.lineEdit_XMin.setText(str('%.3f' % self.Cord_X_min))
                self.dlg.lineEdit_YMin.setText(str('%.3f' % self.Cord_Y_min))
                self.dlg.lineEdit_XMax.setText(str('%.3f' % self.Cord_X_max))
                self.dlg.lineEdit_YMax.setText(str('%.3f' % self.Cord_Y_max))
    
               
                #lê o tamanho dos pixels para gerar o grid     
                self.Pixel_Size_X = self.dlg.SpinBox_Pixel_Size_X.value() 
                self.Pixel_Size_Y = self.dlg.SpinBox_Pixel_Size_Y.value() 
                
                #calcula o número de pontos em x e y 
                self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X))         
                self.Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y))         
            
             
                self.dlg.lineEdit_Num_Points_X.setText(str(self.Num_Points_X)) 
                self.dlg.lineEdit_Num_Points_Y.setText(str(self.Num_Points_Y)) 
            
    
    
                polygono = np.array(self.df_limite, dtype=float)                #define o polygono = area de contorno 
                bbPath = mplPath.Path(polygono)
    
                #drop points out of polygon 
                self.list_index_out_polygon = [] 
                for i in range(len(self.df)):
                    ponto = (self.df.iloc[i][self.Cord_X], self.df.iloc[i][self.Cord_Y])
                    if not bbPath.contains_point(ponto): 
                        self.list_index_out_polygon.append(i)
    
                #print('list_index_out_polygon',  self.list_index_out_polygon)        
                        
                        
                if len(self.list_index_out_polygon) > 0: 
    
                    self.df.drop(self.df.index[self.list_index_out_polygon], inplace=True)
                    self.df.reset_index(drop = True, inplace=True)
                    self.load_datatable_atribute_table()
    
                    self.df_SVM_Trainfeatures.drop(self.df_SVM_Trainfeatures.index[self.list_index_out_polygon], inplace=True)
                    self.df_SVM_Trainfeatures.reset_index(drop = True, inplace=True)
                    self.load_datatable_SVM_Trainfeatures()
                    
                    self.df_SVM_Trainlabels.drop(self.df_SVM_Trainlabels.index[self.list_index_out_polygon], inplace=True)
                    self.df_SVM_Trainlabels.reset_index(drop = True, inplace=True)
                    self.load_datatable_SVM_Trainlabels()
    
                    self.xy.drop(self.xy.index[self.list_index_out_polygon], inplace=True)
                    self.xy.reset_index(drop = True, inplace=True)
    
                    self.z.drop(self.z.index[self.list_index_out_polygon], inplace=True)
                    self.z.reset_index(drop = True, inplace=True)
    
            
                #plotar mapa de pontos e Area Limite     
                self.data = self.df[[self.Cord_X, self.Cord_Y, self.v_target]] 
                self.data = np.array( self.data, dtype=float )
    
    
        
                plt1.close()
                plt1.title('I.Moran: ' + str(self.moran_index) + ' P.Value: ' + str(self.p_value))
                plt1.xlabel('Longitude (X)')
                plt1.ylabel('Latitude  (Y)') 
    
                plt1.xlim(float(self.Cord_X_min-100), float(self.Cord_X_max+100))
                plt1.ylim(float(self.Cord_Y_min-100), float(self.Cord_Y_max+100))        
    
    
                interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
                
                if interval_x == 0:
                    interval_x = 1 #int((self.Cord_X_max-self.Cord_X_min))
    
                xmarks=[i for i in range(int(self.Cord_X_min),int(self.Cord_X_max) , interval_x)]          
                plt1.xticks(xmarks)
     
        
                interval_y = int((self.Cord_Y_max-self.Cord_Y_min)/7)
    
                if interval_y == 0:
                    interval_y = 1 #int((self.Cord_Y_max-self.Cord_Y_min))
    
                ymarks=[i for i in range(int(self.Cord_Y_min),int(self.Cord_Y_max) , interval_y)]          
                plt1.yticks(ymarks)
        
        
                plt1.plot(self.data_limite[:,0], self.data_limite[:,1])
    
                if len(self.list_index_outlier) > 0: 
                   plt1.scatter(self.data_outlier[:,0], self.data_outlier[:,1], c=self.data_outlier[:,2], marker="x", cmap='RdYlGn')
    
                #plt1.scatter(self.data[:,0], self.data[:,1])
                plt1.scatter(self.data[:,0], self.data[:,1], c=self.data[:,2], cmap='RdYlGn', vmin = min(self.data[:,2]), vmax = max(self.data[:,2]))

                clb = plt1.colorbar(aspect=20)                                     #expessura do colorbar 
                clb.ax.set_title(self.v_target)
    
                plt1.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)
                  
                plt1.savefig(os.path.join(     self.path_absolute , '0_Limite_Contorno.png'))
                pixmap1 = QPixmap(os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                self.dlg.label_pontos_limite.show()
                self.dlg.label_pontos_limite.setPixmap(pixmap1)
    
    
                self.SVM_Add_Coord = False                                         #set False to recalculate Test_Features in SVM   
                #self.dlg.pushButton_SVM.setEnabled(False)
                self.df_SVM_Testfeatures = pd.DataFrame(columns=[self.Cord_X, self.Cord_Y])      #dataframe vazio só com o nome das colunas 
    
    
    
                if self.SVM_Add_Feature == True:                                   #Adicionou features ao modelo SVM  -> serão retiradas pois alterou os parâmetros do SVM 
        
                    for i in range(2,len(self.list_cov_SVM)): 
                        self.dlg.comboBox_SVM_Features_Adds.setCurrentIndex(i)
                        self.pushButton_SVM_Remove_Feature_clicked()
    
    
    
                self.Contorno_Definido = True   #Definiu o contorno do mapa 
        
                #self.Variogram = False         #Não ajustou o Variograma 
    
    
                self.dlg.label_SVM.hide()           
                self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
                self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
                self.dlg.label_validacao_cruzada_SVM.hide()
                self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
                self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)


    def label_pontos_limite_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  

            if self.Contorno_Definido == True:                
                image = Image.open(os.path.join(self.path_absolute , '0_Limite_Contorno.png'))
                image.show()


    def pushButton_File_Save_clicked(self):

             
        foo_dir = QFileDialog.getExistingDirectory(self.dlg, self.tr('Selecione um diretório'), expanduser("~"))
        
        if foo_dir != '':                   #usuário selecionou um diretório válido 
            self.dlg.lineEdit.setText(os.path.join(foo_dir))
            self.path_absolute = os.path.join(foo_dir)  
       
        

############################################################    Aba para calcular interpolação por krigagem  #################################################################
    

    def load_semivariograms (self):                               


        selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()
        layer_name  = selectedLayer.name()

        filename = os.path.join(self.path_absolute , '0_Semivariograms_' + layer_name + '.csv')  


        self.list_rows_semiv = []

        if os.path.isfile(filename):  

            self.df_semivariograms  = pd.read_csv(filename, sep = ',')  

            self.dlg.datatable_semivariogramas.setColumnCount(12)  
            self.dlg.datatable_semivariogramas.setRowCount(len(self.df_semivariograms.index))
   
            #preencher o cabeçalho
            try:                       
    
                cols = [self.tr('Marcar'), 'Z', self.tr('Modelo'), self.tr('Distância Máxima'), self.tr('Distância (h)'), self.tr('Efeito Pepita'), self.tr('Contribuição'), self.tr('Alcance'), self.tr('RMSE'), 'R2', self.tr('Raio'), self.tr('Vizinhos')] 
                self.dlg.datatable_semivariogramas.setHorizontalHeaderLabels(cols)
    
            except AttributeError: 
    
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
                
           
            #preencher as linhas da planilha 
            try:                       
                for i in range(len(self.df_semivariograms.index)):             #linhas 

                    
                    chkBoxItem = QTableWidgetItem()
                    chkBoxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
                    chkBoxItem.setCheckState(QtCore.Qt.Unchecked)       
                    self.dlg.datatable_semivariogramas.setItem(i,0,chkBoxItem)           

                    for j in range(11):       #colunas 
    
                        valor = self.df_semivariograms.iloc[i,j]
                       
                        if j >= 2: 
                            if valor.dtype == "float64": 
                                valor = '%.3f' % valor                             
                            
                        valor = QTableWidgetItem(str(valor))                  
                        self.dlg.datatable_semivariogramas.setItem(i,j+1, valor)
    
            except AttributeError: 
    
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
    
    
            self.dlg.datatable_semivariogramas.resizeColumnsToContents();
            
            self.dlg.datatable_semivariogramas.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable


        #Arquivo de Semivariogramas não existe só preenche o cabeçalho. 
        else: 

            self.dlg.datatable_semivariogramas.setColumnCount(12)
            self.dlg.datatable_semivariogramas.setRowCount(0)
            
            #preencher o cabeçalho
            try:                       
    
                cols = [self.tr('Marcar'), 'Z', self.tr('Modelo'), self.tr('Distância Máxima'), self.tr('Distância (h)'), self.tr('Efeito Pepita'), self.tr('Contribuição'), self.tr('Alcance'), self.tr('RMSE'), 'R2', self.tr('Raio'), self.tr('Vizinhos')] 
                self.dlg.datatable_semivariogramas.setHorizontalHeaderLabels(cols)
    
            except AttributeError: 
    
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()


    def datatable_semivariogramas_doubleClicked(self): 

        row = self.dlg.datatable_semivariogramas.currentRow()

        if row >= 0:
            v_target = self.dlg.datatable_semivariogramas.item(row, 1).text()  #obtem o valor da 2ª coluna da linha selecionada 

            #verificar se v_target escolhida já tem semivariograma calculado             
            selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()
            layer_name  = selectedLayer.name()
    
            filename = os.path.join(self.path_absolute , '0_Semivariograms_' + layer_name + '.csv')  
   
            self.df_semivariograms  = pd.read_csv(filename, sep = ',')  
    
            #pesquisar se já foi calculado o semivariograma da variavel -> se sim, exibe semivariograma calculado da variável  
            semiv_calculated = -1 

            for i in range(len(self.df_semivariograms.index)):                 #linhas 
    
                    
                    if v_target == self.df_semivariograms.iloc[i,0]:           #calculou o variograma de uma variável que já foi calculada -> substituir

                        semiv_calculated = i
                        

            if  semiv_calculated >= 0: #Semivariograma já foi calculado -> exibir os resultados do semivariograma calculado 

                self.dlg.comboBox_VTarget.setCurrentText(v_target)             
                self.pushButton_ImportQGIS_clicked()                           #evento onClick do botão Importar             


                Modelo = self.df_semivariograms.iloc[semiv_calculated,1]
                DMax   = float(self.df_semivariograms.iloc[semiv_calculated,2])
                Lag    = float(self.df_semivariograms.iloc[semiv_calculated,3])
                C0     = float(self.df_semivariograms.iloc[semiv_calculated,4])
                C0_C   = float(self.df_semivariograms.iloc[semiv_calculated,5])
                Range  = float(self.df_semivariograms.iloc[semiv_calculated,6])
                RMSE   = float(self.df_semivariograms.iloc[semiv_calculated,7])
                R2     = float(self.df_semivariograms.iloc[semiv_calculated,8])   
                Raio   = float(self.df_semivariograms.iloc[semiv_calculated,9])   
                VB     = int(self.df_semivariograms.iloc[semiv_calculated,10])    

                self.max_dist  = float(self.df_semivariograms.iloc[semiv_calculated,11])
                self.min_dist  = float(self.df_semivariograms.iloc[semiv_calculated,12])
                self.C0_Maximum    = float(self.df_semivariograms.iloc[semiv_calculated,13])
                self.C0_Minimum    = float(self.df_semivariograms.iloc[semiv_calculated,14])
                self.C0_C_Maximum  = float(self.df_semivariograms.iloc[semiv_calculated,15])
                self.C0_C_Minimum  = float(self.df_semivariograms.iloc[semiv_calculated,16])
                self.Range_Maximum = float(self.df_semivariograms.iloc[semiv_calculated,17])
                self.Range_Minimum = float(self.df_semivariograms.iloc[semiv_calculated,18])
                self.Raio_OK_Maximum  = float(self.df_semivariograms.iloc[semiv_calculated,19])
                self.Raio_OK_Minimum  = float(self.df_semivariograms.iloc[semiv_calculated,20])
                self.VB_OK_Maximum    = int(self.df_semivariograms.iloc[semiv_calculated,21])
                self.VB_OK_Minimum    = int(self.df_semivariograms.iloc[semiv_calculated,22])


                #evento onchange do combobox Modelo Variogram
                try: 
                    self.dlg.comboBox_Modelo.currentIndexChanged.disconnect()                                 
                except TypeError:
                    pass  # Ignore the error if no connections exist               
                    

                if (Modelo == 'Linear') or (Modelo == 'Linear'):
                   self.dlg.comboBox_Modelo.setCurrentIndex(0)
                elif (Modelo == 'Linear to Sill') or (Modelo == 'Linear com Patamar'):      
                   self.dlg.comboBox_Modelo.setCurrentIndex(1)
                elif (Modelo == 'Exponential') or (Modelo == 'Exponencial'):       
                   self.dlg.comboBox_Modelo.setCurrentIndex(2)
                elif (Modelo == 'Spherical') or (Modelo == 'Esférico'):       
                   self.dlg.comboBox_Modelo.setCurrentIndex(3)
                elif (Modelo == 'Gaussian') or (Modelo == 'Gaussiano'):       
                   self.dlg.comboBox_Modelo.setCurrentIndex(4)


                #evento onchange do combobox Modelo Variogram  
                self.dlg.comboBox_Modelo.currentIndexChanged.connect(self.comboBox_Modelo_changed)     


                self.dlg.lineEdit_OK_DMax.setText('%.3f' % DMax)        

                self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % Lag)        


                #Nugget 
                if self.hide_horizontalSlider == False: 

                    try: 
                       self.dlg.horizontalSlider_Nugget.valueChanged.disconnect()
                    except TypeError:
                        pass  # Ignore the error if no connections exist               
                       
    
                    self.dlg.horizontalSlider_Nugget.setMinimum(int(self.C0_Minimum*1000))                    #último valor de gamma (eixo y)       
                    self.dlg.horizontalSlider_Nugget.setMaximum(int(self.C0_Maximum*1000))                    #último valor de gamma (eixo y)       
                    self.dlg.horizontalSlider_Nugget.setValue(int(C0*1000))
            
                    self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)

                self.dlg.lineEdit_Nugget.setText('%.3f' % C0)                                        #último valor de gamma (eixo y)       


                #Sill
                if self.hide_horizontalSlider == False: 

                    try: 
                        self.dlg.horizontalSlider_Sill.valueChanged.disconnect()
                    except TypeError:
                        pass  # Ignore the error if no connections exist               
                        
            
                    self.dlg.horizontalSlider_Sill.setMinimum(int(self.C0_C_Minimum*1000))                    #último valor de gamma (eixo y)
                    self.dlg.horizontalSlider_Sill.setMaximum(int(self.C0_C_Maximum*1000))                    #último valor de gamma (eixo y)         
                    self.dlg.horizontalSlider_Sill.setValue(int(C0_C*1000))                                   #Patamar           (Co + C)           
           
                    self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)

                self.dlg.lineEdit_Sill.setText('%.3f' % C0_C) 

                #Range 
                if self.hide_horizontalSlider == False: 

                    try: 
                        self.dlg.horizontalSlider_Range.valueChanged.disconnect()
                    except TypeError:
                        pass  # Ignore the error if no connections exist               
                        
                    
                    self.dlg.horizontalSlider_Range.setMinimum(int(self.Range_Minimum*1000))                  #maxima distancia entre os pontos   
                    self.dlg.horizontalSlider_Range.setMaximum(int(self.Range_Maximum*1000))                  #maxima distancia entre os pontos   
                    self.dlg.horizontalSlider_Range.setValue(int(Range*1000))
                    
                    self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)


                self.dlg.lineEdit_Range.setText('%.3f' % Range)                                      #alcance  efetivo  (A)       



                self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % Raio)     

                self.dlg.lineEdit_OK_VBNumMax.setText(str(VB)) 

                self.dlg.lineEdit_Var_RMSE.setText('%.3f' % RMSE)              #RMSE
                self.dlg.lineEdit_Var_R2.setText('%.3f'   % R2)                #R2


    
                self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  
   
                self.plot_variogram()
                
                self.dlg.pushButton_VariogramaSave.setEnabled(True) 

                self.dlg.pushButton_Validacao_Cruzada_OK.setEnabled(True) 
    
                self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 

                self.Variogram = True  



        
    def pushButton_VariogramaSave_clicked(self):                               #ação do botão de salvar os semivariogramas


        #preenche o dataframe com os dados do semivariograma gerado 
        Z       = self.dlg.comboBox_VTarget.currentText()
        Modelo  = self.dlg.comboBox_Modelo.currentText()
        DMax    = float(self.dlg.lineEdit_OK_DMax.text())
        Lag     = float(self.dlg.lineEdit_OK_lags_dist.text())
        C0      = float(self.dlg.lineEdit_Nugget.text())
        C0_C    = float(self.dlg.lineEdit_Sill.text())
        Range   = float(self.dlg.lineEdit_Range.text())


        DMax_Maximum  = self.max_dist
        DMax_Minimum  = self.min_dist

        C0_Maximum    = self.C0_Maximum    #self.dlg.horizontalSlider_Nugget.maximum()/1000.0
        C0_Minimum    = self.C0_Minimum    #self.dlg.horizontalSlider_Nugget.minimum()/1000.0

        C0_C_Maximum  = self.C0_C_Maximum  #self.dlg.horizontalSlider_Sill.maximum()/1000.0
        C0_C_Minimum  = self.C0_C_Minimum  #self.dlg.horizontalSlider_Sill.minimum()/1000.0

        Range_Maximum = self.Range_Maximum #self.dlg.horizontalSlider_Range.maximum()/1000.0
        Range_Minimum = self.Range_Minimum #self.dlg.horizontalSlider_Range.minimum()/1000.0

        Raio_Maximum  = self.Raio_OK_Maximum
        Raio_Minimum  = self.Raio_OK_Minimum

        VB_Maximum    = self.VB_OK_Maximum
        VB_Minimum    = self.VB_OK_Minimum



        RMSE   = float(self.dlg.lineEdit_Var_RMSE.text())  
        R2     = float(self.dlg.lineEdit_Var_R2.text())   

        Raio   = float(self.dlg.lineEdit_OK_VBRaio.text())
        
        VB     = int(self.dlg.lineEdit_OK_VBNumMax.text())

        selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()
        layer_name  = selectedLayer.name()

        filename = os.path.join(self.path_absolute , '0_Semivariograms_' + layer_name + '.csv')

        #verifica se arquivo se semivariogramas existe 
        if os.path.isfile(filename):  

            self.df_semivariograms  = pd.read_csv(filename, sep = ',')  

            #pesquisar se variavel já foi calculado o semivariograma -> se sim, excluir linha 
            semiv_calculated = False 
            for i in range(len(self.df_semivariograms.index)):          #linhas 
    
                    v_target = self.df_semivariograms.iloc[i,0]
                    
                    if Z == v_target:  #calculou o variograma de uma variável que já foi calculada -> substituir

                        semiv_calculated = True 
                        msg = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr('Deseja substituir o semivariograma de: ') + Z + ' ?', QMessageBox.Yes | QMessageBox.No)

                        if msg == QMessageBox.Yes:
                        
                            #self.df_semivariograms.drop(i, inplace=True)    #remove a linha 
                            self.df_semivariograms.loc[i] = np.array([Z, Modelo,  DMax, Lag,  C0, C0_C, Range, RMSE,  R2, Raio, VB, DMax_Maximum, DMax_Minimum, C0_Maximum, C0_Minimum, C0_C_Maximum, C0_C_Minimum, Range_Maximum, Range_Minimum, Raio_Maximum, Raio_Minimum, VB_Maximum, VB_Minimum])


            if semiv_calculated == False: 
                #insere uma nova linha ao final do dataframe com os dados do semivariograma calculado 
                self.df_semivariograms.loc[len(self.df_semivariograms)] = np.array([Z, Modelo,  DMax, Lag,  C0, C0_C, Range, RMSE,  R2, Raio, VB, DMax_Maximum, DMax_Minimum, C0_Maximum, C0_Minimum, C0_C_Maximum, C0_C_Minimum, Range_Maximum, Range_Minimum, Raio_Maximum, Raio_Minimum, VB_Maximum, VB_Minimum])
                 
        #arquivo de semivariogramas não existe -> cria um dataframe vazio 
        else: 
            
            #cria um dataframe vazio só com o nome das colunas 
            self.df_semivariograms = pd.DataFrame(columns=['Z', 'modelo',  'max_dist', 'lag', 'C0', 'C0_C',  'Range',  'RMSE',   'R2', 'Raio', 'Vizinhos', 'DMax_Maximum', 'DMax_Minimum', 'C0_Maximum', 'C0_Minimum', 'C0_C_Maximum', 'C0_C_Minimum', 'Range_Maximum', 'Range_Minimum', 'Raio_Maximum', 'Raio_Minimum', 'VB_Maximum', 'VB_Minimum'])


            #insere uma nova linha ao final do dataframe com os dados do semivariograma calculado 
            self.df_semivariograms.loc[len(self.df_semivariograms)] = np.array([Z, Modelo,  DMax, Lag,  C0, C0_C, Range, RMSE,  R2, Raio, VB, DMax_Maximum, DMax_Minimum, C0_Maximum, C0_Minimum, C0_C_Maximum, C0_C_Minimum, Range_Maximum, Range_Minimum, Raio_Maximum, Raio_Minimum, VB_Maximum, VB_Minimum])


        #salva o arquivo .csv do semivariograma  
        self.df_semivariograms.to_csv(os.path.join(self.path_absolute , '0_Semivariograms_' + layer_name + '.csv'), sep=',', index=False, encoding='utf-8')

        #carrega lista de semivariogramas salvos na interface do plugin  
        self.load_semivariograms() 
        


    def calculate_variogram(self, initial_variogram, Nugget_Range_Sill): 
        

        #evento onchange do combobox Modelo Variogram
        try: 
            self.dlg.comboBox_Modelo.currentIndexChanged.disconnect()                                 
        except TypeError:
            pass  # Ignore the error if no connections exist               

       
        
        #groupbox variograma experimental
        self.active_distance = float(self.dlg.lineEdit_OK_DMax.text())         #distância máxima 
        self.lag_distance    = float(self.dlg.lineEdit_OK_lags_dist.text())    #distância entre lags    

               
        ###Constrõe o objeto
        #informa xy e z
        Semiv = semivariogram.Semivariogram(self.xy, self.z)

        #Variancia
        self.variancia = Semiv.sample_variance

        #Determina o semivariograma experimental
        #Retorna o vetor de distância média de cada lag, a semivariancia e o número de pares de pontos
        #usado para construir cada lag
        self.lag, self.gamma, self.npoints = Semiv.Exp_Semiv(self.lag_distance, self.active_distance)
        

        while ( len(self.npoints) < 2):   #deve ter no mínimo 2 pontos 
            self.lag_distance = self.lag_distance - 1
            self.lag, self.gamma, self.npoints = Semiv.Exp_Semiv(self.lag_distance, self.active_distance)


        #######################################################################
        #Calcula Variograma Inicial 

        if initial_variogram == True:   #gerar o semivariograma pela primeira vez 
        

            #Lista dos modelos que o usuário deseja ajustar o semivariograma experimental
            use_models = ['linear','linear-sill','exponential','spherical','gaussian'] #,'hole-effect']
    
            #Ajusta o semivariograma para cada um dos modelos
            #Retorno é um dicionário. Ver a descrição da Função
            #Faz tentativas de ajuste sem erro.
            #Muda Lag Distance
            while True: 
                try:
                    self.models = Semiv.Fit(use_models)
                except ValueError as error:
                    if 'is infeasible' in str(error):
                        self.lag_distance = self.lag_distance + 1
                        
                        #Constroi o semivariograma experimental
                        #Retorna o vetor de distância média de cada lag, a semivariancia e o número de pares de pontos
                        #usado para construir cada lag
                        self.lag, self.gamma, self.npoints = Semiv.Exp_Semiv(self.lag_distance, self.active_distance)
                #Conseguiu realizar o ajuste
                else:
                    break


            #Encontra o melhor modelo (menor rss)
            min_rss = self.models['linear'][3]
            
            Model = 'linear'
            
            for i in self.models:

                if self.models[i][3] < min_rss : 
                    min_rss = self.models[i][3]
                    Model = i
            
            
            
             
            if Model == 'linear':
               self.dlg.comboBox_Modelo.setCurrentIndex(0)
            elif Model == 'linear-sill':      
               self.dlg.comboBox_Modelo.setCurrentIndex(1)
            elif Model == 'exponential':       
               self.dlg.comboBox_Modelo.setCurrentIndex(2)
            elif Model == 'spherical':       
               self.dlg.comboBox_Modelo.setCurrentIndex(3)
            elif Model == 'gaussian':       
               self.dlg.comboBox_Modelo.setCurrentIndex(4)
    
            self.model = Model  
            

            #Calcula a semivariância teorica, para um modelo especifico, 
            #a partir do nome do modelo , efeito pepita (nugget ),  alcance (range) and patamar (sill)
            
            #Calcula a semivariância teórica (gamma_t), obtendo ainda o RSS e o R2
            # models[model][0:3]  contêm nugget, range e sill
            self.gamma_t, rss, r2 = Semiv.Gamma(self.model, self.models[self.model][0:3])
    
    
            #dicionario: models[model][Nugget,Range,Sill,rss,r2]
            Nugget = self.models[self.model][0]
            Range  = self.models[self.model][1]
            Sill   = self.models[self.model][2]
            Rss    = self.models[self.model][3]
            R2     = self.models[self.model][4]  
                 
            #print(Nugget, Sill, Range, Rss, R2)


        #######################################################################
        #Variograma Inicial já foi calculado -> obtem ajustes do usuário a partir da GUI              

        #houve primeiro ajuste -> novos ajustes irão pegar as configurações do usuário 
        #Modelo, active_distance, lag_distance, Nugget, Sill, Range 


        if initial_variogram == False:   

            
            #Constroi o semivariograma teórico 
            #Calcula a semivariância teorica, para um modelo especifico, 
            #a partir do nome do modelo , efeito pepita (nugget ),  alcance (range) and patamar (sill)
    
            #groub box Modelo de Variograma             
            if self.dlg.comboBox_Modelo.currentIndex()   == 0:       
                use_models = ['linear'] 
            elif self.dlg.comboBox_Modelo.currentIndex() == 1:           
                use_models = ['linear-sill'] 
            elif self.dlg.comboBox_Modelo.currentIndex() == 2:                
                use_models = ['exponential'] 
            elif self.dlg.comboBox_Modelo.currentIndex() == 3:                
                use_models = ['spherical'] 
            elif self.dlg.comboBox_Modelo.currentIndex() == 4:                
                use_models = ['gaussian'] 
            

            #Ajusta o semivariograma para cada um dos modelos
            #Retorno é um dicionário. Ver a descrição da Função
            #Faz tentativas de ajuste sem erro.
            #Muda Lag Distance
            while True: 
                try:
                    self.models = Semiv.Fit(use_models)
                except ValueError as error:
                    if 'is infeasible' in str(error):
                        self.lag_distance = self.lag_distance + 1
                        
                        #Constroi o semivariograma experimental
                        #Retorna o vetor de distância média de cada lag, a semivariancia e o número de pares de pontos
                        #usado para construir cada lag
                        self.lag, self.gamma, self.npoints = Semiv.Exp_Semiv(self.lag_distance, self.active_distance)
                #Conseguiu realizar o ajuste
                else:
                    break


           
            self.model =  use_models[0] 

                      
            ###################################################################
            #Nugget, Range, Sill foram informados pelo usuário na GUI -> repassa ao modelo 
            #utilizado apenas no evento onchange do combobox modelo 
            if Nugget_Range_Sill == True: 
   
               
                Nugget = float(self.dlg.lineEdit_Nugget.text())                #efeito pepita     (Co) 
                Range  = float(self.dlg.lineEdit_Range.text())                 #alcance  efetivo  (A)
                Sill   = float(self.dlg.lineEdit_Sill.text())                  #Patamar           (Co + C)
           
                self.models[self.model][0] = Nugget 
                self.models[self.model][1] = Range
                self.models[self.model][2] = Sill

            
            #Calcula a semivariância teórica (gamma_t), obtendo o RSS e o R2
            # models[model][0:3]  contêm nugget, range e sill
            self.gamma_t, rss, r2 = Semiv.Gamma(self.model, self.models[self.model][0:3])
    

            #dicionario: models[model][Nugget,Range,Sill,rss,r2]        
            Nugget = self.models[self.model][0]
            Range  = self.models[self.model][1]
            Sill   = self.models[self.model][2]
            Rss    = rss
            R2     = r2



        #######################################################################
        #Parametros do Semivariograma serão colocados na GUI  

        #self.dlg.lineEdit_Nugget.setText('%.3f'   % Nugget)                   #efeito pepita     (Co) 
        #self.dlg.lineEdit_Range.setText( '%.3f'    % Range)                   #alcance  efetivo  (A)
        #self.dlg.lineEdit_Sill.setText( '%.3f'     % Sill)                    #Patamar           (Co + C)           

        self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % self.lag_distance)     #Lag (h)              
        self.dlg.lineEdit_Var_RMSE.setText('%.3f' % Rss)                       #RMSE
        self.dlg.lineEdit_Var_R2.setText('%.3f'   % R2)                        #R2


        if (R2 >= -1) and (R2 <= 1): 
            self.dlg.lineEdit_Var_R2.setText('%.3f'   % R2)                   
        else: 
            if (R2 < -1): 
                self.dlg.lineEdit_Var_R2.setText('-inf')               
            if (R2 >  1): 
                self.dlg.lineEdit_Var_R2.setText('+inf')               



             #Nugget                                                   #Range                                    #Sill
        if (((self.gamma[len(self.gamma)-1])*1000) >  2147483647) or ((Semiv.max_dist*1000) >  2147483647) or ((((self.gamma[len(self.gamma)-1])*3)*1000) >  2147483647): 
            self.hide_horizontalSlider = True 
        else: 
            self.hide_horizontalSlider = False 
            


        #Nugget 
        if self.hide_horizontalSlider == True:                                      #limite máximo do GUI horizontalslider 

            self.dlg.horizontalSlider_Nugget.hide()

            self.C0_Maximum = self.gamma[len(self.gamma)-1]                                         #último valor de gamma (eixo y)       
            self.C0_Minimum = 0
            self.dlg.lineEdit_Nugget.setText('%.3f'  % Nugget)                                      #último valor de gamma (eixo y)       


        else:     

            self.dlg.horizontalSlider_Nugget.show()
            
            try: 
                self.dlg.horizontalSlider_Nugget.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                

            self.dlg.horizontalSlider_Nugget.setMaximum(int((self.gamma[len(self.gamma)-1])*1000))       #último valor de gamma (eixo y)       
            self.C0_Maximum = self.gamma[len(self.gamma)-1]                                         #último valor de gamma (eixo y)       
            self.C0_Minimum = 0
            self.dlg.horizontalSlider_Nugget.setValue(int(Nugget*1000))      
            self.dlg.lineEdit_Nugget.setText('%.3f'  % Nugget)                                      #último valor de gamma (eixo y)       

            self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)


        #Range 
        if self.hide_horizontalSlider == True:                                      #limite máximo do GUI horizontalslider 

            self.dlg.horizontalSlider_Range.hide()

            self.Range_Maximum = Semiv.max_dist                                                         #último valor de gamma (eixo y)       
            self.Range_Minimum = 0.001
            self.dlg.lineEdit_Range.setText('%.3f'  % Range)                                            #último valor de gamma (eixo y)       

        else:     

            self.dlg.horizontalSlider_Range.show()

            try: 
                self.dlg.horizontalSlider_Range.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
               
   
            self.dlg.horizontalSlider_Range.setMaximum(int(Semiv.max_dist*1000))                             #maxima distancia entre os pontos   
            self.Range_Maximum = Semiv.max_dist                                                         #último valor de gamma (eixo y)       
            self.Range_Minimum = 0.001
    
            self.dlg.horizontalSlider_Range.setValue(int(Range*1000))
            self.dlg.lineEdit_Range.setText('%.3f'  % Range)                                            #último valor de gamma (eixo y)       

            self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)

        #Raio de Busca 
        if self.dlg.checkBox_Krigagem_Alcance.isChecked(): 
            Raio   = float(self.dlg.lineEdit_Range.text())                                          #raio de busca -> pegar o valor do alcance  
            self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % Raio)                     


        #Sill
        if self.hide_horizontalSlider == True:                                      #limite máximo do GUI horizontalslider 

            self.dlg.horizontalSlider_Sill.hide()

            self.C0_C_Maximum = (self.gamma[len(self.gamma)-1])*3                                       #último valor de gamma (eixo y)       
            self.C0_C_Minimum = 0 
            self.dlg.lineEdit_Sill.setText('%.3f'  % Sill)  

        else:     

            self.dlg.horizontalSlider_Sill.show()

            try: 
                self.dlg.horizontalSlider_Sill.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
    
    
            self.dlg.horizontalSlider_Sill.setMaximum(int(((self.gamma[len(self.gamma)-1])*3)*1000))         #último valor de gamma (eixo y)         
            self.C0_C_Maximum = (self.gamma[len(self.gamma)-1])*3                                       #último valor de gamma (eixo y)       
            self.C0_C_Minimum = 0 
    
            self.dlg.horizontalSlider_Sill.setValue(int(Sill*1000))
            self.dlg.lineEdit_Sill.setText('%.3f'  % Sill)  
    
            self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)


        self.dlg.comboBox_Modelo.currentIndexChanged.connect(self.comboBox_Modelo_changed)      #evento onchange do combobox Modelo Variogram  


    def plot_variogram(self): 


        Nugget = float(self.dlg.lineEdit_Nugget.text())                        #efeito pepita     (Co) 
        Rss    = float(self.dlg.lineEdit_Var_RMSE.text())                      #RMSE
        R2     = float(self.dlg.lineEdit_Var_R2.text())                        #R2
        
        
        #Plota o Semivariograma Experimental

        plt2.close()
        plt2.scatter(self.lag, self.gamma, c = self.npoints, marker = 's', cmap='RdYlGn',  label = self.tr('Semivariograma Experimental'))       

        #Plota o Semivariograma Teorico
        #Ao plotar o semivariograma téorico, a linha começa no efeito Pepita, conforme o Sarvio sugeriu
        plt2.plot(np.insert(self.lag,0,0), np.insert(self.gamma_t, 0, Nugget), label = self.dlg.comboBox_Modelo.currentText() + '   ' + self.tr('RMSE:') + ' ' + '%.3f' % Rss + '   $R^2$: ' + '%.3f'   % R2)

        #Plota a variancia da amostra
        #eixo x : 0 e vetor lag
        #eixo y : vetor formando pela variancia, com tamanho correspondente a x
        if self.dlg.checkBox_Variogram_Variancia.isChecked():                  #plot sample variance 
            plt2.plot(np.insert(self.lag,0,0), np.full(len(self.lag)+1, self.variancia), linestyle = ':', color = 'black', label=self.tr('Variância Amostral'))

        
        plt2.xlim(0,plt2.xlim()[1])                                            #garante que o eixo X começa em 0
        plt2.title(self.tr('Variograma Isotrópico'))

        #plt2.legend(loc='upper left')                                         #posição da Lengenda              
        #plt2.legend()
        plt2.ylabel(self.tr('Semivariância'))
        plt2.xlabel(self.tr('Distância') + ' (h)')

        m0=int(np.floor(self.npoints.min()))     # colorbar min value
        m6=int(np.ceil(self.npoints.max()))      # colorbar max value

        m1=int(1*(m6-m0)/6.0 + m0)               # colorbar mid value 1
        m2=int(2*(m6-m0)/6.0 + m0)               # colorbar mid value 2
        m3=int(3*(m6-m0)/6.0 + m0)               # colorbar mid value 3
        m4=int(4*(m6-m0)/6.0 + m0)               # colorbar mid value 4
        m5=int(5*(m6-m0)/6.0 + m0)               # colorbar mid value 5

        cbar = plt2.colorbar(aspect=30)                                        #expessura do colorbar 
        titulo = self.tr('Pares de') + '\n' + self.tr('pontos')  
        cbar.ax.set_title(titulo)

        cbar.set_ticks([m0,m1,m2,m3,m4,m5,m6])
        cbar.set_ticklabels([m0,m1,m2,m3,m4,m5,m6])

        plt2.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=1.0, bottom=0.1, top=0.95)


        plt2.savefig(     os.path.join(self.path_absolute , '0_Variograma_' + self.VTarget_FileName + '.png'))
        pixmap2 = QPixmap(os.path.join(self.path_absolute , '0_Variograma_' + self.VTarget_FileName + '.png'))
        self.dlg.label_Variograma.show()
        self.dlg.label_Variograma.setPixmap(pixmap2)

       
        self.dlg.groupBox_Variograma_Model.setEnabled(True)                
        self.dlg.pushButton_VariogramaReset.setEnabled(True)            

        self.dlg.lineEdit_Nugget.setEnabled(True)
        self.dlg.lineEdit_Sill.setEnabled(True)
        self.dlg.lineEdit_Range.setEnabled(True)
        
        self.dlg.groupBox_Krigagem.setEnabled(True)
        self.dlg.lineEdit_OK_VBNumMax.setEnabled(True)
        self.dlg.lineEdit_OK_VBRaio.setEnabled(True)
        self.dlg.checkBox_Krigagem_Alcance.setEnabled(True)
        self.dlg.pushButton_Krigagem.setEnabled(True)
        self.dlg.checkBox_Krigagem_Std_Desv.setEnabled(True) 
        

        self.dlg.label_Krigagem.hide()           
        self.dlg.label_validacao_cruzada_OK.hide()
        self.dlg.pushButton_Validacao_Cruzada_OK.setEnabled(True) 


        self.dlg.datatable_pontos_interpolados_OK.setColumnCount(0)
        self.dlg.datatable_pontos_interpolados_OK.setRowCount(0)

        self.dlg.datatable_validacao_cruzada_OK.setColumnCount(0)
        self.dlg.datatable_validacao_cruzada_OK.setRowCount(0)

        self.Variogram = True



    def label_Variograma_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  
               
            if self.Variogram == True:                
                image = Image.open(os.path.join(self.path_absolute , '0_Variograma_' + self.VTarget_FileName + '.png'))
                image.show()



    def  comboBox_Modelo_changed(self, value):     


        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
        
        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = False)  

        self.plot_variogram()



    def lineEdit_OK_DMax_EditingFinished(self): 


        DMax = float(self.dlg.lineEdit_OK_DMax.text())

        if DMax > self.max_dist: 
           DMax = self.max_dist


        lags_dist = float(self.dlg.lineEdit_OK_lags_dist.text())
        if DMax < lags_dist: 
           DMax = lags_dist 

        self.dlg.lineEdit_OK_DMax.setText('%.3f' % DMax)        


        if self.Variogram == True:                
           self.pushButton_VariogramaAjust_clicked()


    def lineEdit_OK_lags_dist_EditingFinished(self): 


        lags_dist = float(self.dlg.lineEdit_OK_lags_dist.text())

        if lags_dist < self.min_dist: 
           lags_dist = self.min_dist
           
        DMax = float(self.dlg.lineEdit_OK_DMax.text())
        if lags_dist > DMax: 
           lags_dist = DMax

        self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % lags_dist)
           
        if self.Variogram == True:                
           self.pushButton_VariogramaAjust_clicked()



    def lineEdit_Nugget_EditingFinished(self): 


        value_Nugget = float(self.dlg.lineEdit_Nugget.text())

        
        if value_Nugget > self.C0_Maximum: 
            value_Nugget = self.C0_Maximum

        if value_Nugget < self.C0_Minimum: 
            value_Nugget = self.C0_Minimum

        self.dlg.lineEdit_Nugget.setText('%.3f' % value_Nugget)


        if self.hide_horizontalSlider == False:                                #limite máximo do GUI horizontalslider 

            try: 
                self.dlg.horizontalSlider_Nugget.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                
    
            self.dlg.horizontalSlider_Nugget.setValue(int(value_Nugget*1000))
    
            self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)

        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 

        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  

        self.plot_variogram()
        
        
    def  horizontalSlider_Nugget_valueChanged(self):     

               
        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
        
        value_Nugget = float(self.dlg.horizontalSlider_Nugget.value()) / 1000  #1000 pois HorizontalSlider só aceita inteiro. 
                                                                               #Intervalo [1..100] -> ajustar para [1..100.000], depois dividir por 1000 para encontrar valor real  

        self.dlg.lineEdit_Nugget.setText('%.3f'   % value_Nugget)              #Efeito Pepita     (Co) 
        
        
        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)    

        self.plot_variogram()



    def lineEdit_Sill_EditingFinished(self): 

        value_Sill = float(self.dlg.lineEdit_Sill.text()) 

        
        if value_Sill > self.C0_C_Maximum: 
            value_Sill = self.C0_C_Maximum

        if value_Sill < self.C0_C_Minimum: 
            value_Sill = self.C0_C_Minimum


        self.dlg.lineEdit_Sill.setText('%.3f' % value_Sill)


        if self.hide_horizontalSlider == False:                                #limite máximo do GUI horizontalslider 

            try: 
                self.dlg.horizontalSlider_Sill.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                
    
            self.dlg.horizontalSlider_Sill.setValue(int(value_Sill*1000))
    
            self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)


        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 

        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  

        self.plot_variogram()
        


    def  horizontalSlider_Sill_valueChanged(self):     

        
        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
        
        value_Sill =  float(self.dlg.horizontalSlider_Sill.value()) / 1000
        
        self.dlg.lineEdit_Sill.setText('%.3f'   % value_Sill)                  #Patamar      (Co + C1) 
        
        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  

        self.plot_variogram()



    def lineEdit_Range_EditingFinished(self): 


        value_Range = float(self.dlg.lineEdit_Range.text())


        if value_Range > self.Range_Maximum: 
            value_Range = self.Range_Maximum

        if value_Range < self.Range_Minimum: 
            value_Range = self.Range_Minimum


        self.dlg.lineEdit_Range.setText('%.3f' % value_Range)


        if self.hide_horizontalSlider == False:                                #limite máximo do GUI horizontalslider 

            try: 
                self.dlg.horizontalSlider_Range.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                
    
            self.dlg.horizontalSlider_Range.setValue(int(value_Range*1000))
    
            self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)

        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 

        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  

        self.plot_variogram()


        
    def  horizontalSlider_Range_valueChanged(self):     


        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
        
        value_Range = float(self.dlg.horizontalSlider_Range.value()) / 1000
        
        self.dlg.lineEdit_Range.setText('%.3f'   % value_Range)                #Alcance     (A) 

        self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  

        self.plot_variogram()



    def  lineEdit_OK_VBNumMax_EditingFinished(self): 
        
        
        VB = int(self.dlg.lineEdit_OK_VBNumMax.text())

        if VB > self.VB_OK_Maximum: 
            VB = self.VB_OK_Maximum

        if VB < self.VB_OK_Minimum: 
            VB = self.VB_OK_Minimum

        self.dlg.lineEdit_OK_VBNumMax.setText(str(VB))



    def  lineEdit_OK_VBRaio_EditingFinished(self): 
        
        
        Raio = float(self.dlg.lineEdit_OK_VBRaio.text())

        if Raio > self.max_dist: 
            Raio = self.max_dist

        if Raio < self.min_dist: 
            Raio = self.min_dist

        self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % Raio)



    def  checkBox_Krigagem_Alcance_clicked(self):                              #Raio de Busca -> usar o Alcance do Semivariograma    


        if self.dlg.checkBox_Krigagem_Alcance.isChecked(): 
            Raio   = float(self.dlg.lineEdit_Range.text())                     #raio de busca -> pegar o valor do alcance  
        else:        
            Raio   = self.max_dist                                             #raio de busca -> usar a maxima distância entre 2 pontos 

        self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % Raio)                     



    def  pushButton_VariogramaReset_clicked(self):                             #reset variogram   


        self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 


        self.dlg.lineEdit_OK_DMax.setText('%.3f' % self.active_distance_ini)   #60% da maior distancia entre dois pontos amostrais       
        self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % self.lag_distance_ini)       
        self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % self.max_dist)            #maior distancia entre dois pontos amostrais        
        
        self.Variogram = False

        self.calculate_variogram(initial_variogram = True, Nugget_Range_Sill = False)  

        self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % self.lag_distance)    

        self.plot_variogram()
        
        self.dlg.pushButton_VariogramaSave.setEnabled(True)                    
        self.dlg.pushButton_Validacao_Cruzada_OK.setEnabled(True) 

        self.Variogram = True
 
       
    def  pushButton_VariogramaAjust_clicked(self):     


        if self.Var_Selected == False:    #Não definiu as coordenadas e atributos para interpolação 
                
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Faça a seleção de atributos(variáveis) na Tabela de Atributos e clique no botão Selecionar.'))
            msg_box.exec_()
 
        else: 
        
            self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 


            if self.Variogram == False:          #Carregou Tabela de Atributos, mas ainda não gerou semivariograma 

                self.calculate_variogram(initial_variogram = True, Nugget_Range_Sill = False)  
        
            else: 

                self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = False)  


            self.dlg.lineEdit_OK_lags_dist.setText('%.3f' % self.lag_distance)    

            self.plot_variogram()
            
            self.dlg.pushButton_VariogramaSave.setEnabled(True)                        
            self.dlg.pushButton_Validacao_Cruzada_OK.setEnabled(True) 

            self.Variogram = True


        
    def pushButton_Krigagem_clicked(self):
        

        if self.Variogram == False: 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Ajuste do Semivariograma não realizado.'))
            msg_box.exec_()
                  
        else: 
            
            grid_x   = self.dlg.SpinBox_Pixel_Size_X.value()                   #tamanho do grid em X  
            grid_y   = self.dlg.SpinBox_Pixel_Size_Y.value()                   #tamanho do grid em Y   

            n_neig     = int(self.dlg.lineEdit_OK_VBNumMax.text())             #numero de vizinhos 
            raio_busca = float(self.dlg.lineEdit_OK_VBRaio.text())             #raio de busca 

                  
            #codigo utilizado na biblioteca pykrige para gerar semivariograma
            if self.dlg.comboBox_Modelo.currentIndex()   == 0:       
                Model = 'linear' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 1:           
                Model = 'linear-sill' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 2:                
                Model = 'exponential' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 3:                
                Model = 'spherical' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 4:                
                Model = 'gaussian' 
    
    
            Nugget   = float(self.dlg.lineEdit_Nugget.text())                  #efeito pepita     (Co) 
            Range    = float(self.dlg.lineEdit_Range.text())                   #alcance  efetivo  (A)
            Sill     = float(self.dlg.lineEdit_Sill.text())                    #patamar           (Co + C)
    

            #######################################################################
            #Krigagem usando DAGAPy


            var_params = [Nugget, Range, Sill]
          
            OK = kriging.OrdinaryKriging(self.xy, self.z, variogram_model = Model,  variogram_parameters = var_params)

            
            #Grid        
            pixel_size_x = grid_x  #Tamanho do pixel definido pelo usuário         
            pixel_size_y = grid_y  #Tamanho do pixel definido pelo usuário         
            
            has_contour = self.dlg.checkBox_Area_Contorno.isChecked()                                                               
            
            if has_contour == True:     
                if len(self.df_limite) > 0:  
                   xygrid = OK.Grid(pixel_size_x, pixel_size_y, has_contour, self.df_limite)       #xygrid é coordenada xy do grid
                else: 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 
                        self.pushButton_Area_Contorno_clicked()    
                        xygrid = OK.Grid(pixel_size_x, pixel_size_y, has_contour, self.df_limite)  #xygrid é coordenada xy do grid                        
            else: 
                #create a numpy with [[xmin, ymin], 
                #                     [xmax, ymax]]
                limite = np.array([[float(self.Cord_X_min), float(self.Cord_Y_min)],
                                   [float(self.Cord_X_max), float(self.Cord_Y_max)]
                                  ])                 
                df_limite = pd.DataFrame(np.atleast_2d(limite), columns=['Coord_X', 'Coord_Y'])
               
                xygrid = OK.Grid(pixel_size_x, pixel_size_y, has_contour, df_limite)               #xygrid é coordenada xy do grid

    
            maximum = (len(xygrid) * 3) + 5
            progress = QProgressDialog(self.tr('Krigagem Ordinária') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(0.1)

            cont = 1 
            progress.setValue(cont)                        
            if progress.wasCanceled():                          
               progress.close() 
               return 

            #z_est_py -> vetor numpy (7860,)  com os pontos etimados 
            #ss       -> vetor numpy (7860,)  com as estimativas de erros             


            #busca de vizinhança será feita por Raio de Busca -> se nº de pontos execeder o número de vizinhos permitido, 
            #será utilizado o nº maximo de vizinhos permitido. 

            z_est_py, ss = OK.execute(xygrid, n_closest_points=n_neig, radius=raio_busca)        
    

            z_est_py = z_est_py.reshape(-1,1)  #redimenciona para 2d array          
            ss       = ss.reshape(-1,1)        #redimenciona para 2d array      
                  
            self.arr_cut = np.vstack((xygrid[:,0], xygrid[:,1],  z_est_py[:,0], ss[:,0]))  #array [4, 7860]

            self.arr_cut = self.arr_cut.T                                         #array [7860, 4]
    
            cont = cont + 1 
            progress.setValue(cont)                        
            if progress.wasCanceled():                          
               progress.close() 
               return 

            
            ###################################################################
            #preenchendo tabela com pontos interpolados  
                        
            df_pontos_interpolados_OK = pd.DataFrame(np.atleast_2d(self.arr_cut), columns=[self.Cord_X, self.Cord_Y, self.v_target, 'SD_Values'])
            df_pontos_interpolados_OK.to_csv(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.csv'   ), sep=',', index=False, encoding='utf-8')
            df_pontos_interpolados_OK.to_csv(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map_SD.csv'), sep=',', index=False, encoding='utf-8')
            df_pontos_interpolados_OK.to_csv(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.kri'   ), sep=',', index=False, encoding='utf-8')

      
            self.dlg.datatable_pontos_interpolados_OK.setColumnCount(len(df_pontos_interpolados_OK.columns))
            self.dlg.datatable_pontos_interpolados_OK.setRowCount(len(df_pontos_interpolados_OK.index))
            
            #preencher o cabeçalho
            try:                       
    
                cols = [] 
                cols = list(df_pontos_interpolados_OK.columns.values)                        
                cols[2] = self.tr('Z.Predito')
                cols[3] = self.tr('Desv.Pad.')
                self.dlg.datatable_pontos_interpolados_OK.setHorizontalHeaderLabels(cols)
    
            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
                
           
            #preencher as linhas da planilha 
            try:                       
                for i in range(len(df_pontos_interpolados_OK.index)):          #linhas 
                    for j in range(len(df_pontos_interpolados_OK.columns)):    #colunas 

                        valor = df_pontos_interpolados_OK.iloc[i,j]

                        if valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                        
                        valor = QTableWidgetItem(str(valor))                  
                        self.dlg.datatable_pontos_interpolados_OK.setItem(i,j, valor)
                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 


            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()

    
            self.dlg.datatable_pontos_interpolados_OK.resizeColumnsToContents();
            
            self.dlg.datatable_pontos_interpolados_OK.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable
            
    
            self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(2)
    

            ###################################################################
            #Exportando arquivo Rasterfile da Kriagem para QGIS 

            if self.dlg.checkBox_Qgis_Raster.isChecked(): 
 
                cont = cont + 1 
                progress.setValue(cont)                        
                if progress.wasCanceled():                          
                   progress.close() 
                   return 


                # get the filenames
                Input_Table            =                                   '1_Krig_' + self.VTarget_FileName + '_Grid_Map.csv'
                Output_Layer_File_tiff = os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.tiff')             
                Output_Layer_Name      =                                   '1_Krig_' + self.VTarget_FileName
                z_field   = self.v_target

                try: 
                    self.dlg.mMapLayerComboBox.currentIndexChanged.disconnect()
                except TypeError:
                    pass  # Ignore the error if no connections exist               
                
                Output_Layer_File_tiff = self.export_raster_to_qgis(Input_Table, Output_Layer_File_tiff, Output_Layer_Name, z_field) 



                ###################################################################
                #Exportando arquivo Shapefile de pontos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Points.isChecked(): 
    

                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopoints") 
                        
                    else: 
                        self.dlg.checkBox_Qgis_Vector_Points.setChecked(False)           



                ###################################################################
                #Exportando arquivo Shapefile de poligonos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Polygons.isChecked(): 
                    
                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopolygons") 

                    else: 
                        self.dlg.checkBox_Qgis_Vector_Polygons.setChecked(False)           

                

            ###################################################################
            #Exportando arquivo Rasterfile do Desvio Padrão para QGIS 
            if self.dlg.checkBox_Krigagem_Std_Desv.isChecked(): 


                cont = cont + 1 
                progress.setValue(cont)                        
                if progress.wasCanceled():                          
                   progress.close() 
                   return 

                # get the filenames
                Input_Table            =                                   '1_Krig_' + self.VTarget_FileName + '_Grid_Map_SD.csv'
                Output_Layer_File_tiff = os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map_SD.tiff')             
                Output_Layer_Name      =                                   '1_Krig_' + self.VTarget_FileName + '_SD'
                z_field   = 'SD_Values'


                Output_Layer_File_tiff = self.export_raster_to_qgis(Input_Table, Output_Layer_File_tiff, Output_Layer_Name, z_field) 


                ###################################################################
                #Exportando arquivo Shapefile de pontos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Points.isChecked(): 
    
                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopoints") 

                    else: 
                        self.dlg.checkBox_Qgis_Vector_Points.setChecked(False)           



                ###################################################################
                #Exportando arquivo Shapefile de poligonos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Polygons.isChecked(): 
                    
                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopolygons") 

                    else: 
                        self.dlg.checkBox_Qgis_Vector_Polygons.setChecked(False)           



            if self.dlg.checkBox_Qgis_Raster.isChecked(): 

                self.dlg.mMapLayerComboBox.currentIndexChanged.connect(self.mMapLayerComboBox_changed)



            ###################################################################
            #Plotando o Mapa Interpolado por OK 

            cont = cont + 1 
            progress.setValue(cont)                        
            if progress.wasCanceled():                          
               progress.close() 
               return 

            
            plt3.close()
            plt3.title(self.tr('Mapa Interpolado Krigagem'))
            plt3.xlabel('Longitude (X)')
            plt3.ylabel('Latitude  (Y)') 
    
            plt3.xlim(float(self.Cord_X_min-100), float(self.Cord_X_max+100))
            plt3.ylim(float(self.Cord_Y_min-100), float(self.Cord_Y_max+100))


            interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
            
            if interval_x == 0:
                interval_x = 1 #int((self.Cord_X_max-self.Cord_X_min))


            xmarks=[i for i in range(int(self.Cord_X_min),int(self.Cord_X_max) , interval_x)]          
            plt3.xticks(xmarks)


            interval_y = int((self.Cord_Y_max-self.Cord_Y_min)/7)
            
            if interval_y == 0:
                interval_y = 1 #int((self.Cord_X_max-self.Cord_X_min))

            ymarks=[i for i in range(int(self.Cord_Y_min),int(self.Cord_Y_max) , interval_y)]          
            plt3.yticks(ymarks)


            plt3.scatter(self.arr_cut[:,0], self.arr_cut[:,1], c=self.arr_cut[:,2], cmap='RdYlGn', vmin = min(self.arr_cut[:,2]), vmax = max(self.arr_cut[:,2])) #plotar gráfico de Mapa Interpolado

            clb = plt3.colorbar(aspect=20)                                     #expessura do colorbar 
            clb.ax.set_title(self.v_target)
    
            plt3.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=1.0, bottom=0.1, top=0.95)

            plt3.ticklabel_format(style='plain', useOffset=False, axis='both') #não exibir coordenadas em notação cientifica 

            #janela do plot exibir as coordenadas em notação decimal. 
            ax = plt3.gca()
            ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)
                       
            plt3.savefig(os.path.join(     self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.png'))
            pixmap4 = QPixmap(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.png'))
            self.dlg.label_Krigagem.show()
            self.dlg.label_Krigagem.setPixmap(pixmap4)
    
            if self.dlg.checkBox_Qgis_Maps.isChecked():             
                plt3.show()         

            
            self.load_maps_to_generate_ZM()                              
            
            self.Krigagem = True

            progress.close() 



    def datatable_pontos_interpolados_OK_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.csv'))





    def pushButton_Krigagem_All_Variables_clicked(self):  #ação do botão de realizar a krigagem para todas as variáveis selecionadas 




        msg = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr('Os mapas interpolados serão exportados para o QGIS. Deseja continuar?'), QMessageBox.Yes | QMessageBox.No)

        if msg == QMessageBox.Yes:

            if ((not self.dlg.checkBox_Qgis_Vector_Points.isChecked()) and (not self.dlg.checkBox_Qgis_Raster.isChecked())):  #checkbox Vector e checkbox Raster não estão marcados 

                self.dlg.checkBox_Qgis_Raster.setChecked(True)              

            self.dlg.checkBox_Qgis_Maps.setChecked(False)              
            list_rows_semiv = self.list_rows_semiv.copy()
            for sv in range(len(list_rows_semiv)): 

            
                row = list_rows_semiv[sv]
        
                v_target = self.dlg.datatable_semivariogramas.item(row, 1).text()  #obtem o valor da 2ª coluna da linha selecionada 
              
                #verificar se v_target escolhida já tem semivariograma calculado             
                selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()
                layer_name  = selectedLayer.name()
        
                filename = os.path.join(self.path_absolute , '0_Semivariograms_' + layer_name + '.csv')
        
        
                self.df_semivariograms  = pd.read_csv(filename, sep = ',')  
        
                #pesquisar se já foi calculado o semivariograma da variavel -> se sim, exibe semivariograma calculado da variável  
                semiv_calculated = -1 
    
                for i in range(len(self.df_semivariograms.index)):                 #linhas 
        
                        
                        if v_target == self.df_semivariograms.iloc[i,0]:           #calculou o variograma de uma variável que já foi calculada -> substituir
    
                            semiv_calculated = i
                            
    
                if  semiv_calculated >= 0: #Semivariograma já foi calculado -> exibir os resultados do semivariograma calculado 
    
                    self.dlg.comboBox_VTarget.setCurrentText(v_target)             
    
                    self.pushButton_ImportQGIS_clicked()                           #evento onClick do botão Importar             

    
                    Modelo = self.df_semivariograms.iloc[semiv_calculated,1]
                    DMax   = float(self.df_semivariograms.iloc[semiv_calculated,2])
                    Lag    = float(self.df_semivariograms.iloc[semiv_calculated,3])
                    C0     = float(self.df_semivariograms.iloc[semiv_calculated,4])
                    C0_C   = float(self.df_semivariograms.iloc[semiv_calculated,5])
                    Range  = float(self.df_semivariograms.iloc[semiv_calculated,6])
                    RMSE   = float(self.df_semivariograms.iloc[semiv_calculated,7])
                    R2     = float(self.df_semivariograms.iloc[semiv_calculated,8])   
                    Raio   = float(self.df_semivariograms.iloc[semiv_calculated,9])   
                    VB     = int(self.df_semivariograms.iloc[semiv_calculated,10])    

                    self.max_dist = float(self.df_semivariograms.iloc[semiv_calculated,11])
                    self.min_dist = float(self.df_semivariograms.iloc[semiv_calculated,12])
                    self.C0_Maximum    = float(self.df_semivariograms.iloc[semiv_calculated,13])
                    self.C0_Minimum    = float(self.df_semivariograms.iloc[semiv_calculated,14])
                    self.C0_C_Maximum  = float(self.df_semivariograms.iloc[semiv_calculated,15])
                    self.C0_C_Minimum  = float(self.df_semivariograms.iloc[semiv_calculated,16])
                    self.Range_Maximum = float(self.df_semivariograms.iloc[semiv_calculated,17])
                    self.Range_Minimum = float(self.df_semivariograms.iloc[semiv_calculated,18])

                    self.Raio_OK_Maximum  = float(self.df_semivariograms.iloc[semiv_calculated,19])
                    self.Raio_OK_Minimum  = float(self.df_semivariograms.iloc[semiv_calculated,20])
                    self.VB_OK_Maximum    = int(self.df_semivariograms.iloc[semiv_calculated,21])
                    self.VB_OK_Minimum    = int(self.df_semivariograms.iloc[semiv_calculated,22])

    
                    #evento onchange do combobox Modelo Variogram
                    try: 
                        self.dlg.comboBox_Modelo.currentIndexChanged.disconnect()                                 
                    except TypeError:
                        pass  # Ignore the error if no connections exist               
                        
    
    
                    if (Modelo == 'Linear') or (Modelo == 'Linear'):
                       self.dlg.comboBox_Modelo.setCurrentIndex(0)
                    elif (Modelo == 'Linear to Sill') or (Modelo == 'Linear com Patamar'):      
                       self.dlg.comboBox_Modelo.setCurrentIndex(1)
                    elif (Modelo == 'Exponential') or (Modelo == 'Exponencial'):       
                       self.dlg.comboBox_Modelo.setCurrentIndex(2)
                    elif (Modelo == 'Spherical') or (Modelo == 'Esférico'):       
                       self.dlg.comboBox_Modelo.setCurrentIndex(3)
                    elif (Modelo == 'Gaussian') or (Modelo == 'Gaussiano'):       
                       self.dlg.comboBox_Modelo.setCurrentIndex(4)
    
    
                    #evento onchange do combobox Modelo Variogram  
                    self.dlg.comboBox_Modelo.currentIndexChanged.connect(self.comboBox_Modelo_changed)     

    
                    self.dlg.lineEdit_OK_DMax.setText('%.3f'  % DMax)   

                    self.dlg.lineEdit_OK_lags_dist.setText('%.3f'  % Lag)     

    
                    #Nugget 
                    
                    if self.hide_horizontalSlider == False: 
                    
                        try: 
                            self.dlg.horizontalSlider_Nugget.valueChanged.disconnect()
                        except TypeError:
                            pass  # Ignore the error if no connections exist               
                                
                        self.dlg.horizontalSlider_Nugget.setMinimum(int(self.C0_Minimum*1000))                    #último valor de gamma (eixo y)       
                        self.dlg.horizontalSlider_Nugget.setMaximum(int(self.C0_Maximum*1000))                    #último valor de gamma (eixo y)       
                        self.dlg.horizontalSlider_Nugget.setValue(int(C0*1000))
    
                        self.dlg.horizontalSlider_Nugget.valueChanged.connect(self.horizontalSlider_Nugget_valueChanged)

                    self.dlg.lineEdit_Nugget.setText('%.3f'  % C0)                                       #último valor de gamma (eixo y)       


                    #Sill

                    if self.hide_horizontalSlider == False: 

                        try: 
                            self.dlg.horizontalSlider_Sill.valueChanged.disconnect()
                        except TypeError:
                            pass  # Ignore the error if no connections exist               
                            
                
                        self.dlg.horizontalSlider_Sill.setMinimum(int(self.C0_C_Minimum*1000))                    #último valor de gamma (eixo y)           
                        self.dlg.horizontalSlider_Sill.setMaximum(int(self.C0_C_Maximum*1000))                    #último valor de gamma (eixo y)         
                        self.dlg.horizontalSlider_Sill.setValue(int(C0_C*1000))                                   #Patamar           (Co + C)           
    
                        self.dlg.horizontalSlider_Sill.valueChanged.connect(self.horizontalSlider_Sill_valueChanged)

                    self.dlg.lineEdit_Sill.setText('%.3f'  % C0_C) 

                    #Range 

                    if self.hide_horizontalSlider == False: 

                        try: 
                            self.dlg.horizontalSlider_Range.valueChanged.disconnect()
                        except TypeError:
                            pass  # Ignore the error if no connections exist               
                            
                        
                        self.dlg.horizontalSlider_Range.setMinimum(int(self.Range_Minimum*1000))                  #minima distancia entre os pontos   
                        self.dlg.horizontalSlider_Range.setMaximum(int(self.Range_Maximum*1000))                  #maxima distancia entre os pontos   
                        self.dlg.horizontalSlider_Range.setValue(int(Range*1000))
                        
                        self.dlg.horizontalSlider_Range.valueChanged.connect(self.horizontalSlider_Range_valueChanged)


                    self.dlg.lineEdit_Range.setText('%.3f'  % Range)                                     #alcance  efetivo  (A)       
    
                    self.dlg.lineEdit_OK_VBRaio.setText('%.3f' % Raio)     

                    self.dlg.lineEdit_OK_VBNumMax.setText(str(VB))     
    
                    self.dlg.lineEdit_Var_RMSE.setText('%.3f' % RMSE)          #RMSE
                    self.dlg.lineEdit_Var_R2.setText('%.3f'   % R2)            #R2

        
                    self.calculate_variogram(initial_variogram = False, Nugget_Range_Sill = True)  
       
                    self.plot_variogram()
                    
                    self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(0) 
    
                    self.Variogram = True

                    self.pushButton_Krigagem_clicked()
                


    def label_Krigagem_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  

            if self.Krigagem == True:                
                image = Image.open(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_Grid_Map.png'))
                image.show()



    def pushButton_Validacao_Cruzada_OK_clicked(self):
       
       
        if self.Variogram == False: 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Ajuste do Semivariograma não realizado.'))
            msg_box.exec_()
  
        else:          
            n_neig     = int(self.dlg.lineEdit_OK_VBNumMax.text())             #numero de vizinhos 
            raio_busca = float(self.dlg.lineEdit_OK_VBRaio.text())             #raio de busca 
    
            #codigo utilizado na biblioteca pykrige para gerar semivariograma
            if self.dlg.comboBox_Modelo.currentIndex()   == 0:       
                Model = 'linear' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 1:           
                Model = 'linear-sill' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 2:                
                Model = 'exponential' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 3:                
                Model = 'spherical' 
            elif self.dlg.comboBox_Modelo.currentIndex() == 4:                
                Model = 'gaussian' 
    
            nugget          = float(self.dlg.lineEdit_Nugget.text())           #efeito pepita     (Co) 
            sill            = float(self.dlg.lineEdit_Sill.text())             #patamar           (Co + C)
            effective_range = float(self.dlg.lineEdit_Range.text())            #alcance  efetivo  (A)
    
    
            #Validacao Cruzada usando DAGAPy
            var_params = [nugget, effective_range, sill]      
    
            maximum = (len(self.data) + (len(self.data)*4)) 
            progress = QProgressDialog(self.tr('Validação Cruzada - Krigagem') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(0.1)


            
            for cont in (range(len(self.xy))):
        
                      
                coordx = self.xy.iloc[cont, 0]      #concatena o único ponto (x), que será utilizado na validação cruzada
                coordy = self.xy.iloc[cont, 1]      #concatena o único ponto (y), que será utilizado na validação cruzada
               
                
                xy2 = self.xy.drop(cont)            #deleta a linha cont do dataframe xy 
                z2  = self.z.drop(cont)             #deleta a linha cont da Series z 
                                   
                OK = kriging.OrdinaryKriging(xy2, z2, variogram_model=Model,  variogram_parameters = var_params)
    

                #busca de vizinhança será feita por Raio de Busca -> se nº de pontos execeder o número de vizinhos permitido, 
                #será utilizado o nº maximo de vizinhos permitido. 
                coordxy = [[coordx, coordy]]

                z_est_py, ss = OK.execute(coordxy, n_closest_points=n_neig, radius=raio_busca)        
              
                              
                if cont == 0:  
                    labels_OK_CV = np.copy(z_est_py[0]) 
                else:       
                    labels_OK_CV = np.vstack((labels_OK_CV, z_est_py[0]))      #concatena após ultima linha. 
    

                progress.setValue(cont)                        
                if progress.wasCanceled():                          
                   progress.close() 
                   return 
    
            #exibir os dados da validação cruzada em um datatable
            
            labels_OK_CV = np.array(labels_OK_CV)
            labels = self.data[:, 2]
    
            data_CV_OK = np.column_stack((self.data[:, 0], self.data[:, 1], labels, labels_OK_CV))    
    
            

            self.df_CV_OK = pd.DataFrame(np.atleast_2d(data_CV_OK), columns=['Coord_X', 'Coord_Y', self.tr('Z.Obs.'), self.tr('Z.Predito')])
            self.df_CV_OK.to_csv(os.path.join(self.path_absolute ,  '1_Krig_' + self.VTarget_FileName + '_CV.csv'), sep=',', index=False, encoding='utf-8')
    
            
            self.dlg.datatable_validacao_cruzada_OK.setColumnCount(len(self.df_CV_OK.columns))
            self.dlg.datatable_validacao_cruzada_OK.setRowCount(len(self.df_CV_OK.index))
            
    
            #preencher o cabeçalho
            try:                       
    
                cols = [] 
                cols = list(self.df_CV_OK.columns.values)
    
                self.dlg.datatable_validacao_cruzada_OK.setHorizontalHeaderLabels(cols)
    
            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()

                      
            #preencher as linhas da planilha 
            try:                       
                for i in range(len(self.df_CV_OK.index)):  #linhas 
                    for j in range(len(self.df_CV_OK.columns)): #colunas 

                        valor = self.df_CV_OK.iloc[i,j]

                        if valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                        
                        valor = QTableWidgetItem(str(valor))                  
                        self.dlg.datatable_validacao_cruzada_OK.setItem(i,j, valor)
                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
                        
                        
            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_() 
    

            self.dlg.datatable_validacao_cruzada_OK.resizeColumnsToContents();
     
            self.dlg.datatable_validacao_cruzada_OK.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable
     
           
            #plotar o gráfico da validação cruzada 

            
            #regression part  with sklearn.linear_model import LinearRegression
            RMSE_lib, R2_RCV, regressor, R2_Elp, lccc = functions.calculate_statistics(labels_OK_CV, labels)
            
            #print('R2_Elp: ', R2_Elp)
            #print('lccc: ', lccc)

            RMSE_lib = '%.3f' % (RMSE_lib)   
            R2_RCV = '%.3f' % (R2_RCV) 


            #To retrieve the intercept:
            intercept = regressor.intercept_[0]

            #For retrieving the slope:
            slope = regressor.coef_[0][0]
            
            #To retrieve the residual da regressão:
            #residual = regressor._residues

           
            #regression part with stats.linregress 
            #from scipy import stats                                    
            #slope, intercept, r_value, p_value, std_err = stats.linregress(labels_OK_CV.T,labels)

      
            #definir os limites do gráfico de validação cruzada 

            x_min = min(labels_OK_CV.min(), labels.min()) 
            x_max = max(labels_OK_CV.max(), labels.max()) 

            
            x_min = x_min - abs(intercept) 
            if x_min < 0: 
                x_min = 0

            x_max = x_max + abs(intercept) 
            
            self.dlg.label_Variograma.show()
    
            plt5.close()
            plt5.title(self.tr('Validação Cruzada - Krigagem')  + '   ' + self.tr('RMSE:') + ' ' + str(RMSE_lib) + '   $R^2$ : ' + str(R2_RCV))
            
    
            plt5.xlim(x_min, x_max)
            plt5.ylim(x_min, x_max)
            
            
            plt5.xlabel(self.tr('Valor Predito') + ' - ' + self.v_target)
            plt5.ylabel(self.tr('Valor Observado') + ' - ' + self.v_target) 
    
            plt5.scatter(labels_OK_CV, labels,      marker = 's',     color = 'blue')
            plt5.plot( [x_min,x_max],[x_min,x_max], linestyle = ':',  color = 'black')

            labels_OK_CV = np.append(0, labels_OK_CV)                          #insert 0 na posição 0 do array 
            labels_OK_CV = np.append(labels_OK_CV, x_max)                      #insert x_max na ultima posição do array 
            
            line = slope * labels_OK_CV + intercept
            
            #plot Line of Regression 
            if intercept >= 0:                       
                plt5.plot(labels_OK_CV, line, color = 'black', label='y={:.3f}x+{:.3f}'.format(slope,intercept))  
            else: 
                plt5.plot(labels_OK_CV, line, color = 'black', label='y={:.3f}x-{:.3f}'.format(slope,abs(intercept)))  
                

            plt5.legend(loc='upper left')                                      #posição da Lengenda                  
            plt5.legend()

            plt5.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)

            plt5.ticklabel_format(style='plain', useOffset=False, axis='both') #não exibir coordenadas em notação cientifica 

            #janela do plot exibir as coordenadas em notação decimal. 
            ax = plt5.gca()
            ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)

            
            plt5.savefig(     os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_CV.png'))
            pixmap5 = QPixmap(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_CV.png'))
            self.dlg.label_validacao_cruzada_OK.show()
            self.dlg.label_validacao_cruzada_OK.setPixmap(pixmap5)
            
            if self.dlg.checkBox_Qgis_Maps.isChecked(): 
                plt5.show()
      
            self.Validacao_Cruzada_OK = True 
            
            self.dlg.tabWidget_Interpolacao_OK.setCurrentIndex(1) 

            progress.close() 


    def datatable_validacao_cruzada_OK_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute ,  '1_Krig_' + self.VTarget_FileName + '_CV.csv'))


    def label_validacao_cruzada_OK_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  
        
            if self.Validacao_Cruzada_OK == True:                
               image = Image.open(os.path.join(self.path_absolute , '1_Krig_' + self.VTarget_FileName + '_CV.png'))
               image.show()
           


    def datatable_semivariogramas_checkbox_clicked(self, item):

        if item.checkState() == QtCore.Qt.Checked:  #quando marca o checkbox  

            if not item.row() in self.list_rows_semiv:

                self.list_rows_semiv.append(item.row())
                self.list_rows_semiv.sort() 

        else:
            if item.row() in self.list_rows_semiv:
                self.list_rows_semiv.remove(item.row())


        if len(self.list_rows_semiv) > 0: 
            self.dlg.pushButton_Krigagem_All_Variables.setEnabled(True)
        else: 
            self.dlg.pushButton_Krigagem_All_Variables.setEnabled(False)
            
            
############################################################    Aba para calcular interpolação por Machine Learning  #################################################################

    def  lineEdit_SVM_VBNumMax_EditingFinished(self): 
        
        
        VB = int(self.dlg.lineEdit_SVM_VBNumMax.text())

        if VB > self.VB_SVM_Maximum: 
            VB = self.VB_SVM_Maximum

        if VB < self.VB_SVM_Minimum: 
            VB = self.VB_SVM_Minimum

        self.dlg.lineEdit_SVM_VBNumMax.setText(str(VB))

            

    def  lineEdit_SVM_VBRaio_EditingFinished(self): 
        
        
        Raio = float(self.dlg.lineEdit_SVM_VBRaio.text())

        if Raio > self.max_dist: 
            Raio = self.max_dist

        if Raio < self.min_dist: 
            Raio = self.min_dist

        self.dlg.lineEdit_SVM_VBRaio.setText('%.3f' % Raio)



    def comboBox_SVM_Fonte_changed(self, value):                               #evento onchange do combobox Fonte Layer   
 
                  
        #if self.dlg.checkBox_Moran.isChecked(): 
        #   self.checkBox_Moran_clicked()                                      #exibe correlação de Moran 
        self.dlg.checkBox_Moran.setChecked(False)
        self.list_rows_moran = [] 
        self.dlg.pushButton_SVM_Add_Selected_Features.setEnabled(False)        
        self.dlg.datatable_moran.setColumnCount(0)
        self.dlg.datatable_moran.setRowCount(0)

        if value == 0:  #Features da tabela de Atributos 

            self.dlg.checkBox_RFE.setEnabled(True)

            self.dlg.label_SVM_DenseLayer.setEnabled(False)
            self.dlg.mMapLayerComboBox_DenseLayer.setEnabled(False)
            
            self.dlg.comboBox_SVM_Features.setEnabled(True)
            self.dlg.pushButton_SVM_Add_Feature.setEnabled(True)            
            self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
            self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            

            self.dlg.comboBox_SVM_Features.clear()
            self.dlg.comboBox_SVM_Features.addItems(self.cols_table_atribute)
            self.dlg.comboBox_SVM_Features.setCurrentIndex(3)

            
        else:           #Features de outras Layers com camada densa 

            self.dlg.checkBox_RFE.setEnabled(False)
            self.dlg.checkBox_Moran.setEnabled(True)
            self.dlg.checkBox_Moran.setChecked(False)              

            #self.dlg.datatable_SVM_Trainfeatures.setGeometry(10, 30, 510, 300)

            selectedLayer = self.dlg.mMapLayerComboBox_DenseLayer.currentLayer()

            if selectedLayer.type() == QgsMapLayerType.RasterLayer:            #RasterLayer  


                self.dlg.label_SVM_DenseLayer.setEnabled(True)
                self.dlg.mMapLayerComboBox_DenseLayer.setEnabled(True)

                self.dlg.comboBox_SVM_Features.setEnabled(False)
                self.dlg.pushButton_SVM_Add_Feature.setEnabled(True)            

                self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            

                self.dlg.comboBox_SVM_Features.clear()

                
            else:                                                              #VectorLayer

                self.cols_table_atribute_dense = selectedLayer.fields().names() 
    
                self.dlg.label_SVM_DenseLayer.setEnabled(True)
                self.dlg.mMapLayerComboBox_DenseLayer.setEnabled(True)

                self.dlg.comboBox_SVM_Features.setEnabled(True) 
                self.dlg.pushButton_SVM_Add_Feature.setEnabled(True)            

                self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            

                self.dlg.comboBox_SVM_Features.clear()
                
                self.dlg.comboBox_SVM_Features.addItems(self.cols_table_atribute_dense)
                self.dlg.comboBox_SVM_Features.setCurrentIndex(3)
    



    def mMapLayerComboBox_DenseLayer_changed(self):                            #evento onchange do combobox  Dense Layer  


        if self.dlg.comboBox_SVM_Fonte.currentIndex() == 1:  #Fonte: DenseLayer 

            
            if self.dlg.mMapLayerComboBox_DenseLayer.currentIndex() >= 0:  
            
                selectedLayer = self.dlg.mMapLayerComboBox_DenseLayer.currentLayer()
    
                coordenate_reference = selectedLayer.crs().description()
                
                if 'SAD69' in coordenate_reference: 
                    
                    lyrCRS = QgsProject.instance().crs().authid()  #get CRS of project   EX: EPSG:32723
                
                else:      

                    lyrCRS = selectedLayer.crs().authid() 

        
                if (lyrCRS != self.lyrCRS_table_atribute):  
        
        
                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('O CRS da Layer selecionada é diferente do CRS da Layer da Tabela de Atributos.'))
                    msg_box.exec_()


                elif selectedLayer.type() == QgsMapLayerType.RasterLayer:      #RasterLayer  
                
                    self.dlg.comboBox_SVM_Features.setEnabled(False)
                    self.dlg.pushButton_SVM_Add_Feature.setEnabled(True)            

                    self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                    self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            
    
                    self.dlg.comboBox_SVM_Features.clear()
                    
    
                else:                                                          #VectorLayer               
    
                    self.cols_table_atribute_dense = selectedLayer.fields().names() 
        
                    self.dlg.comboBox_SVM_Features.setEnabled(True) 
                    self.dlg.pushButton_SVM_Add_Feature.setEnabled(True)            

                    self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                    self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            
    
                    self.dlg.comboBox_SVM_Features.clear()

                    self.dlg.comboBox_SVM_Features.addItems(self.cols_table_atribute_dense)
                    self.dlg.comboBox_SVM_Features.setCurrentIndex(3)
    

    ###########################################################################   
    #calculando Correlação de Moran 

    def checkBox_Moran_clicked(self):
        

        if self.dlg.checkBox_Moran.isChecked(): 

            if self.dlg.comboBox_SVM_Fonte.currentIndex() == 0:                #df_moran de v_target em relação as atributos da tabela de atributos     

                self.correlacao_Moran_BV(self.df, use_check = True)
            
            else:                                                              #df_moran de v_target em relação as atributos adicionados ao grid denso 
        
                if len(self.list_cov_SVM) >= 2:                                #possui atributos - coordenadas (x, y)

                    #df_Trainfeatures = pd.concat([self.df_SVM_Trainfeatures.iloc[:, 2:], self.df[[self.v_target]] ], axis=1)  #concatena a partir da terceira coluna de df_train_features 
                    df_Trainfeatures  = pd.concat([self.df_SVM_Trainfeatures, self.df[[self.v_target]] ], axis=1)  

                    self.correlacao_Moran_BV(df_Trainfeatures, use_check = False)
                
                    #self.dlg.datatable_SVM_Trainfeatures.setGeometry(10, 30, 300, 300)

        else: 
            self.list_rows_moran = []
            self.dlg.datatable_moran.setColumnCount(0)
            self.dlg.datatable_moran.setRowCount(0)


    def correlacao_Moran_BV(self, dataframe, use_check):

        
        df_moran = functions.calculate_index_moran_BV(dataframe, self.Cord_X, self.Cord_Y, self.v_target)  

        
        df_moran = df_moran[df_moran.Covariavel != 'ID']                       #Exclui a linha do atributo ID 
        df_moran = df_moran[df_moran.Covariavel != 'ID_SM']                    #Exclui a linha do atributo ID_SM 
           
        if use_check == True: 
           self.dlg.datatable_moran.setColumnCount(len(df_moran.columns)+1)
        else: 
           self.dlg.datatable_moran.setColumnCount(len(df_moran.columns))
        
        self.dlg.datatable_moran.setRowCount(len(df_moran.index))
        

        #preencher o cabeçalho
        try:                       
    
            cols = [] 
            if use_check == True: 
                cols = [self.tr('Marcar')] + list(df_moran.columns.values) 
            else: 
                cols = list(df_moran.columns.values)                 

            self.dlg.datatable_moran.setHorizontalHeaderLabels(cols)
        
        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()
            
        
        #preencher as linhas da planilha 
        try:                       
            for i in range(len(df_moran.index)):          #linhas 

                if use_check == True: 

                    chkBoxItem = QTableWidgetItem()
                    chkBoxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
                    chkBoxItem.setCheckState(QtCore.Qt.Unchecked)       
                    self.dlg.datatable_moran.setItem(i,0,chkBoxItem)           

                for j in range(len(df_moran.columns)):    #colunas 
    
                        valor = df_moran.iloc[i,j]
                      
                        if isinstance(valor, str): 
                            valor = QTableWidgetItem(valor)                      
                        elif valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                            valor = QTableWidgetItem(str(valor))                  
                        else:     
                            valor = QTableWidgetItem(str(valor))                  
    
                        if use_check == True: 
                            self.dlg.datatable_moran.setItem(i,j+1, valor)
                        else:     
                            self.dlg.datatable_moran.setItem(i,j, valor)

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        self.dlg.datatable_moran.resizeColumnsToContents()

        self.dlg.datatable_moran.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

    ###########################################################################   
    #calculando Recursive Feature Elimination


    def checkBox_RFE_clicked(self):
        
        if self.dlg.checkBox_RFE.isChecked(): 


            maximum = (5) 
            progress = QProgressDialog(self.tr('Seleção de Variáveis') + ' - ' + self.tr('Recursive Feature Elimination (RFE)') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(5)

            filename = os.path.join(self.path_absolute , '0_Dados.csv')  
    
            df = pd.read_csv(filename, sep = ',')  

            df = functions.eliminar_outlier(df, self.v_target)

            progress.setValue(2)                        
            time.sleep(1)
            if progress.wasCanceled():                          
                progress.close() 
            
            '''
            df_moran = functions.calculate_index_moran_BV(df, self.Cord_X, self.Cord_Y, self.v_target)  

            df_moran['Moran_ABS'] = abs(df_moran['Moran'])
            df_moran.sort_values(['Moran_ABS'], ascending=[False], inplace=True)    

            print(df_moran['Covariavel'])
            df_moran = df_moran[df_moran.Covariavel != 'ID'] 
            df_moran = df_moran[df_moran.Covariavel != 'CoordX_SM'] 
            df_moran = df_moran[df_moran.Covariavel != 'Coordy_SM'] 
            
            print(df_moran['Covariavel'])
            if len(df_moran) > 21: 
                df_moran = df_moran.head(21)
            
            df_moran.drop('Moran_ABS', axis=1, inplace=True)  #drop column 'Moran_ABS'
          
            cols = list(df_moran['Covariavel']) 
            print(df_moran['Covariavel'])

            df = df[cols]
            '''

            progress.setValue(3)                        
            time.sleep(1)
            if progress.wasCanceled():                          
                progress.close() 

            self.Recursive_Feature_Elimination(df)

            progress.setValue(4)                        
            if progress.wasCanceled():                          
                progress.close() 

            progress.close() 
            
        else: 

            self.dlg.datatable_RFE.setColumnCount(0)
            self.dlg.datatable_RFE.setRowCount(0)


    def Recursive_Feature_Elimination(self, dataframe):


        df_RFE = functions.selected_features_RFE(dataframe, self.Cord_X, self.Cord_Y, self.v_target)  

        self.dlg.datatable_RFE.setColumnCount(len(df_RFE.columns))
        self.dlg.datatable_RFE.setRowCount(len(df_RFE.index))
        
        #preencher o cabeçalho
        try:                       
    
            cols = [] 
            cols = list(df_RFE.columns.values)
            cols[0] = self.tr(cols[0])
            cols[1] = self.tr(cols[1])
            self.dlg.datatable_RFE.setHorizontalHeaderLabels(cols)
        
        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()
            
        
        #preencher as linhas da planilha 
        try:                       
            for i in range(len(df_RFE.index)):          #linhas 
                for j in range(len(df_RFE.columns)):    #colunas 
    
                        valor = df_RFE.iloc[i,j]
                      
                        if isinstance(valor, str): 
                            valor = QTableWidgetItem(valor)                      
                        elif valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                            valor = QTableWidgetItem(str(valor))                  
                        else:     
                            valor = QTableWidgetItem(str(valor))                  
    
                        self.dlg.datatable_RFE.setItem(i,j, valor)

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        self.dlg.datatable_RFE.resizeColumnsToContents()

        self.dlg.datatable_RFE.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable


    ###########################################################################   
    #Adicionando Feature ao Modelo


    def  pushButton_SVM_Add_Feature_clicked(self):    #Adicionar coordenadas (X, Y) como feature do modelo de ML

            
        Cord_Z     =  self.dlg.comboBox_SVM_Features.currentText()             #Covariável a ser adicionada ao ML  

        n_neig     =  int(self.dlg.lineEdit_SVM_VBNumMax.text())
        weight_IDW =  self.dlg.doubleSpinBox_Weight_IDW.value()    


        #Usuário está tentando adicionar v_target com vizinhança de IDW = 1 Metodo de Busca vizinho + proximo
        if (Cord_Z == self.v_target) and (int(self.dlg.lineEdit_SVM_VBNumMax.text()) == 1):                                                     
                               
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('O Modelo de Machine Learning não permite adicionar a variável target: ') + self.v_target + '\n' + self.tr('utilizando o método de busca por vizinho mais próximo.'))
                msg_box.exec_()              

        else: 
            
            if self.SVM_Add_Coord == False:                                    #adicionar as coordenas (X, Y)  ao modelo 

                if self.SVM_Add_Feature == True:                               #Adicionou features ao modelo SVM  -> serão retiradas pois alterou os parâmetros do SVM 
        
                    for i in range(2,len(self.list_cov_SVM)): 
                        self.dlg.comboBox_SVM_Features_Adds.setCurrentIndex(i)
                        self.pushButton_SVM_Remove_Feature_clicked()
                
                
                self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(0) 
                
        
                ###############################################################
                #definindo o dataframe df_SVM_Testfeatures -> Colunas (X, Y) para o grid de interpolação 
        
                
                self.gridx = np.arange(float(self.Cord_X_min), float(self.Cord_X_max), self.Pixel_Size_X)
                self.gridy = np.arange(float(self.Cord_Y_min), float(self.Cord_Y_max), self.Pixel_Size_Y)        
        
    
                maximum = (len(self.gridx) * len(self.gridy)) 
                progress = QProgressDialog(self.tr('Machine Learning - Support Vector Machine...'), self.tr('Cancelar'),  1, maximum, self.dlg)
                progress.setWindowTitle('Smart-Map')
                progress.show() 
                progress.setCancelButton(None)                                 #remove button cancel 
                #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)#disable button 'X' 
                progress.setWindowModality(QtCore.Qt.WindowModal)              #modal for parent form 
                #progress.setWindowModality(QtCore.Qt.ApplicationModal)        #modal for application 
                time.sleep(0.1)

        
                #monta o grid_xy  ['x', 'y'] com 7860 linhas 
                cont = 1
                lista_xy = []
                for i in range(len(self.gridx)):
                    for j in range(len(self.gridy)): 
                        lista_xy.append([self.gridx[i]+(self.Pixel_Size_X/2), self.gridy[j]-(self.Pixel_Size_Y/2)])   
                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 

                progress.close() 

                arr_xy = np.array(lista_xy)
                
               
                if self.dlg.checkBox_Area_Contorno.isChecked(): 

                    if len(self.df_limite) <= 0:  #usuário selecionou o checkbox mas não clicou no botão para definir o contorno 
                        if (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0): 
                            self.pushButton_Area_Contorno_clicked()    
                            
                    lista_cut_xy = []
        
                    polygono = np.array(self.df_limite, dtype=float)        #define o polygono = area de contorno 
                    bbPath = mplPath.Path(polygono)
    
                    maximum = len(arr_xy)
                    progress = QProgressDialog(self.tr('Gerando grid para os pontos de interpolação (x, y, z): '), self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)

                   
                    cont = 1
                    for i in range(len(arr_xy)):
                        ponto = (arr_xy[i,0], arr_xy[i,1])
                        if bbPath.contains_point(ponto): 
                            lista_cut_xy.append([arr_xy[i,0], arr_xy[i,1]])

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 

                    progress.close() 
                     
                    arr_xy = np.array(lista_cut_xy)
                        
                self.grid_xy = np.array(arr_xy) 
                 

                self.df_SVM_Testfeatures = pd.DataFrame(np.atleast_2d(self.grid_xy), columns=[self.Cord_X, self.Cord_Y]) 
        
        
                
                self.features_grid = np.array(self.grid_xy)
            
                self.SVM_Add_Coord = True 
                self.SVM_Add_Feature = False 
            
                self.dlg.label_SVM.hide()           
                self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
                self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
        
                self.dlg.label_validacao_cruzada_SVM.hide()
                self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
                self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)
    
    
                ####################################################################### 
                #Fim do processo de adicionar Coordenadas (X, Y) aos dataframes:   df_SVM_Trainfeatures, df_SVM_Trainlabels, df_SVM_Testfeatures, 



            ####################################################################### 
            #Adicionando um atributo ao modelo SVM 
                                  
                     
            if self.dlg.comboBox_SVM_Fonte.currentIndex() == 1:                #layer    selecionada é a Layer Dense 
    
                selectedLayer = self.dlg.mMapLayerComboBox_DenseLayer.currentLayer() 
    
                if selectedLayer.type() == QgsMapLayerType.RasterLayer:        #layer    selecionada é uma  Layer Dense -> Raster               
    
                    Cord_Z     =  selectedLayer.name()                         #Não há variável selecionada Layer Dense -> Raster 
    
                else: 
    
                    Cord_Z     =  self.dlg.comboBox_SVM_Features.currentText() #Variável selecionada na  Layer Dense -> Vector     
                    
    
            if self.dlg.comboBox_SVM_Fonte.currentIndex() == 0:                #layer    selecionada é a tabela de atributos 
    
                Cord_Z     =  self.dlg.comboBox_SVM_Features.currentText()     #Variável selecionada na  tabela de atributos      
    
    
            ''' 
            if Cord_Z in self.list_cov_SVM:                                    #Coord_Z já foi adicionada  nas features 
                
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(Cord_Z + ' ' + self.tr('já foi adicionada às Covariáveis do Modelo SVM.'))
                msg_box.exec_()              
    
    
            else: 
            '''

            if (True): 

                self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(0)                 
                
                cols = []
                
                '''
                if (Cord_Z == self.v_target): 
                    cols.append('IDW_' + Cord_Z)
                else:     
                    cols.append(Cord_Z)
                '''
  
                cols.append(Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text())                                
                    
                self.dlg.comboBox_SVM_Features_Adds.addItems(cols)     
    
                self.list_cov_SVM = [self.dlg.comboBox_SVM_Features_Adds.itemText(i) for i in range(self.dlg.comboBox_SVM_Features_Adds.count())]     


                ###############################################################
                #layer selecionada da tabela de atributos
                                    
                if self.dlg.comboBox_SVM_Fonte.currentIndex() == 0:        
    
                                        
                    #verificar se coluna:  Cord_Z possui valores nulos 
                    is_NaN = self.df.isnull()                                                #retorna uma matriz de booleanos  
                    row_has_NaN = is_NaN.any(axis=1)                                         #retorna um vetor   de booleanos onde tem linhas com nan
                   
                   
                    df_with_NaN = self.df[row_has_NaN]                                       #retorna o dataframe com as linhas e colunas com nan
                    
                    #list_rows_NaN = list(df_with_NaN.index.values)                          #retorna os indices das linhas que possuem valores nan
            
                    list_cols_NaN = df_with_NaN.columns[df_with_NaN.isnull().any()].tolist() #retorna os nomes das colunas que possuem valores nan
            
            
                    if Cord_Z in list_cols_NaN:   #o atributo selecionado possui valores nulos  
            
                        
                        #df_with_NaN = self.df[self.df[Cord_Z].isnull()]                     #dataframe com valores nan na coluna de Cord_Z 
                        #list_rows_NaN = list(df_with_NaN.index.values)                      #retorna os indices das linhas que possuem valores nan
                        #self.df.drop(index=list_rows_NaN, inplace=True)                     #apaga linhas com valores nulos 
                        #self.df.reset_index(drop = True, inplace=True)                      #reset the index without new colum index    
                       
                        #self.df[Cord_Z].fillna(value=df[Cord_Z].mean(), inplace=True)       #preenche com o valor médio da coluna 
                        self.df[Cord_Z].fillna(method = 'backfill', inplace = True)          #preenche com o valor anterior ao do nan 
                        #self.df[Cord_Z].fillna(method = 'ffill', inplace=True)              #preenche com o valor posterir ao do nan 


                    ###########################################################
                    #substituir outliers pelo valor médio da coluna
                    if self.dlg.checkBox_Eliminate_Outilier.isChecked():
                        
                        list_index_outlier = []
                        list_index_outlier = functions.localizar_outlier(self.df, Cord_Z)
                        
                        
                        #calcular mean com base nos 16 vizinhos + proximos. 
                        
                        features = np.column_stack([self.df[self.Cord_X], self.df[self.Cord_Y]])
                        
                        for cont in list_index_outlier:                                      #cont variando para cada ponto de outlier
               
                            vt2 = np.copy(np.array(self.df[Cord_Z]))                              #Array 1d (141,) com os valores da covariavel 
                            vt2 = np.delete(vt2, (cont), axis=0)                                  #deleta a linha cont da matriz - vt2 
                                         
            
                            features2 = np.copy(features)                                         #Array 1d (141,) com os valores da covariavel 
                            features2 = np.delete(features2, (cont), axis=0)                      #deleta a linha cont da matriz - features2 
                             
                            gridxy = np.c_[features2[:,0], features2[:,1]]                        #Array 2d com os valores (140,2) com os valores de x, y 
                            
                            ## ------------- Creating KDTree
                            tree = spatial.cKDTree(gridxy)                                        #objeto com as distâncias entre os pontos  
                                   
                            p = np.array([features[cont,0], features[cont,1]])                    #p = ponto (x,y) de features 
            
                                
                            raio_busca = float(self.dlg.lineEdit_SVM_VBRaio.text())
                            neigs      = tree.query_ball_point(p, raio_busca)                     #neigs     = indice no vetor de array dos pontos a 50m de distancia  

                            if len(neigs) > n_neig:                                               #nr. de vizinhos encontrados dentro do raio de busca excedeu o máximo nr. de vizinhos permitido -> usa o máximo de vizinhos permitido  
                                distances, points_idx = tree.query(p, k=n_neig)                   #distances     = distancia de p aos 16 pontos mais proximos em ordem crescente 
                            elif len(neigs) < 2:                             
                                distances, points_idx = tree.query(p, k=3)                        #distances = distancia de p aos 3 pontos mais proximos em ordem crescente  
                            else: 
                                distances, points_idx = tree.query(p, k=len(neigs))               #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 

                                                                                                  #points_idx    = indice no vetor de array dos 16 pontos mais proximos 
                            vt_vals = vt2[points_idx]                                             #vt_vals       = valores observados dos 16 pontos mais proximos         
                           
                            value = functions.mean(distances, vt_vals, weight_IDW)                #value = valor obtido por IDW no ponto p apartir dos 16 vizinhos 

                            
                            #z_mean = self.df[Cord_Z].mean() 
                            #print('valor medio do ponto:', cont, value)
        
        
                            self.df.loc[cont, Cord_Z] = value


                        #print('df com valores substituidos pela media \n:', self.df[Cord_Z].to_string())


                    ###########################################################
                    #definindo o dataframe df_SVM_Trainfeatures


                    if (int(self.dlg.lineEdit_SVM_VBNumMax.text()) == 1):                    #IDW = 1 Método de busca por vizinho + proximo da tabela de atributos                      
                         

                        self.df_SVM_Trainfeatures = pd.concat([self.df_SVM_Trainfeatures, self.df[[Cord_Z]] ], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (feature selecionado pelo usuário)
                        
                        self.df_SVM_Trainfeatures.rename(columns={Cord_Z: Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text()}, inplace=True)


                    elif (int(self.dlg.lineEdit_SVM_VBNumMax.text()) > 1):                   #Método de busca por IDW da Vizinhança da tabela de atributos 
                    

                        #######################################################
                        #gerando IDW para variável Cord_Z  no dataframe df_SVM_Trainfeatures
                        
                        features = np.column_stack([self.df[self.Cord_X], self.df[self.Cord_Y]])
                      
                        lista_IDW = []
                        
                        maximum = len(features)
                        progress = QProgressDialog(self.tr('Gerando IDW em TrainFeatures: ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                        progress.setWindowTitle('Smart-Map')
                        progress.show() 
                        progress.setCancelButton(None)                                            #remove button cancel 
                        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)           #disable button 'X' 
                        progress.setWindowModality(QtCore.Qt.WindowModal)                         #modal for parent form 
                        #progress.setWindowModality(QtCore.Qt.ApplicationModal)                   #modal for application 
                        time.sleep(0.1)


                        for cont in range(len(features)):                                         #cont variando entre (1,141) para cada ponto de features 
               
                            vt2 = np.copy(np.array(self.df[Cord_Z]))                              #Array 1d (141,) com os valores da covariavel 
                            vt2 = np.delete(vt2, (cont), axis=0)                                  #deleta a linha cont da matriz - vt2 
                                         
            
                            features2 = np.copy(features)                                         #Array 1d (141,) com os valores da covariavel 
                            features2 = np.delete(features2, (cont), axis=0)                      #deleta a linha cont da matriz - features2 
                             
                            gridxy = np.c_[features2[:,0], features2[:,1]]                        #Array 2d com os valores (140,2) com os valores de x, y 
                            
                            ## ------------- Creating KDTree
                            tree = spatial.cKDTree(gridxy)                                        #objeto com as distâncias entre os pontos  
                                   
                            p = np.array([features[cont,0], features[cont,1]])                    #p = ponto (x,y) de features 
            
                                
                            raio_busca = float(self.dlg.lineEdit_SVM_VBRaio.text())
                            neigs      = tree.query_ball_point(p, raio_busca)                     #neigs     = indice no vetor de array dos pontos a 50m de distancia  

                            if len(neigs) > n_neig:                                               #nr. de vizinhos encontrados dentro do raio de busca excedeu o máximo nr. de vizinhos permitido -> usa o máximo de vizinhos permitido  
                                distances, points_idx = tree.query(p, k=n_neig)                   #distances     = distancia de p aos 16 pontos mais proximos em ordem crescente 
                            elif len(neigs) < 2:                             
                                distances, points_idx = tree.query(p, k=3)                        #distances = distancia de p aos 3 pontos mais proximos em ordem crescente  
                            else: 
                                distances, points_idx = tree.query(p, k=len(neigs))               #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 

                                                                                                  #points_idx    = indice no vetor de array dos 16 pontos mais proximos 
                            vt_vals = vt2[points_idx]                                             #vt_vals       = valores observados dos 16 pontos mais proximos         
                           
                            value = functions.idw(distances, vt_vals, weight_IDW)                 #value = valor obtido por IDW no ponto p apartir dos 16 vizinhos 
            
                            lista_IDW.append(value)   

                            progress.setValue(cont)                        
                            if progress.wasCanceled():                          
                               progress.close() 
                               return 
    
                        progress.close() 

                                 
                        labels_IDW = np.array(lista_IDW)      #arr_cut com todas as coluna     
                       
                       
                        labels_IDW = labels_IDW.reshape(-1,1)            
                       
                       
                        labels_IDW_df = pd.DataFrame(np.atleast_2d(labels_IDW), columns=[Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text()]) 
         
                         
                        self.df_SVM_Trainfeatures = pd.concat([ self.df_SVM_Trainfeatures, labels_IDW_df ], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (IDW da feature selecionado pelo usuário)
                        
                        

                    ####################################################################### 
                    #definindo o dataframe df_SVM_Testfeatures

                    maximum = (len(self.gridx) * len(self.gridy))
                    progress = QProgressDialog(self.tr('Gerando grid para os pontos de interpolação (x, y, z): ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)
                                     
    
                    #valores da ultima covariável adicionada em TrainFeatures 
                    vt = np.array(self.df_SVM_Trainfeatures.iloc[:,len(self.df_SVM_Trainfeatures.columns)-1]) 
                        
                    #array 2d com as coordenadas (x,y) adicionadas em TrainFeatures 
                    gridxy = np.c_[self.df_SVM_Trainfeatures.iloc[:,0], self.df_SVM_Trainfeatures.iloc[:,1]]
                    
                    ## ------------- Creating KDTree
                    tree = spatial.cKDTree(gridxy)

                    ## ------------- Creating empty grid matrix with np.zeros                               
                    z = np.zeros((self.gridx.shape[0], self.gridy.shape[0]), dtype=float)
    
                    cont = 1    
                    for i, val1 in enumerate(self.gridx):
                        for j, val2 in enumerate(self.gridy):

                            p = np.array([val1, val2])
                            
                                
                            raio_busca = float(self.dlg.lineEdit_SVM_VBRaio.text())
                            neigs      = tree.query_ball_point(p, raio_busca)                         #neigs     = indice no vetor de array dos pontos a 50m de distancia  

                            if len(neigs) > n_neig:                                                   #nr. de vizinhos encontrados dentro do raio de busca excedeu o máximo nr. de vizinhos permitido -> usa o máximo de vizinhos permitido  
                                distances, points_idx = tree.query(p, k=n_neig+1)                     #distances     = distancia de p aos 16 pontos mais proximos em ordem crescente 
                            elif len(neigs) < 2:                             
                                distances, points_idx = tree.query(p, k=3)                            #distances = distancia de p aos 3 pontos mais proximos em ordem crescente  
                            elif len(neigs) < len(self.df_SVM_Trainfeatures):
                                distances, points_idx = tree.query(p, k=len(neigs)+1)                 #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 
                            else:  
                                distances, points_idx = tree.query(p, k=len(neigs))                   #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 


                            vt_vals = vt[points_idx]                                
                            

                            if int(self.dlg.lineEdit_SVM_VBNumMax.text()) == 1:                       #método de busca é com IDW = 1 -> sem vizinhos                            

                                if distances[0] == 0:                                                 #ponto p em features existe na amostragem densa 
                                    value = vt_vals[0]                                                #obtem o valor do ponto p da feature  
                                else: 
                                    value = vt_vals[0]                                                #obtem o valor mais proximo ao ponto p da feature 
                                   
                                 
                            if int(self.dlg.lineEdit_SVM_VBNumMax.text()) > 1:                        #método de busca é por IDW da vizinhança                             

                                
                                if distances[0] == 0:                                                 #ponto p em features existe na amostragem densa 
                                   points_idx    = np.delete(points_idx, 0)                           #remove o primeiro elemento do array  
                                   distances = np.delete(distances, 0)                                 
                                   vt_vals   = np.delete(vt_vals, 0)                         
                                else:
                                   points_idx    = np.delete(points_idx, len(points_idx)-1)           #remove o ultimo elemento do array                                                                      
                                   distances = np.delete(distances, len(distances)-1)                 
                                   vt_vals   = np.delete(vt_vals, len(vt_vals)-1)                         

                                value = functions.idw(distances, vt_vals, weight_IDW)                 #value = valor obtido por IDW no ponto p apartir dos 16 vizinhos 

                            z[i,j] = value

                            cont = cont + 1 
                            progress.setValue(cont)                        
                            if progress.wasCanceled():                          
                               progress.close() 
                               return 
    
                    progress.close() 

                            
                            
                    maximum = (len(self.gridx) * len(self.gridy))
                    progress = QProgressDialog(self.tr('Aplicando Área de Contorno ao grid dos pontos de interpolação: ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)

                    lista = []                               
    
                    if self.dlg.checkBox_Area_Contorno.isChecked(): 
                        
                        if len(self.df_limite) <= 0:  #usuário selecionou o checkbox mas não clicou no botão para definir o contorno 
                            if (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0): 
                                self.pushButton_Area_Contorno_clicked()    


                        polygono = np.array(self.df_limite, dtype=float)    #define o polygono = area de contorno
                        bbPath = mplPath.Path(polygono)
                        
                        cont = 1       
                        for i in range(len(self.gridx)):
                            for j in range(len(self.gridy)): 
                                ponto = (self.gridx[i]+(self.Pixel_Size_X/2), self.gridy[j]-(self.Pixel_Size_Y/2))
                                if bbPath.contains_point(ponto): 
                                    lista.append([z[i,j]])   
                                cont = cont + 1 
                                progress.setValue(cont)                        
                                if progress.wasCanceled():                          
                                   progress.close() 
                                   return 
      
                    else: 
    
                        cont = 1       
                        for i in range(len(self.gridx)):
                            for j in range(len(self.gridy)): 
                                lista.append([z[i,j]])   
                                cont = cont + 1 
                                progress.setValue(cont)                        
                                if progress.wasCanceled():                          
                                   progress.close() 
                                   return 
 
       
                    progress.close() 
                    
                    arr = np.array(lista)                                               #arr_cut com todas as colunas                
                    self.features_grid =  np.column_stack([self.features_grid, arr])    #concatena apos ultima coluna 
                                
                    arr = arr.reshape(-1,1)            

                    arr_df = pd.DataFrame(np.atleast_2d(arr), columns=[Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text()]) #['IDW_' + Cord_Z])               
 
                    self.df_SVM_Testfeatures = pd.concat([ self.df_SVM_Testfeatures, arr_df ], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (feature selecionado pelo usuário)

                    self.df_SVM_Testfeatures.to_csv(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Test_Set.csv'), sep=',', index = False, encoding='utf-8')
                        
                ############################################################### 
                #layer selecionada do grid_dense 
    
                elif self.dlg.comboBox_SVM_Fonte.currentIndex() == 1:       
                    
                
                    selectedLayer = self.dlg.mMapLayerComboBox_DenseLayer.currentLayer() 
    
                    if selectedLayer.type() == QgsMapLayerType.RasterLayer:    #LayerDense é Raster 
            
                        dim = selectedLayer.extent().toString()
                        if ' ' in dim: 
                            dim = dim.replace(' ','')
    
                        coords = dim.split(":") 
                        coord_min = coords[0].split(",")                            
                        coord_max = coords[1].split(",")
    
                        coord_x_min = float(coord_min[0])
                        coord_y_min = float(coord_min[1])
                        coord_x_max = float(coord_max[0])
                        coord_y_max = float(coord_max[1])
                        
                        gridx       = np.arange(coord_x_min, coord_x_max, self.Pixel_Size_X)
                        gridy       = np.arange(coord_y_min, coord_y_max, self.Pixel_Size_Y)

                        if self.dlg.checkBox_Area_Contorno.isChecked(): 
                            polygono = np.array(self.df_limite, dtype=float)#define o poly = area de contorno 
                            bbPath = mplPath.Path(polygono)
    

                        maximum = (len(gridx) * len(gridy))
                        progress = QProgressDialog(self.tr('Gerando grid para os pontos de interpolação (x, y, z): ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                        progress.setWindowTitle('Smart-Map')
                        progress.show() 
                        progress.setCancelButton(None)                                     #remove button cancel 
                        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                        time.sleep(0.1)
            
                        
                        features_Coordx = []
                        features_Coordy = []
                        features_target = []
                        
                        cont = 1
                        for i in range(len(gridx)):
                            for j in range(len(gridy)): 
    
                                val, res = selectedLayer.dataProvider().sample(QgsPointXY(gridx[i], gridy[j]), 1)  #verificar valor no ponto no RasterLayer 
    
                                if res == True: #possui valor no ponto 
    
                                    if val >= 0.0:  #evitar valores em mapas com interpolação cujo valor val = -1000000000.0
                                        
                                        if self.dlg.checkBox_Area_Contorno.isChecked(): 
                                            ponto = (gridx[i], gridy[j])
                                            if bbPath.contains_point(ponto): 
                                                 features_Coordx.append(gridx[i])   #Indice da coordenada X     
                                                 features_Coordy.append(gridy[j])   #Indice da coordenada Y 
                                                 features_target.append(val)        #Indice de v_target em layer dense 
                                        else: 
                                            features_Coordx.append(gridx[i])        #Indice da coordenada X     
                                            features_Coordy.append(gridy[j])        #Indice da coordenada Y 
                                            features_target.append(val)             #Indice de v_target em layer dense 
                                                                           
                                cont = cont + 1 
                                progress.setValue(cont)                        
                                if progress.wasCanceled():                          
                                   progress.close() 
                                   return 
 
       
                        progress.close() 

    
                    else:                                                      #Layer_Dense é um vector layer 
    
                        '''
                        #obter as coordenadas de um shapefile
                        layer = iface.activeLayer()
                        features = layer.getFeatures()
                        for feat in features:
                        	geo= QgsGeometry.asPoint(feat.geometry())
                        	pxy=QgsPointXY(geo)
                        	print (pxy.x(),pxy.y())
                        '''

                        features = selectedLayer.getFeatures()                       
                        
                        id_target = self.dlg.comboBox_SVM_Features.currentIndex()        #indice da coluna selecionada na feature 
                        #id_coordx = self.dlg.comboBox_CordX_DenseLayer.currentIndex()   #indice da coluna selecionada na feature 
                        #id_coordy = self.dlg.comboBox_CordY_DenseLayer.currentIndex()   #indice da coluna selecionada na feature 
    
                        
                        features_Coordx = []
                        features_Coordy = []
                        features_target = []
                        for feat in features:
                             attrs = feat.attributes()
                             geom = QgsGeometry.asPoint(feat.geometry())
                             pxy=QgsPointXY(geom)

                             if (attrs[id_target] != None):                    #verificar se são valores != de nulos 
                                 features_Coordx.append(pxy.x())               #Valor da coordenada X     
                                 features_Coordy.append(pxy.y())               #Valor da coordenada Y 
                                 features_target.append(attrs[id_target])      #Indice de v_target em layer dense 
                             
    
                        features_Coordx = np.array(features_Coordx)
                        features_Coordy = np.array(features_Coordy)
                        features_target = np.array(features_target)
                  
    
                    features_dense = np.column_stack([features_Coordx, features_Coordy, features_target])      

    
                    ####################################################################### 
                    #definindo o dataframe df_SVM_Trainfeatures

                    maximum = len(self.data)
                    progress = QProgressDialog(self.tr('Gerando covariáveis em TrainFeatures: ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)

    
                    vt_dense = features_dense[:,2]                                           #Array 1d (783,) com os valores da covariavel 
                       
                    gridxy_dense = np.c_[features_dense[:,0], features_dense[:,1]]           #Array 2d com os valores (783,2) com os valores de x, y 
                   
                    ## ------------- Creating KDTree
                    tree_dense = spatial.cKDTree(gridxy_dense)                               #objeto com as distâncias entre os pontos  
                    ## ------------- Creating empty grid matrix with np.zeros
                              
                    #z = np.zeros((gridx.shape[0], gridy.shape[0]), dtype=float)             #matriz (121, 104) de zeros formada pelos pontos de gridx e gridy
           
                    lista = []
                    for cont in range(len(self.data)):                                       #cont variando entre (1,141) para cada ponto de features 
           
                           p = np.array([self.data[cont,0], self.data[cont,1]])                      #p = ponto (x,y) de features 

                           raio_busca = float(self.dlg.lineEdit_SVM_VBRaio.text())
                           neigs      = tree_dense.query_ball_point(p, raio_busca)                   #neigs     = indice no vetor de array dos pontos a 50m de distancia  

                           if len(neigs) > n_neig:                                                   #nr. de vizinhos encontrados dentro do raio de busca excedeu o máximo nr. de vizinhos permitido -> usa o máximo de vizinhos permitido  
                              distances, points_idx = tree_dense.query(p, k=n_neig+1)                #distances     = distancia de p aos 16 pontos mais proximos em ordem crescente 
                           elif len(neigs) < 2:                             
                              distances, points_idx = tree_dense.query(p, k=3)                       #distances = distancia de p aos 3 pontos mais proximos em ordem crescente  
                           elif len(neigs) < len(features_dense):
                              distances, points_idx = tree_dense.query(p, k=len(neigs)+1)            #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 
                           else:  
                              distances, points_idx = tree_dense.query(p, k=len(neigs))              #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 

                                                                                                     #points_idx    = indice no vetor de array dos 16 pontos mais proximos 
                           vt_vals_dense = vt_dense[points_idx]                                      #vt_vals_dense = valores observados dos 16 pontos mais proximos         
           
                          
                           if int(self.dlg.lineEdit_SVM_VBNumMax.text()) == 1:                       #método de busca é com IDW = 1 -> sem vizinhos                            

                               if distances[0] == 0:                                                 #ponto p em features existe na amostragem densa 
                                   value = vt_vals_dense[0]                                          #obtem o valor do ponto p da feature que está também na amostragem densa 
                               else: 
                                   value = vt_vals_dense[0]                                          #obtem o valor mais proximo da amostragem densa ao ponto p da feature 
                                   
           
                           if int(self.dlg.lineEdit_SVM_VBNumMax.text()) > 1:                        #método de busca é por IDW da vizinhança                             

                                if distances[0] == 0:                                                #ponto p em features existe na amostragem densa 
                                   points_idx    = np.delete(points_idx, 0)                          #remove o primeiro elemento do array  
                                   distances     = np.delete(distances, 0)                           
                                   vt_vals_dense = np.delete(vt_vals_dense, 0)                         
                                else:  
                                   points_idx    = np.delete(points_idx, len(points_idx)-1)          #remove o ultimo elemento do array                                  
                                   distances     = np.delete(distances, len(distances)-1)            
                                   vt_vals_dense = np.delete(vt_vals_dense, len(vt_vals_dense)-1)                         


                                value = functions.idw(distances, vt_vals_dense, weight_IDW)          #value = valor obtido por IDW no ponto p apartir dos 16 vizinhos 


                           lista.append(value)   

                           progress.setValue(cont)                        
                           if progress.wasCanceled():                          
                               progress.close() 
                               return 
 
   
                    progress.close() 
                           
                    
                    arr = np.array(lista)      #arr_cut com todas as coluna     
                   
                   
                    arr = arr.reshape(-1,1)            
                   

                    #converter o numpy array em um dataframe 
                    arr_df = pd.DataFrame(np.atleast_2d(arr), columns=[Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text()]) #['IDW_' + Cord_Z])               

                   
       
                    self.df_SVM_Trainfeatures = pd.concat([ self.df_SVM_Trainfeatures, arr_df ], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (IDW da feature selecionado pelo usuário)
    
                    #salvar o dataframe df_SVM_TrainFeatures 
                    self.df_SVM_Trainfeatures.to_csv(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Train_Set.csv'), sep=',', index = False, encoding='utf-8')


                    ###########################################################
                    #definindo o dataframe df_SVM_Testfeatures

                    maximum = ( len(self.gridx) * len(self.gridy) )
                    progress = QProgressDialog(self.tr('Gerando grid para os pontos de interpolação (x, y, z): ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)

                    
                    #obtem os dados de features_dense  
                    #os dados de features_dense serão repassados para test_features 
                    vt_dense     = features_dense[:,2]                                       #Array 1d (783,)  com os valores da covariavel                        
                    gridxy_dense = np.c_[features_dense[:,0], features_dense[:,1]]           #Array 2d (783,2) com os valores de x, y 
                        
                    #obtem os dados de train_features (estes dados vieram de features_dense) 
                    #os dados de features_dense adicionados em train_features serão repassados para test_features 
                    #vt_dense     = np.array(self.df_SVM_Trainfeatures.iloc[:, len(self.df_SVM_Trainfeatures.columns)-1]) #Array 1d (141,)  com os valores da covariavel                                                
                    #gridxy_dense = np.c_[self.df_SVM_Trainfeatures.iloc[:,0], self.df_SVM_Trainfeatures.iloc[:,1]]       #Array 2d (141,2) com os valores de x, y

                    
                    ## ------------- Creating KDTree
                    tree_dense = spatial.cKDTree(gridxy_dense)

                    ## ------------- Creating empty grid matrix with np.zeros                               
                    z = np.zeros((self.gridx.shape[0], self.gridy.shape[0]), dtype=float)
        
                    cont = 1    
                    for i, val1 in enumerate(self.gridx):
                        for j, val2 in enumerate(self.gridy):
                            p = np.array([val1, val2])

                                
                            raio_busca = float(self.dlg.lineEdit_SVM_VBRaio.text())
                            neigs      = tree_dense.query_ball_point(p, raio_busca)                  #neigs     = indice no vetor de array dos pontos a 50m de distancia  

                            if len(neigs) > n_neig:                                                  #nr. de vizinhos encontrados dentro do raio de busca excedeu o máximo nr. de vizinhos permitido -> usa o máximo de vizinhos permitido  
                               distances, points_idx = tree_dense.query(p, k=n_neig+1)               #distances     = distancia de p aos 16 pontos mais proximos em ordem crescente 
                            elif len(neigs) < 2:                             
                               distances, points_idx = tree_dense.query(p, k=3)                      #distances = distancia de p aos 3 pontos mais proximos em ordem crescente  
                            elif len(neigs) <  len(self.df_SVM_Trainfeatures):
                               distances, points_idx = tree_dense.query(p, k=len(neigs)+1)           #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 
                            else:  
                               distances, points_idx = tree_dense.query(p, k=len(neigs))             #distances = distancia de p aos neigs pontos mais proximos em ordem crescente 


                            vt_vals_dense = vt_dense[points_idx]
    
    
                            if int(self.dlg.lineEdit_SVM_VBNumMax.text()) == 1:                       #método de busca é com IDW = 1 -> sem vizinhos                            

                                if distances[0] == 0:                                                 #ponto p em features existe na amostragem densa 
                                    value = vt_vals_dense[0]                                          #obtem o valor do ponto p da feature que está também na amostragem densa 
                                else: 
                                    value = vt_vals_dense[0]                                          #obtem o valor mais proximo da amostragem densa ao ponto p da feature 
                                                       
            
                            if int(self.dlg.lineEdit_SVM_VBNumMax.text()) > 1:                        #método de busca é por IDW da vizinhança                             

                                if distances[0] == 0:                                                 #ponto p em features existe na amostragem densa 
                                   points_idx    = np.delete(points_idx, 0)                           #remove o primeiro elemento do array  
                                   distances     = np.delete(distances, 0)                            
                                   vt_vals_dense = np.delete(vt_vals_dense, 0)                         
                                else:  
                                   points_idx    = np.delete(points_idx, len(points_idx)-1)           #remove o ultimo elemento do array                                  
                                   distances     = np.delete(distances, len(distances)-1)         
                                   vt_vals_dense = np.delete(vt_vals_dense, len(vt_vals_dense)-1)                         


                                value = functions.idw(distances, vt_vals_dense, weight_IDW)           #value = valor obtido por IDW no ponto p apartir dos 16 vizinhos 

                            #print('cont: ', cont, ' points: ', points_idx, ' distances: ', distances, ' vals: ', vt_vals_dense, ' value: ', value)

                            z[i,j] = value  

                            cont = cont + 1 

                            progress.setValue(cont)                        
                            if progress.wasCanceled():                          
                                progress.close() 
                                return 
 
   
                    progress.close() 

                    maximum = ( len(self.gridx) * len(self.gridy) )
                    progress = QProgressDialog(self.tr('Aplicando Área de Contorno ao grid dos pontos de interpolação: ') + Cord_Z + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                    progress.setWindowTitle('Smart-Map')
                    progress.show() 
                    progress.setCancelButton(None)                                     #remove button cancel 
                    #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                    progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                    #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                    time.sleep(0.1)
        
                                    
                    lista = []
        
                    if self.dlg.checkBox_Area_Contorno.isChecked(): 
        
                        polygono = np.array(self.df_limite, dtype=float)    #define o polygono = area de contorno
                        bbPath = mplPath.Path(polygono)
                        
                        cont = 1       
                        for i in range(len(self.gridx)):
                            for j in range(len(self.gridy)): 
                                ponto = (self.gridx[i]+(self.Pixel_Size_X/2), self.gridy[j]-(self.Pixel_Size_X/2))
                                if bbPath.contains_point(ponto): 
                                    lista.append([z[i,j]])   
                                cont = cont + 1 
                                progress.setValue(cont)                        
                                if progress.wasCanceled():                          
                                    progress.close() 
                                    return 
 
                    
                    else: 
                    
                        cont = 1       
                        for i in range(len(self.gridx)):
                            for j in range(len(self.gridy)): 
                                lista.append([z[i,j]])   
                                cont = cont + 1 
                                progress.setValue(cont)                        
                                if progress.wasCanceled():                          
                                    progress.close() 
                                    return 
 
   
                    progress.close() 


                    arr = np.array(lista)      #arr_cut com todas as colunas                
                                   
                    self.features_grid =  np.column_stack([self.features_grid, arr]) #concatena apos ultima coluna 
                               
                    arr = arr.reshape(-1,1)            
                                  
                    #converter o numpy array em um dataframe 
                    arr_df = pd.DataFrame(np.atleast_2d(arr), columns=[Cord_Z + '_' + self.dlg.lineEdit_SVM_VBNumMax.text()]) #['IDW_' + Cord_Z])               
        
                    self.df_SVM_Testfeatures = pd.concat([ self.df_SVM_Testfeatures, arr_df ], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (IDW da feature selecionado pelo usuário)
        
                    self.df_SVM_Testfeatures.to_csv(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Test_Set.csv'), sep=',', index = False, encoding='utf-8')



                ####################################################################### 
                #preenchendo o datatable Trainfeatures
     
                maximum = len(self.df_SVM_Trainfeatures.index)
                progress = QProgressDialog(self.tr('Preenchendo a Tabela TrainFeatures') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
                progress.setWindowTitle('Smart-Map')
                progress.show() 
                progress.setCancelButton(None)                                     #remove button cancel 
                #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                time.sleep(0.1)


                self.dlg.datatable_SVM_Trainfeatures.setColumnCount(len(self.df_SVM_Trainfeatures.columns))
                self.dlg.datatable_SVM_Trainfeatures.setRowCount(len(self.df_SVM_Trainfeatures.index))

    
                #preencher o cabeçalho
                try:                       
                    cols = [] 
                    cols = list(self.df_SVM_Trainfeatures.columns.values)
                
                    self.dlg.datatable_SVM_Trainfeatures.setHorizontalHeaderLabels(cols)

                except AttributeError: 

                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                    msg_box.exec_()
                    
                    
                #preencher as linhas do datatable TrainFeatures 
                cont = 1
                try:                       
                    for i in range(len(self.df_SVM_Trainfeatures.index)):      #linhas 
                            valor = self.df_SVM_Trainfeatures.iloc[i,len(self.df_SVM_Trainfeatures.columns)-1]

                            if valor.dtype == "float64": 
                                valor = '%.3f' % valor                       
                        
                            valor = QTableWidgetItem(str(valor))                  
                            self.dlg.datatable_SVM_Trainfeatures.setItem(i, len(self.df_SVM_Trainfeatures.columns)-1, valor)
                            cont = cont + 1 
                            progress.setValue(cont)                        
                            if progress.wasCanceled():                          
                                progress.close() 
                                return 
 
   
    
                except AttributeError: 

                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                    msg_box.exec_()

                progress.close() 
    
                self.dlg.datatable_SVM_Trainfeatures.resizeColumnsToContents()
    
                self.dlg.datatable_SVM_Trainfeatures.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

                #salvar o dataframe df_SVM_TrainFeatures 
                self.df_SVM_Trainfeatures.to_csv(os.path.join(self.path_absolute ,  '1_SVM_' + self.VTarget_FileName + '_Train_Set.csv'), sep=',', index = False, encoding='utf-8')
    
       
                self.SVM_Add_Feature = True 
    
                self.dlg.pushButton_SVM.setEnabled(True)
                self.dlg.label_SVM.hide()           
                self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
                self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
                #self.dlg.pushButton_Validacao_Cruzada_SVM.setEnabled(False)
                self.dlg.label_validacao_cruzada_SVM.hide()
                self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
                self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)

                self.dlg.comboBox_SVM_Features_Adds.setEnabled(True)
                self.dlg.pushButton_SVM_Remove_Feature.setEnabled(True)            

                #self.checkBox_Moran_clicked()  #exibe correlação de Moran 
                #self.dlg.checkBox_Moran.setChecked(False)
                

                

    def  pushButton_SVM_Add_Selected_Features_clicked(self):                   #Add Selected Features do modelo de ML
               
        
        msg = QMessageBox.question(self.dlg, self.tr('Mensagem'), self.tr('As variáveis selecionadas serão adicionadas ao modelo SVM. Deseja continuar?'), QMessageBox.Yes | QMessageBox.No)

        if msg == QMessageBox.Yes:

            for v in range(len(self.list_rows_moran)): 
           
                row = self.list_rows_moran[v]

                v_target = self.dlg.datatable_moran.item(row, 1).text()        #obtem o valor da 2ª coluna da linha selecionada 

                self.dlg.comboBox_SVM_Features.setCurrentText(v_target)             
                    
                self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(0) 

                self.pushButton_SVM_Add_Feature_clicked()
        


    def datatable_moran_checkbox_clicked(self, item):

        if item.checkState() == QtCore.Qt.Checked:  #quando marca o checkbox  

            if not item.row() in self.list_rows_moran: 
                self.list_rows_moran.append(item.row())
                self.list_rows_moran.sort()
        else:
            if item.row() in self.list_rows_moran:
                self.list_rows_moran.remove(item.row())


        if len(self.list_rows_moran) > 0: 
            self.dlg.pushButton_SVM_Add_Selected_Features.setEnabled(True)
        else: 
            self.dlg.pushButton_SVM_Add_Selected_Features.setEnabled(False)


        


    def  pushButton_SVM_Remove_Feature_clicked(self):                          #Add Selected Features do modelo de ML

        
        
        if len(self.list_cov_SVM) == 2:                                        #só tem X e Y como covariáveis -> não pode remover X e Y 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Todas as Covariáveis do Modelo SVM foram removidas.'))
            msg_box.exec_()              
            
        else: 

            id_col =  self.dlg.comboBox_SVM_Features_Adds.currentIndex()       #obtem o índice da coluna a ser excluída 

            if id_col >= 2: 

                self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(0) 

                #######################################################################
                #definindo o combobox SVM_Features_Adds

                list_cov_SVM_Index = [i for i in range(self.dlg.comboBox_SVM_Features_Adds.count())]     #lista de indice 
                list_cov_SVM_Index.remove(id_col)


                self.dlg.comboBox_SVM_Features_Adds.removeItem(id_col)         # delete (id_col) column of comboBox_SVM_Features_Adds 
                
                self.features_grid = np.delete(self.features_grid, id_col, 1)  # delete (id_col) column of features_grid
                
                self.list_cov_SVM = [self.dlg.comboBox_SVM_Features_Adds.itemText(i) for i in range(self.dlg.comboBox_SVM_Features_Adds.count())] 
                
                if len(self.list_cov_SVM) == 2:                                #so tem coordenadas (X, Y)
    
                    self.SVM_Add_Feature = False 
                    #self.dlg.pushButton_SVM.setEnabled(False)
                    self.dlg.pushButton_SVM_Remove_Feature.setEnabled(False)            



                self.df_SVM_Trainfeatures = self.df_SVM_Trainfeatures.iloc[:, list_cov_SVM_Index]
                #self.df_SVM_Trainfeatures.drop(self.df_SVM_Trainfeatures.columns[id_col], axis=1, inplace=True)    #-> se tiver coluna com mesmo nome, apaga todas as colunas de mesmo nome 
                
                self.df_SVM_Testfeatures = self.df_SVM_Testfeatures.iloc[:,list_cov_SVM_Index]
                #self.df_SVM_Testfeatures.drop( self.df_SVM_Testfeatures.columns[id_col],  axis=1, inplace=True)  
        
    
                self.dlg.label_SVM.hide()           
                self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(0)
                self.dlg.datatable_pontos_interpolados_SVM.setRowCount(0)
    
                #self.dlg.pushButton_Validacao_Cruzada_SVM.setEnabled(False)
                self.dlg.label_validacao_cruzada_SVM.hide()
                self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(0)
                self.dlg.datatable_validacao_cruzada_SVM.setRowCount(0)                
    
                ###############################################################
                #definindo o dataframe df_SVM_Trainfeatures
    
                
                self.dlg.datatable_SVM_Trainfeatures.removeColumn(id_col)            
                
                self.dlg.datatable_SVM_Trainfeatures.resizeColumnsToContents()
    
                self.dlg.datatable_SVM_Trainfeatures.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable
    
                #self.checkBox_Moran_clicked() #exibe correlação de Moran 

                #salvar o dataframe df_SVM_TrainFeatures e df_sVM_TestFeatures 
                self.df_SVM_Trainfeatures.to_csv(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Train_Set.csv'), sep=',', index = False, encoding='utf-8')
                self.df_SVM_Testfeatures.to_csv(os.path.join(self.path_absolute ,  '1_SVM_' + self.VTarget_FileName + '_Test_Set.csv'), sep=',', index = False, encoding='utf-8')


            else:     

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('As Coordenadas (x, y) não podem ser removidas do Modelo SVM.'))
                msg_box.exec_()              
              


    def datatable_SVM_Trainfeatures_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Train_Set.csv'))
        os.startfile(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Test_Set.csv'))




    
    def  pushButton_SVM_clicked(self):    #Realizar interpolação utilizando SVM

             
        '''
        #if ((self.SVM_Add_Coord == False) or (self.SVM_Add_Feature == False)): #não adicionou features ao modelo 

        if (self.SVM_Add_Coord == False): #não adicionou coordenadas ao modelo         
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Modelo Incompleto. Não existem covariáveis adicionadas ao Modelo SVM.'))
            msg_box.exec_()              
         
        else: 
        '''
        
        self.dlg.tabWidget_Interpolacao_SVM.setCurrentIndex(2)             #aba com mapa interpolado 

        ###############################################################
        #definindo o dataframe df_SVM_Testfeatures -> Colunas (X, Y) para o grid de interpolação 


        if (len(self.df_SVM_Testfeatures) == 0):                           #só tem CoordX e Coordy  e dataframe está fazio 

           
            self.gridx = np.arange(float(self.Cord_X_min), float(self.Cord_X_max), self.Pixel_Size_X)
            self.gridy = np.arange(float(self.Cord_Y_min), float(self.Cord_Y_max), self.Pixel_Size_Y)        
    

            maximum = (len(self.gridx) * len(self.gridy)) 
            progress = QProgressDialog(self.tr('Machine Learning - Support Vector Machine...'), self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                 #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)#disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)              #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)        #modal for application 
            time.sleep(0.1)

    
            #monta o grid_xy  ['x', 'y'] com 7860 linhas 
            cont = 1
            lista_xy = []
            for i in range(len(self.gridx)):
                for j in range(len(self.gridy)): 
                    lista_xy.append([self.gridx[i]+(self.Pixel_Size_X/2), self.gridy[j]-(self.Pixel_Size_Y/2)])   
                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 

            progress.close() 

            arr_xy = np.array(lista_xy)
            
           
            if self.dlg.checkBox_Area_Contorno.isChecked(): 

                if len(self.df_limite) <= 0:  #usuário selecionou o checkbox mas não clicou no botão para definir o contorno 
                    if (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0): 
                        self.pushButton_Area_Contorno_clicked()    
                        
                lista_cut_xy = []
    
                polygono = np.array(self.df_limite, dtype=float)        #define o polygono = area de contorno 
                bbPath = mplPath.Path(polygono)

                maximum = len(arr_xy)
                progress = QProgressDialog(self.tr('Gerando grid para os pontos de interpolação (x, y, z): '), self.tr('Cancelar'),  1, maximum, self.dlg)
                progress.setWindowTitle('Smart-Map')
                progress.show() 
                progress.setCancelButton(None)                                     #remove button cancel 
                #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
                progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
                #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
                time.sleep(0.1)

               
                cont = 1
                for i in range(len(arr_xy)):
                    ponto = (arr_xy[i,0], arr_xy[i,1])
                    if bbPath.contains_point(ponto): 
                        lista_cut_xy.append([arr_xy[i,0], arr_xy[i,1]])

                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 

                progress.close() 
                 
                arr_xy = np.array(lista_cut_xy)
                    
            self.grid_xy = np.array(arr_xy) 
             

            self.df_SVM_Testfeatures = pd.DataFrame(np.atleast_2d(self.grid_xy), columns=[self.Cord_X, self.Cord_Y]) 
    
    
            
            self.features_grid = np.array(self.grid_xy)


        ###############################################################
        #termino do preenchimento do dataframe df_SVM_Testfeatures -> Colunas (X, Y) para o grid de interpolação 


             
        #set the max Kfold to 20 points in each fold
        k_folds = round(len(self.data)/20) 

        if k_folds < 2: 
           k_folds = 2  
        elif k_folds > 5: 
           k_folds = 5 
     
        #k_folds    =  self.dlg.spinBox_KFolds_CV.value()                  #numero de K-Folds para CV

        features = np.array(self.df_SVM_Trainfeatures, dtype=float)
     
        labels =   np.array(self.df_SVM_Trainlabels   , dtype=float)
      
     
        maximum = (len(self.grid_xy) * 3)  + 5            
        progress = QProgressDialog(self.tr('Machine Learning - Support Vector Machine...'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                     #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
        time.sleep(0.1)


        ###################################################################
        #otimização dos parametros do SVM


        cont = 1 
        progress.setValue(cont)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 
  
        self.norm = StandardScaler()   #objeto para normalizar as features e labels do SVM 

        #calculando C e gamma ótimo atraves do GridSearchCV                     
        C_average, gamma_average  = functions.svr_param_selection(         self.norm, features, labels, k_folds)  #usa GridSearchCV     
        #C_average, gamma_average = functions.svr_param_selection_optimize(self.norm, features, labels, k_folds)  #usa scikit-optimize 

    

        ###################################################################
        #Treinamento do Modelo de Machine Learning 
        
        cont = cont + 1 
        progress.setValue(cont)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 
 
 
        self.svr = svm.SVR(kernel = 'rbf', C = C_average, gamma = gamma_average)

   
        #Split the data into training and testing sets
        #quando separa escolhe-se ao aleatório quais serão para treianamento e quais serão para teste, não mantendo a mesma ordem dos vetores originais    
        train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size = 1, random_state = 42)
        
        
        #considerando que todos os valores amostrados serão considerados para treinamento 
        train_features = np.copy(features)
        train_labels = np.copy(labels)
        
        #considerando que todos os valores do grid [7860 pontos] serão considerados para teste
        test_features = np.copy(self.features_grid)
        #test_labels  = np.copy(test_labels)
       
    
        self.norm  =  self.norm.fit(train_features)           #ajusta o vetor de features 141 pontos      (x, y, IDW_cov1, .... IDW_covn)  
        #self.norm =  self.norm.fit(test_features)            #ajustar  o vetor features_grid 7860 pontos (x, y, IDW_cov1, .... IDW_covn) 
       
    
        train_features = self.norm.transform(train_features)  #normalizar o vetor de features e labels 
        test_features  = self.norm.transform(test_features )  #normalizar o vetor features_grid (x, y, IDW_cov1, .... IDW_covn) 
    
          
        # Instantiate model 
        #SVR(C=1.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='auto_deprecated', kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
       
        # Instantiate model 
        #svr = svm.SVR()
      
        # Train the model on training data
        self.svr.fit(train_features, train_labels)
        
        predictions = self.svr.predict(test_features)  #valores preditos -> para gerar o mapa de predição [7860]   
        
        self.arr_cut =  np.column_stack([self.grid_xy[:,0], self.grid_xy[:,1], predictions])
 
        #######################################################################
        #definindo o dataframe: df_pontos_interpolados_SVM
  
     
        df_pontos_interpolados_SVM = pd.DataFrame(np.atleast_2d(self.arr_cut), columns=[self.Cord_X, self.Cord_Y, self.v_target])
        df_pontos_interpolados_SVM.to_csv(os.path.join(self.path_absolute ,  '1_SVM_' + self.VTarget_FileName + '_Grid_Map.csv'), sep=',', index = False, encoding='utf-8')
        df_pontos_interpolados_SVM.to_csv(os.path.join(self.path_absolute ,  '1_SVM_' + self.VTarget_FileName + '_Grid_Map.svm'), sep=',', index = False, encoding='utf-8')
    
  
        self.dlg.datatable_pontos_interpolados_SVM.setColumnCount(len(df_pontos_interpolados_SVM.columns))
        self.dlg.datatable_pontos_interpolados_SVM.setRowCount(len(df_pontos_interpolados_SVM.index))
        
        
        #preencher o cabeçalho
        try:                       

            cols = [] 
            cols = list(df_pontos_interpolados_SVM.columns.values)  
            cols[2] = self.tr('Z.Predito')
            self.dlg.datatable_pontos_interpolados_SVM.setHorizontalHeaderLabels(cols)

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()
            
       
        #preencher as linhas da planilha 
        try: 
            for i in range(len(df_pontos_interpolados_SVM.index)):         #linhas 
                for j in range(len(df_pontos_interpolados_SVM.columns)):   #colunas 

                    valor = df_pontos_interpolados_SVM.iloc[i,j]

                    if valor.dtype == "float64": 
                        valor = '%.3f' % valor                       
                    
                    valor = QTableWidgetItem(str(valor))                  
                    self.dlg.datatable_pontos_interpolados_SVM.setItem(i,j, valor)   

                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
 
        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()


        self.dlg.datatable_pontos_interpolados_SVM.resizeColumnsToContents();

        self.dlg.datatable_pontos_interpolados_SVM.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable


            
        ###################################################################
        #Exportando arquivo RasterFile  

        cont = cont + 1 
        progress.setValue(cont)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 


        if self.dlg.checkBox_Qgis_Raster.isChecked(): 
 

            # get the filenames
            Input_Table            =                                   '1_SVM_' + self.VTarget_FileName + '_Grid_Map.csv'
            Output_Layer_File_tiff = os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Grid_Map.tiff')
            Output_Layer_Name      =                                   '1_SVM_' + self.VTarget_FileName
            z_field   = self.v_target
            
            try:
                self.dlg.mMapLayerComboBox.currentIndexChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                

            Output_Layer_File_tiff = self.export_raster_to_qgis(Input_Table, Output_Layer_File_tiff, Output_Layer_Name, z_field) 



            ###################################################################
            #Exportando arquivo Shapefile de pontos para QGIS 

            if self.dlg.checkBox_Qgis_Vector_Points.isChecked(): 


                #    marcou area de contorno                       e   definiu a layer de contorno) 
                if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
    
                    
                    self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopoints") 

                else: 
                    self.dlg.checkBox_Qgis_Vector_Points.setChecked(False)           



            ###################################################################
            #Exportando arquivo Shapefile de poligonos para QGIS 

            if self.dlg.checkBox_Qgis_Vector_Polygons.isChecked(): 
                
                #    marcou area de contorno                       e   definiu a layer de contorno) 
                if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
    
                    
                    self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopolygons") 

                else: 
                    self.dlg.checkBox_Qgis_Vector_Polygons.setChecked(False)           


        if self.dlg.checkBox_Qgis_Raster.isChecked(): 

            self.dlg.mMapLayerComboBox.currentIndexChanged.connect(self.mMapLayerComboBox_changed)



        ###################################################################
        #Plotando o Mapa Interpolado por SVM 

        cont = cont + 1 
        progress.setValue(cont)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 
        
        plt3.close()
        plt3.title(self.tr('Mapa Interpolado SVM'))
        plt3.xlabel('Longitude (X)')
        plt3.ylabel('Latitude  (Y)') 

        plt3.xlim(float(self.Cord_X_min-100), float(self.Cord_X_max+100))
        plt3.ylim(float(self.Cord_Y_min-100), float(self.Cord_Y_max+100))


        interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
        
        if interval_x == 0:
            interval_x = 1 #int((self.Cord_X_max-self.Cord_X_min))

        xmarks=[i for i in range(int(self.Cord_X_min),int(self.Cord_X_max) , interval_x)]          
        plt3.xticks(xmarks)


        interval_y = int((self.Cord_Y_max-self.Cord_Y_min)/7)
        
        if interval_y == 0:
            interval_y = 1 #int((self.Cord_X_max-self.Cord_X_min))


        ymarks=[i for i in range(int(self.Cord_Y_min),int(self.Cord_Y_max) , interval_y)]          
        plt3.yticks(ymarks)

        
        plt3.scatter(self.grid_xy[:,0], self.grid_xy[:,1], c=predictions, cmap='RdYlGn', vmin = min(predictions), vmax = max(predictions))    
        
        clb = plt3.colorbar(aspect=20)                                     #expessura do colorbar 
        clb.ax.set_title(self.v_target)

        plt3.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=1.0, bottom=0.1, top=0.95)

        plt3.ticklabel_format(style='plain', useOffset=False, axis='both')

        #janela do plot exibir as coordenadas em notação decimal. 
        ax = plt3.gca()
        ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)
        
        plt3.savefig(     os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Grid_Map.png'))
        pixmap4 = QPixmap(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Grid_Map.png'))
        self.dlg.label_SVM.show()
        self.dlg.label_SVM.setPixmap(pixmap4)

        if self.dlg.checkBox_Qgis_Maps.isChecked(): 
            plt3.show()         

                       
        self.SVM = True
        
        self.load_maps_to_generate_ZM()                              

        progress.close() 



    
    def datatable_pontos_interpolados_SVM_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute ,  '1_SVM_' + self.VTarget_FileName + '_Grid_Map.csv'))



    def label_SVM_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  
        
            if self.SVM == True:                
               image = Image.open(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_Grid_Map.png'))
               image.show()



    def  pushButton_Validacao_Cruzada_SVM_clicked(self):                       #Validação Cruzada da SVM


        '''
        #if ((self.SVM_Add_Coord == False) or (self.SVM_Add_Feature == False)): #não adicionou features ao modelo 
        if (self.SVM_Add_Coord == False): #não coordenadas ao modelo 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Modelo Incompleto. Não existem covariáveis adicionadas ao Modelo SVM.'))
            msg_box.exec_()              
         
        else: 
        '''
        #set the max Kfold to 20 points in each fold
        k_folds = round(len(self.data)/20) 

        if k_folds < 2: 
           k_folds = 2  
        elif k_folds > 5: 
           k_folds = 5 


        features = np.array(self.df_SVM_Trainfeatures, dtype=float)
        
        labels =   np.array(self.df_SVM_Trainlabels  , dtype=float)


        maximum = len(features) + (len(features) * 4) + 3
        progress = QProgressDialog(self.tr('Validação Cruzada - SVM'), self.tr('Cancelar'),  1, maximum, self.dlg)
        progress.setWindowTitle('Smart-Map')
        progress.show() 
        progress.setCancelButton(None)                                     #remove button cancel 
        #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
        progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
        #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
        time.sleep(0.1)


        ###################################################################
        #otimização dos parametros do SVM

        
        progress.setValue(1)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 

        self.norm = StandardScaler()   #objeto para normalizar as features e labels do SVM 

        #calculando C e gamma ótimo atraves do GridSearchCV                     
        C_average, gamma_average  = functions.svr_param_selection(         self.norm, features, labels, k_folds)  #usa GridSearchCV     
        #C_average, gamma_average = functions.svr_param_selection_optimize(self.norm, features, labels, k_folds)  #usa scikit-optimize 

    

        ###################################################################
        #Treinamento do Modelo de Machine Learning 

       
        progress.setValue(2)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 

 
        self.svr = svm.SVR(kernel = 'rbf', C = C_average, gamma = gamma_average)


        ###################################################################
        #Validação Cruzada  LOOCV


        for cont in (range(len(features))):
    
            
            train_features = np.copy(features)
            train_labels = np.copy(labels)
           
            test_features = train_features[cont:cont+1,:]  #copia a linha cont da matriz  train_features(features) 
            
            train_features = np.delete(train_features, (cont), axis=0)     #deleta a linha cont da matriz - train_features         
            train_labels = np.delete(train_labels, (cont), axis=0)         #deleta a linha cont da matriz - train_features         
        
        
            self.norm  = self.norm.fit(train_features)
            #self.norm = self.norm.fit(test_features)
            
            train_features = self.norm.transform(train_features)
                          
            test_features =  self.norm.transform(test_features)
    
            self.svr.fit(train_features, train_labels)
                    
            predictions = self.svr.predict(test_features) 
    
            if cont == 0:  #inicia a matriz de covariaveis p 
                labels_SVM_CV = np.copy(predictions) 
            else:       
                labels_SVM_CV = np.vstack((labels_SVM_CV, predictions))    #concatena após ultima linha. 
            

            progress.setValue(cont+2)                        
            if progress.wasCanceled():                          
               progress.close() 
               return 

        
        labels_SVM_CV = labels_SVM_CV.reshape(len(labels_SVM_CV))          #redimensiona o 2d-array em um 1d-array
    
        data_CV_SVM = np.column_stack((features[:, 0], features[:, 1], labels, labels_SVM_CV))    


        self.df_CV_SVM = pd.DataFrame(np.atleast_2d(data_CV_SVM), columns=['Coord_X', 'Coord_Y', self.tr('Z.Obs.'), self.tr('Z.Predito')])
        self.df_CV_SVM.to_csv(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_CV.csv'), sep=',', index = False, encoding='utf-8')

        
        self.dlg.datatable_validacao_cruzada_SVM.setColumnCount(len(self.df_CV_SVM.columns))
        self.dlg.datatable_validacao_cruzada_SVM.setRowCount(len(self.df_CV_SVM.index))
        

        #preencher o cabeçalho
        try:                       

            cols = [] 
            cols = list(self.df_CV_SVM.columns.values)
            
            self.dlg.datatable_validacao_cruzada_SVM.setHorizontalHeaderLabels(cols)

        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()
                  
        #preencher as linhas da planilha 
        try:                       
                    
            for i in range(len(self.df_CV_SVM.index)):  #linhas 
                for j in range(len(self.df_CV_SVM.columns)):   #colunas 

                    valor = self.df_CV_SVM.iloc[i,j]

                    if valor.dtype == "float64": 
                        valor = '%.3f' % valor                       
                    
                    valor = QTableWidgetItem(str(valor))                  
                    self.dlg.datatable_validacao_cruzada_SVM.setItem(i,j, valor)

                    cont = cont + 1 
                    progress.setValue(cont+2)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 
                    
                    
        except AttributeError: 

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
            msg_box.exec_()

   
        self.dlg.datatable_validacao_cruzada_SVM.resizeColumnsToContents();

        self.dlg.datatable_validacao_cruzada_SVM.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

        progress.setValue(cont+3)                        
        if progress.wasCanceled():                          
           progress.close() 
           return 

        
        #plotar o gráfico da validação cruzada 
            
        #regression part  with sklearn.linear_model import LinearRegression
        RMSE_lib, R2_RCV, regressor, R2_Elp, lccc = functions.calculate_statistics(labels_SVM_CV, labels)

        #print('R2_Elp: ', R2_Elp)
        #print('lccc: ', lccc)

        
        RMSE_lib = '%.3f' % (RMSE_lib)   
        R2_RCV = '%.3f' % (R2_RCV) 
             
        
        #To retrieve the intercept:
        intercept = regressor.intercept_[0]

        #For retrieving the slope:
        slope = regressor.coef_[0][0]
        
        #To retrieve the residual da regressão:
        #residual = regressor._residues

       
        #regression part with stats.linregress 
        #from scipy import stats                                    
        #slope, intercept, r_value, p_value, std_err = stats.linregress(labels_SVM_CV, labels.T)



        #definir os limites do gráfico de validação cruzada 
        x_min = min(labels_SVM_CV.min(), labels.min()) 
        x_max = max(labels_SVM_CV.max(), labels.max()) 
        
        x_min = x_min - abs(intercept) 
        if x_min < 0: 
            x_min = 0

        x_max = x_max + abs(intercept)
                 
        plt5.close()
        plt5.title(self.tr('Validação Cruzada - SVM') + '   ' + self.tr('RMSE:') + ' ' + str(RMSE_lib) + '   $R^2$ : ' + str(R2_RCV))

        plt5.xlim(x_min, x_max)
        plt5.ylim(x_min, x_max)

        plt5.xlabel(self.tr('Valor Predito')  + ' - ' + self.v_target)
        plt5.ylabel(self.tr('Valor Observado') + ' - ' + self.v_target) 

        plt5.scatter(labels_SVM_CV, labels,     marker = 's'    , color = 'blue')
        plt5.plot( [x_min,x_max],[x_min,x_max], linestyle = ':' , color = 'black')

        labels_SVM_CV = np.append(0, labels_SVM_CV)       #insert 0 na posição 0 do array 
        labels_SVM_CV = np.append(labels_SVM_CV, x_max)   #insert x_max na ultima posição do array 
        
        line = slope * labels_SVM_CV + intercept
        
        #plot Line of Regression                       
        if intercept >= 0:                       
            plt5.plot(labels_SVM_CV, line, color = 'black', label='y={:.3f}x+{:.3f}'.format(slope,intercept))
        else: 
            plt5.plot(labels_SVM_CV, line, color = 'black', label='y={:.3f}x-{:.3f}'.format(slope,abs(intercept)))


        plt5.legend(loc='upper left')       #posição da Lengenda                  
        plt5.legend()

        plt5.ticklabel_format(style='plain', useOffset=False, axis='both') #não exibir coordenadas em notação cientifica 

        #janela do plot exibir as coordenadas em notação decimal. 
        ax = plt5.gca()
        ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)

       
        plt5.savefig(os.path.join(     self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_CV.png'))
        pixmap5 = QPixmap(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_CV.png'))
        self.dlg.label_validacao_cruzada_SVM.show()
        self.dlg.label_validacao_cruzada_SVM.setPixmap(pixmap5)
        
        if self.dlg.checkBox_Qgis_Maps.isChecked(): 
            plt5.show()
   
        progress.close() 

        self.Validacao_Cruzada_SVM  = True 


    def datatable_validacao_cruzada_SVM_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_CV.csv'))



    def label_validacao_cruzada_SVM_clicked(self, value):


        if system != 'Darwin':  #PIL do not is install in MacOS  
        
            if self.Validacao_Cruzada_SVM == True:                
               image = Image.open(os.path.join(self.path_absolute , '1_SVM_' + self.VTarget_FileName + '_CV.png'))
               image.show()

  
            
############################################################    Aba para definir zonas de manejo utilizando cluster  #################################################################
    def load_maps_to_generate_ZM(self):                               


        filenames = os.listdir(os.path.join(self.path_absolute)) # + '/')  
        lista = []
        for filename in filenames: # loop through all the files and folders

            if (('_Grid_Map.kri' in filename) or (('_Grid_Map.svm' in filename))): # check whether the current object is a .kri or .svm file
               lista.append(filename)                    


        self.dlg.datatable_ZM_Maps.setColumnCount(5)
        self.dlg.datatable_ZM_Maps.setRowCount(len(lista))

        #preencher o cabeçalho
        try:                       
 
             cols = [self.tr('Marcar'), 'Z', self.tr('Método'), self.tr('Pontos'), self.tr('Arquivo')] 
             self.dlg.datatable_ZM_Maps.setHorizontalHeaderLabels(cols)
 
             
        except AttributeError: 
 
             #mensagem de retorno ao usuário 
             msg_box = QMessageBox()
             msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
             msg_box.setIcon(QMessageBox.Warning)
             msg_box.setWindowTitle(self.tr('Mensagem'))
             msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
             msg_box.exec_()

  
        for i in range(len(lista)): 
            
            if os.path.isfile(os.path.join(self.path_absolute , lista[i])):  
              
                if '1_Krig_' in lista[i]: 
                    Metodo = 'Ordinary Kriging'
                    start = 7
                else: 
                    Metodo = 'ML-SVM'
                    start = 6

                stop = len(lista[i]) - 9    # -9 por causa do sufixo de: '_Grid_Map.kri'  ou  '_Grid_Map.svm'

                #Z = '1_Krig_'
                #Z = '1_SVM_' 

                Z = lista[i][start:stop]
                
                filename = os.path.join(self.path_absolute , lista[i])
                df_Map = pd.read_csv(filename, sep = ',')
       
                #preencher as linhas da planilha 
                try:                       
                    
                    chkBoxItem = QTableWidgetItem()
                    chkBoxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
                    chkBoxItem.setCheckState(QtCore.Qt.Unchecked)       
                    self.dlg.datatable_ZM_Maps.setItem(i,0,chkBoxItem)           

                    Z = QTableWidgetItem(Z)                                              
                    self.dlg.datatable_ZM_Maps.setItem(i,1, Z)
                    Metodo = QTableWidgetItem(Metodo)                                              
                    self.dlg.datatable_ZM_Maps.setItem(i,2, Metodo)
                    Pontos = QTableWidgetItem(str(len(df_Map)))                                              
                    self.dlg.datatable_ZM_Maps.setItem(i,3, Pontos)
                    filename = QTableWidgetItem(lista[i])                                              
                    self.dlg.datatable_ZM_Maps.setItem(i,4, filename)

        
                except AttributeError: 
        
                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                    msg_box.exec_()
        
        
                self.dlg.datatable_ZM_Maps.resizeColumnsToContents();

                
                self.dlg.datatable_ZM_Maps.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

    
                self.list_rows_Map_ZM = []
                self.list_Z_Map_ZM = []
                self.list_Points_Map_ZM = []

                  
                '''
                data = ['first_row', 'second_row', 'third_row']
                nb_row = len(data)
                nb_col = 2
                
                qTable = self.dockwidget.tableWidget
                qTable.setRowCount(nb_row)
                qTable.setColumnCount(nb_col)
                chkBoxItem = QTableWidgetItem()
                
                for row in range(nb_row):

                    for col in [0]:
                        item = QTableWidgetItem(str(data[row]))
                        qTable.setItem(row,col,item)
                    for col in [1]:
                        chkBoxItem = QTableWidgetItem()
                        chkBoxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
                        chkBoxItem.setCheckState(QtCore.Qt.Unchecked)       
                        qTable.setItem(row,col,chkBoxItem)           
                '''
    

    def datatable_ZM_Maps_checkbox_clicked(self, item):

        if item.checkState() == QtCore.Qt.Checked:  #quando marca o checkbox  

            #print('"%s" Checked' % item.text())
            
            Z_selected = False 

            Z = self.dlg.datatable_ZM_Maps.item(item.row(), 1).text()          #obtem o valor da 2ª coluna da linha selecionada 
            
            '''
            if Z in self.list_Z_Map_ZM: 

                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Variável já foi adicionada para gerar Zonas de Manejo.'))
                msg_box.exec_()
                item.setCheckState(QtCore.Qt.Unchecked)
                Z_selected = True 
            else: 
            '''

            Points_dif = False 

            Points = self.dlg.datatable_ZM_Maps.item(item.row(), 3).text()     #obtem o valor da 4ª coluna da linha selecionada 

            for p in range(len(self.list_Points_Map_ZM)): 
                if Points != self.list_Points_Map_ZM[p]: 
                    Points_dif = True 
            
            if Points_dif == True: 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('O número de pontos de todos os mapas interpolados devem ser igual para gerar Zonas de Manejo.'))
                msg_box.exec_()
                item.setCheckState(QtCore.Qt.Unchecked)
                    
                    
            if ((Z_selected == False) and (Points_dif == False)): 


                if not item.row() in self.list_rows_Map_ZM:

                    self.list_rows_Map_ZM.append(item.row())
                    self.list_Z_Map_ZM.append(Z)

                self.list_Points_Map_ZM.append(Points)
                self.list_rows_Map_ZM.sort() 


        else:
            if item.row() in self.list_rows_Map_ZM:
                self.list_rows_Map_ZM.remove(item.row())

            Z = self.dlg.datatable_ZM_Maps.item(item.row(), 1).text()          #obtem o valor da 2ª coluna da linha selecionada 
            if Z in self.list_Z_Map_ZM:
                self.list_Z_Map_ZM.remove(Z)            

            Points = self.dlg.datatable_ZM_Maps.item(item.row(), 3).text()     #obtem o valor da 4ª coluna da linha selecionada 
            if Points in self.list_Points_Map_ZM:
                self.list_Points_Map_ZM.remove(Points)            


        if len(self.list_rows_Map_ZM) > 0: 
            self.dlg.pushButton_ZM_Add_All_Vars_Selected.setEnabled(True)
        else: 
            self.dlg.pushButton_ZM_Add_All_Vars_Selected.setEnabled(False)



    def func_ZM_Add_Coord(self, filename): 
        
    
        self.dlg.tabWidget_ZM.setCurrentIndex(1) 
    
        self.dlg.comboBox_ZM_var.clear()            
        self.dlg.datatable_ZM.setColumnCount(0)
        self.dlg.datatable_ZM.setRowCount(0)
       
        self.list_cov_ZM        = []   
        self.list_cov_ZM_metodo = []   
        #self.atributos_ZM = ''               

        
        self.df_ZM_Coord = pd.read_csv(filename, sep = ',')

        tot_nan = self.df_ZM_Coord.isnull().sum().sum()
        if tot_nan > 0: 

            
            #self.df_ZM_Coord.dropna(inplace=True)                             #apaga linhas com valores nulos 
            #self.df_ZM_Coord.reset_index(drop = True, inplace=True)           #reset the index without new colum index                
            self.df_ZM_Coord = self.df_ZM_Coord.fillna(self.df.mean())         #preeenche com o valor da média da feature 


        self.df_ZM_Coord = self.df_ZM_Coord.iloc[:,0:2]                        #seleciona a coluna 0  (Coord_X) e coluna 1 (Coord_Y)


        self.ZM_Add_Coord = True 
        self.ZM_Add_Var   = False

        self.Calc_Nr_Ideal_ZM = False                                          #Não calculou o número ideal de ZM's com base no FPI e NCE      
        self.dlg.lineEdit_ZM_FPI.setText('')  
        self.dlg.lineEdit_ZM_NCE.setText('')  

       
        self.dlg.pushButton_ZM_Add_Var.setEnabled(True)

        
        if  len(list(self.df_ZM_Coord.columns.values)) == 2:                   #lista de covariáveis possui X, Y 

            self.dlg.groupBox_ZM_Remove_Var.setEnabled(False)
            self.dlg.pushButton_ZM_Remove_Var.setEnabled(False)
            self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
            self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
            self.dlg.pushButton_ZM_Calcular.setEnabled(False)
            self.dlg.groupBox_ZM_Calcular.setEnabled(False)

        else: 
            
            self.dlg.groupBox_ZM_Remove_Var.setEnabled(True)
            self.dlg.pushButton_ZM_Remove_Var.setEnabled(True)
            self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
            self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
            self.dlg.pushButton_ZM_Calcular.setEnabled(True)
            self.dlg.groupBox_ZM_Calcular.setEnabled(True)


        self.dlg.label_ZM.hide()                        
        self.dlg.label_ZM_FPI_NCE.hide()



    def  func_ZM_Add_Var(self, filename): 
        
        
        self.dlg.tabWidget_ZM.setCurrentIndex(1) 

        df = pd.read_csv(filename, sep = ',')

          
        tot_nan = df.isnull().sum().sum()
        if tot_nan > 0: 

            #df.dropna(inplace=True)                                           #apaga linhas com valores nulos 
            #df.reset_index(drop = True, inplace=True)                         #reset the index without new colum index                   
            df = df.fillna(self.df.mean())                                     #preeenche com o valor da média da feature 

        '''
        if df.columns[2] in self.list_cov_ZM:              #restrição para não adicionar a mesma variável mais de uma vez 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Variável já foi adicionada.'))
            msg_box.exec_()
        '''


        if len(self.df_ZM_Coord) != len(df): 
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg = self.tr('Variável a ser adicionada possui ')  + str(len(df)) + self.tr(' pontos interpolados.')
            msg = msg + '\n' +  self.tr('Tabela de ZM possui ') + str(len(self.df_ZM_Coord)) + self.tr(' pontos interpolados.')
            msg = msg + '\n' +  self.tr('Não é possível adicionar a variável selecionada.') 
            msg = msg + '\n' +  self.tr('Número de pontos interpolados são diferentes.')
            msg_box.setText(msg)
            msg_box.exec_()
            
        else: 
       
            if self.ZM_Add_Var == False:                                       #Não adicionou nenhuma variável  

                self.df_ZM_Var = df.iloc[:,[2]]                                #Terceira coluna (indice 2)

                
            else: 
                
                self.df_ZM_Var = pd.concat([self.df_ZM_Var, df.iloc[:,2]], axis=1)  #concatena a coluna 0 = (Coord_X)  e  coluna 1 = (Coord_Y)  com a terceira coluna (indice 2)


            tot_nan = self.df_ZM_Var.isnull().sum().sum()
            if tot_nan > 0: 
                
                #self.df_ZM_Var.dropna(inplace=True)                           #apaga linhas com valores nulos 
                #self.df_ZM_Var.reset_index(drop = True, inplace=True)         #reset the index without new colum index                        
                self.df_ZM_Var = self.df_ZM_Var.fillna(self.df.mean())         #preeenche com o valor da média da feature 


            self.df_ZM_Var.to_csv(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Vars.csv'), sep=',', index = False, encoding='utf-8')

   
            cols = [] 
            cols.append(df.columns[2])
            self.dlg.comboBox_ZM_var.addItems(cols)     

            self.list_cov_ZM = [self.dlg.comboBox_ZM_var.itemText(i) for i in range(self.dlg.comboBox_ZM_var.count())]        

            if '1_Krig_' in filename: 
                    
                self.list_cov_ZM_metodo.append('Krig_' + df.columns[2])
                    
            elif  '1_SVM_' in filename:    
                    
                self.list_cov_ZM_metodo.append('SVM_' + df.columns[2])

            
            self.dlg.datatable_ZM.setColumnCount( len(self.df_ZM_Var.columns) )
            self.dlg.datatable_ZM.setRowCount( len(self.df_ZM_Var.index) )
        
            #preencher o cabeçalho
            try:                       
                cols = [] 
                cols = list(self.df_ZM_Var.columns.values)
            
                self.dlg.datatable_ZM.setHorizontalHeaderLabels(cols)

            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
                

            maximum = len(self.df_ZM_Var.index)
            progress = QProgressDialog(self.tr('Adicionando variável para gerar Zonas de Manejo.') + ' ' + df.columns[2] + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(0.1)


            #preencher as linhas da planilha 
            cont = 1
            try:                       
                for i in range(len(self.df_ZM_Var.index)):  #linhas 

                    valor = self.df_ZM_Var.iloc[i,len(self.df_ZM_Var.columns)-1]

                    if valor.dtype == "float64": 
                        valor = '%.3f' % valor                       
                
                    valor = QTableWidgetItem(str(valor))                  
                    self.dlg.datatable_ZM.setItem(i,len(self.df_ZM_Var.columns)-1, valor)
                    cont = cont + 1 
                    progress.setValue(cont)                        
                    if progress.wasCanceled():                          
                       progress.close() 
                       return 

                        
            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()


            self.dlg.datatable_ZM.resizeColumnsToContents();

            self.dlg.datatable_ZM.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

            self.ZM_Add_Var = True 
            
            self.Calc_Nr_Ideal_ZM = False   #Não calculou o número ideal de ZM's com base no FPI e NCE      
            self.dlg.lineEdit_ZM_FPI.setText('')  
            self.dlg.lineEdit_ZM_NCE.setText('')  
            

            self.dlg.groupBox_ZM_Remove_Var.setEnabled(True)
            self.dlg.pushButton_ZM_Remove_Var.setEnabled(True)
            self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
            self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
            self.dlg.pushButton_ZM_Calcular.setEnabled(True)
            self.dlg.groupBox_ZM_Calcular.setEnabled(True)

            self.dlg.datatable_ZM_Classe.setColumnCount(0)
            self.dlg.datatable_ZM_Classe.setRowCount(0)       

            self.dlg.label_ZM.hide()                                
            self.dlg.label_ZM_FPI_NCE.hide()

            progress.close() 
            #self.dlg.datatable_MP.setColumnCount(0)
            #self.dlg.datatable_MP.setRowCount(0)


    def  pushButton_ZM_Add_Var_clicked(self):    #Adicionar Variaveis para zonas de manejo utilizando cluster. 


        #"CSV files (1_*_Grid_Map.csv)"
        #"KRIG files (*.kri);;SVM files (*.svm)"
        filename  = QFileDialog.getOpenFileName(self.dlg, self.tr('Abrir Arquivo'),  os.path.join(self.path_absolute) , "Interpolated files (*.kri;*.svm)")
   
        if filename[0] != '': 

            if self.ZM_Add_Coord == False: 

                 self.func_ZM_Add_Coord(filename[0])

            self.func_ZM_Add_Var(filename[0])     


    def  pushButton_ZM_Add_All_Vars_Selected_clicked(self): #Adicionar todas as variaveis selecionadas para gerar as Zonas de Manejo

        if len(self.list_rows_Map_ZM) > 0:  

            for i in range(len(self.list_rows_Map_ZM)): 
            
                row = self.list_rows_Map_ZM[i] 
                filename = os.path.join(self.path_absolute , self.dlg.datatable_ZM_Maps.item(row, 4).text())  #obtem o valor da 5ª coluna da linha selecionada 
                if i == 0: #first variable to add -> add coord 
                    self.func_ZM_Add_Coord(filename)
                self.func_ZM_Add_Var(filename)     

                    

    def  pushButton_ZM_Remove_Var_clicked(self):     #Remover Variaveis para zonas de manejo utilizando cluster. 



        
        if  len(self.list_cov_ZM) == 0:
            
            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Todas as variáveis foram removidas.'))
            msg_box.exec_() 
  
        else: 
            
            id_col =  self.dlg.comboBox_ZM_var.currentIndex()                                 #obtem o índice da coluna a ser excluída 

            if id_col >= 0: 

                self.dlg.tabWidget_ZM.setCurrentIndex(1) 

                list_cov_ZM_Index = [i for i in range(self.dlg.comboBox_ZM_var.count())]     #lista de indice 
                list_cov_ZM_Index.remove(id_col)
    
                del self.list_cov_ZM_metodo[id_col]                                          #remove elemento de indice id_col 
                
                #self.df_ZM_Var.drop(self.df_ZM_Var.columns[[id_col]], axis=1, inplace=True) #se existir variavel repetida apaga as repetições e não apenas o índice da coluna  
                self.df_ZM_Var = self.df_ZM_Var.iloc[:, list_cov_ZM_Index]
    
                self.df_ZM_Var.to_csv(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Vars.csv'), sep=',', index = False, encoding='utf-8')

    
                self.dlg.comboBox_ZM_var.removeItem(id_col)     
                
                self.list_cov_ZM = [self.dlg.comboBox_ZM_var.itemText(i) for i in range(self.dlg.comboBox_ZM_var.count())]  
                
                self.dlg.datatable_ZM.removeColumn(id_col)            
                
                self.dlg.datatable_ZM.resizeColumnsToContents();
        
                self.dlg.datatable_ZM.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable
    
                if  len(self.list_cov_ZM) == 0:  
                    
                    self.ZM_Add_Var = False 
                    self.dlg.groupBox_ZM_Remove_Var.setEnabled(False)
                    self.dlg.pushButton_ZM_Remove_Var.setEnabled(False)
                    self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
                    self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(False)
                    self.dlg.pushButton_ZM_Calcular.setEnabled(False)
                    self.dlg.groupBox_ZM_Calcular.setEnabled(False)
                    self.dlg.datatable_ZM.setColumnCount(0)
                    self.dlg.datatable_ZM.setRowCount(0)       
        
                else: 
                    
                    self.dlg.groupBox_ZM_Remove_Var.setEnabled(True)
                    self.dlg.pushButton_ZM_Remove_Var.setEnabled(True)
                    self.dlg.groupBox_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
                    self.dlg.pushButton_ZM_Calc_Nr_Ideal_ZM.setEnabled(True)
                    self.dlg.pushButton_ZM_Calcular.setEnabled(True)
                    self.dlg.groupBox_ZM_Calcular.setEnabled(True)
    
    
                self.Calc_Nr_Ideal_ZM = False                                  #Não calculou o número ideal de ZM's com base no FPI e NCE      
                self.dlg.lineEdit_ZM_FPI.setText('')  
                self.dlg.lineEdit_ZM_NCE.setText('')  
    
                self.dlg.datatable_ZM_Classe.setColumnCount(0)
                self.dlg.datatable_ZM_Classe.setRowCount(0)       

                self.dlg.label_ZM.hide()                            
                self.dlg.label_ZM_FPI_NCE.hide()
    
                #self.dlg.datatable_MP.setColumnCount(0)
                #self.dlg.datatable_MP.setRowCount(0)

            else:     

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('As Coordenadas (x, y) não podem ser removidas.'))
                msg_box.exec_()              



    def datatable_ZM_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Vars.csv'))



    def  pushButton_ZM_Calc_Nr_Ideal_ZM_clicked(self):    #definir número ideal de Zonas de Manejo com base no FPI e NCE        


        if self.ZM_Add_Var == False:  

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Variável(is) deve(m) ser adicionadas para gerar Zonas de Manejo.'))
            msg_box.exec_()               
        
        else: 

            self.dlg.label_ZM_FPI_NCE.hide()
            self.dlg.tabWidget_ZM.setCurrentIndex(2)             
                        
            num_iteration =  self.dlg.spinBox_ZM_Iter.value()            #definir o número máximo de iterações  no Fuzzy K-Means
            coef_nebuloso =  self.dlg.doubleSpinBox_ZM_CFuzzy.value()    #definir o valor do coeficiente nebuloso
    
      
            #executar o fuzzy KMeans para um número de agrupamentos variando entre 2 e 10. 
            
            # vamos definir o valor do expoente nebuloso como sendo 1.25, esse
            # número deve ser maior que um e menor que infinito
            #m=coef_nebuloso

            # vamos criar três blobs (bolhas), que darão origem a três classes,
            # K define o número de classes
            #K=3

            # vamos estabelecer um número máximo de 100 iterações, n_int define
            # o número máximo de iterações
            #n_int=num_iteration

            # vamos definir a tolerância para convergência da função de minimização, 
            # tol define a tolerância
            tol=1.0E-5

            #self.df_ZM = pd.concat([self.df_ZM_Coord, self.df_ZM_Var], axis=1) 
            self.df_ZM = pd.concat([self.df_ZM_Var], axis=1) 

            tot_nan = self.df_ZM.isnull().sum().sum()
                
            if tot_nan > 0: 
                
                self.df_ZM.dropna(inplace=True)                                            #drop lines with null values  
                self.df_ZM.reset_index(drop = True, inplace=True)                          #reset the index without create new colum index


            # vamos definir o banco de dados            
            X = np.copy(self.df_ZM)  #X[7860,5]  7860 linhas por 5 colunas (coordx, coordy, +3 atributos)
            X = X.T                  #X[5,7860]
            X = scale(X, axis=1, with_mean=True, with_std=True, copy=True)     #padroniza por linha (axis=1)
       
            
            self.NK =[]    #lista para armazenar o número de classes
            
            self.FPI = []  #lista para armazenar os valores do Indice de Performance Fuzzy -> calculo Daniel Marçal
    
            self.NCE = []  #lista para armazenar os valores da Entropia de Classificação Normalizada -> calculo Daniel Marçal
    
            #FPC = [] #lista para armazenar os valores do Indice de Performance Fuzzy -> calculo biblioteca scikit-fuzzy

            maximum = 10
            progress = QProgressDialog(self.tr('Calculando número ideal de Zonas de Manejo.') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(0.1)

    
            '''
            #code Daniel Marçal para calcular fpi, nce 
            ii=1
            for nclasses in range(2,11):
                self.dlg.label_etapa_ZM.setText('Calculando FPI/NCE para determinar numero ideal de Zonas de Manejo... Numero de Classes: ' + str(nclasses) )  
                fpi, nce, U, MI, Jplot, classe = functions.fuzzKMeans(m, nclasses, n_int, tol, X)
                FPI.append(fpi)
                NCE.append(nce)
                NK.append(nclasses)
                ii=ii+1
                self.dlg.progressBar_ZM.setValue(ii)    
            '''
                      
            for nclasses in range(2,11):
            
                #cntr, u_orig, _, _, _, _, fpc = fuzz.cluster.cmeans(X, c=nclasses, m=coef_nebuloso, error=tol, maxiter=num_iteration)   #libray scikit-fuzzy  (when import all library)          
                cntr, u_orig, _, _, _, _, fpc = _cmeans.cmeans(X, c=nclasses, m=coef_nebuloso, error=tol, maxiter=num_iteration)         #libray scikit-fuzzy                
                
                
                #calculo de FPI e NCE -> Daniel Marçal                 
                u_orig = u_orig.T  #u_orig [2,7860]   #2 classes, 7860 amostras  , #u_orig.T [7860,2]
                N,NF = np.shape(X.T) #X[2,7860],   X.T [7860, 2],  N = nr. de linhas e NF = nr. de colunas 
                
                K = nclasses
                sum1=0
                sum2=0
                # inicia o loop do objeto
                for i in range(N):
                    # incia o loop das classes
                    for j in range(K):
                        # atualiza os somatórios
                        sum1=sum1+u_orig[i,j]*u_orig[i,j] 
                        sum2=sum2+u_orig[i,j]*math.log(u_orig[i,j])
                # calcula o valor do FPI
                fpi=1-(K*((1/N)*sum1)-1)/(K-1)
                # calcula o valor de NCE
                nce=(-1/N)*sum2/math.log(K)


                self.FPI.append(fpi)
                self.NCE.append(nce)
                #FPC.append(fpc)
                self.NK.append(nclasses)
                #if(nclasses % 2 == 0): time.sleep(0.005)
                progress.setValue(nclasses)                        
                if progress.wasCanceled():                          
                   progress.close() 
                   return 
                
 
            
            #determinando o número de classes ideal de acordo com o FPC             
            #nFPC = FPC.index(min(FPC))  #retorna a posição onde está o valor mínimo de FPC         

            #determinando o número de classes ideal de acordo com o FPI             
            nFPI = self.FPI.index(min(self.FPI))  #retorna a posição onde está o valor mínimo de FPI  , FPI = [0.78, 0.80], nFPI = 0        
            
            nNCE = self.NCE.index(min(self.NCE))  #retorna a posição onde está o valor mínimo de NCE  , NCE = [0.99, 0.79], nNCE = 1        

            #index  0  1  2  3  4  5  6  7  8
            #NK =  [2, 3, 4, 5, 6, 7, 8, 9, 10]
            
            num_zones = min(self.NK[nFPI], self.NK[nNCE]) #EX: NK[nFPI] = NK[0] = 2 , NK[nNCE] = NK[1] = 3 -> min(2, 3)  -> num_zones = 2

            nK = self.NK.index(num_zones)   #num_zones = 2, NK.index(2)  ->  nk = 0
            
            #self.fpi = '%.3f' % FPI[nFPI]   
            self.fpi  = '%.3f' % self.FPI[nK]      
            self.dlg.lineEdit_ZM_FPI.setText(str(self.fpi))  
    
                
            #self.nce = '%.3f' % NCE[nNCE]   
            self.nce  = '%.3f' % self.NCE[nK]               
            self.dlg.lineEdit_ZM_NCE.setText(str(self.nce))  
            
          
            try: 
                self.dlg.spinBox_ZM_NrZonas.valueChanged.disconnect()
            except TypeError:
                pass  # Ignore the error if no connections exist               
                

            self.dlg.spinBox_ZM_NrZonas.setValue(num_zones)
    
            self.dlg.spinBox_ZM_NrZonas.valueChanged.connect(self.spinBox_ZM_NrZonas_changed)                               
    
            #grafico de FPI x número de classes            
            plt6.close()
            plt6.title( self.tr('Número de Classes') + ': ' +  str(num_zones) + '   FPI: ' + str(self.fpi) + '   NCE: ' + str(self.nce))
            plt6.xlabel(self.tr('Número de Classes'))
            plt6.ylabel('FPI / NCE')
            plt6.plot( self.NK, self.FPI, marker = '*', label='FPI')
            plt6.plot( self.NK, self.NCE, marker = '+', label='NCE')
            #plt6.plot(NK, FPC, marker='.',label='FPC')
    
            plt6.legend()    
    
            plt6.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)

            plt6.ticklabel_format(style='plain', useOffset=False, axis='both') #não exibir coordenadas em notação cientifica 

            #janela do plot exibir as coordenadas em notação decimal. 
            ax = plt6.gca()
            ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)

      
            plt6.savefig(     os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_FPI_NCE.png'))
            pixmap6 = QPixmap(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_FPI_NCE.png'))
            self.dlg.label_ZM_FPI_NCE.show()
            self.dlg.label_ZM_FPI_NCE.setPixmap(pixmap6)
            
            if self.dlg.checkBox_Qgis_Maps.isChecked(): 
                plt6.show()
  
            self.Calc_Nr_Ideal_ZM = True 

            self.dlg.datatable_ZM_Classe.setColumnCount(0)
            self.dlg.datatable_ZM_Classe.setRowCount(0)       


            self.dlg.label_ZM.hide()

            progress.close()                 

            #self.dlg.datatable_MP.setColumnCount(0)
            #self.dlg.datatable_MP.setRowCount(0)


    def spinBox_ZM_NrZonas_changed(self):

        #index  0  1  2  3  4  5  6  7  8
        #NK =  [2, 3, 4, 5, 6, 7, 8, 9, 10]   (num_zones)

        if  self.Calc_Nr_Ideal_ZM == True:  #usuário calculou nr. ideal de ZM com base no FPI e NCE  

            num_zones = self.dlg.spinBox_ZM_NrZonas.value()

            self.fpi  = '%.3f' % self.FPI[num_zones-2]      
            self.dlg.lineEdit_ZM_FPI.setText(str(self.fpi))  
                   
            self.nce  = '%.3f' % self.NCE[num_zones-2]               
            self.dlg.lineEdit_ZM_NCE.setText(str(self.nce))  
                     
            
            

    def label_ZM_FPI_NCE_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  
 
            
            if  self.Calc_Nr_Ideal_ZM == True:                
               image = Image.open(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_FPI_NCE.png'))
               image.show()



    def  pushButton_ZM_Calcular_clicked(self):    #Definir as zonas de manejo utilizando cluster. 


        if self.ZM_Add_Var == False:  

            #mensagem de retorno ao usuário 
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
            msg_box.setIcon(QMessageBox.Warning)
            msg_box.setWindowTitle(self.tr('Mensagem'))
            msg_box.setText(self.tr('Variável(is) deve(m) ser adicionadas para gerar Zonas de Manejo.'))
            msg_box.exec_()               

        else: 
            
            num_iteration =  self.dlg.spinBox_ZM_Iter.value()                  #numero de iteraçoes
            num_zones     =  self.dlg.spinBox_ZM_NrZonas.value()               #numero de classes de zonas de manejos
            coef_nebuloso =  self.dlg.doubleSpinBox_ZM_CFuzzy.value()          #coeficiente de performance fuzzy
            
            #definir a tolerancia para a função objetivo 
            tol = 1.0E-5


           
            #self.atributos_ZM = ''

            self.df_ZM = pd.concat([self.df_ZM_Coord, self.df_ZM_Var], axis=1) 

            tot_nan = self.df_ZM.isnull().sum().sum()
                
            if tot_nan > 0: 
                
                self.df_ZM.dropna(inplace=True)                                            #drop lines with null values  
                self.df_ZM.reset_index(drop = True, inplace=True)                          #reset the index without create new colum index

            
            '''
            for i in range(len(self.list_cov_ZM_metodo)):  
    
                if 'SVM' in self.list_cov_ZM_metodo[i]: 
 
                    if 'SVM' not in  self.atributos_ZM: 

                        self.atributos_ZM = self.atributos_ZM + 'SVM_'              

                elif 'Krig' in self.list_cov_ZM_metodo[i]: 

                    if 'Krig' not in  self.atributos_ZM: 

                        self.atributos_ZM = self.atributos_ZM + 'Krig_'              
                    
            '''
            
            
            data = np.array(self.df_ZM, dtype=float)

            X = np.copy(data[:, [0, 1]])   #pega todos os dados da matriz coluna 0 (Coord_X) e coluna 1 (Coord_Y)
                       
            
            if len(self.df_ZM.columns) == 3:                                   #só possui um atributo 
               z = np.copy(data[:, [2]])                                       #pega todos os dados da matriz coluna 2 
               alldata = np.vstack((z[:,0], z[:,0]))                           #repete a coluna para ficar um vetor 2D 
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2]
             
            elif len(self.df_ZM.columns) == 4:                                 #possui dois atributo  
               z = np.copy(data[:, [2,3]])                                     #pega todos os dados da matriz coluna 2 e 3
               alldata = np.vstack((z[:,0], z[:,1]))   
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3]               
            
            elif len(self.df_ZM.columns) == 5:                                 #possui tres atributos 
               z = np.copy(data[:, [2,3,4]])                                   #pega todos os dados da matriz coluna 2, 3, 4
               alldata = np.vstack((z[:,0], z[:,1], z[:,2]))   
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4]              
             
            elif len(self.df_ZM.columns) == 6:                                 #possui 4 atributos 
               z = np.copy(data[:, [2,3,4,5]])                                 #pega todos os dados da matriz coluna 2, 3, 4, 5
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5]                           
             
            elif len(self.df_ZM.columns) == 7:                                 #possui 5 atributos 
               z = np.copy(data[:, [2,3,4,5,6]])                               #pega todos os dados da matriz coluna 2, 3, 4, 5, 6
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6]              
             
            elif len(self.df_ZM.columns) == 8:                                 #possui 6 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7]])                             #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7]              
              
            elif len(self.df_ZM.columns) == 9:                                 #possui 7 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8]])                           #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8]              
              
            elif len(self.df_ZM.columns) == 10:                                #possui 8 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9]])                         #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 9
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9]             
               
            elif len(self.df_ZM.columns) == 11:                                #possui 9 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10]])                      #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10]             
               
            elif len(self.df_ZM.columns) == 12:                                #possui 10 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11]])                   #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11]
               
            elif len(self.df_ZM.columns) == 13:                                #possui 11 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12]])                #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12]

            elif len(self.df_ZM.columns) == 14:                                #possui 12 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13]])             #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13]

            elif len(self.df_ZM.columns) == 15:                                #possui 13 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14]])          #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14]

            elif len(self.df_ZM.columns) == 16:                                #possui 14 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15]])       #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15]

            elif len(self.df_ZM.columns) == 17:                                #possui 15 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]])    #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16]

            elif len(self.df_ZM.columns) == 18:                                #possui 16 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]]) #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14], z[:,15]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16] + '_' + self.df_ZM.columns[17]

            elif len(self.df_ZM.columns) == 19:                                    #possui 17 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]])  #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14], z[:,15], z[:,16]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16] + '_' + self.df_ZM.columns[17] + '_' + self.df_ZM.columns[18]

            elif len(self.df_ZM.columns) == 20:                                      #possui 18 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]]) #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14], z[:,15], z[:,16], z[:,17]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16] + '_' + self.df_ZM.columns[17] + '_' + self.df_ZM.columns[18] + '_' + self.df_ZM.columns[19]

            elif len(self.df_ZM.columns) == 21:                                         #possui 19 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]]) #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14], z[:,15], z[:,16], z[:,17], z[:,18]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16] + '_' + self.df_ZM.columns[17] + '_' + self.df_ZM.columns[18] + '_' + self.df_ZM.columns[19] + '_' + self.df_ZM.columns[20]

            elif len(self.df_ZM.columns) == 22:                                            #possui 20 atributos 
               z = np.copy(data[:, [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]]) #pega todos os dados da matriz coluna 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 
               alldata = np.vstack((z[:,0], z[:,1], z[:,2], z[:,3], z[:,4], z[:,5], z[:,6], z[:,7], z[:,8], z[:,9], z[:,10], z[:,11], z[:,12], z[:,13], z[:,14], z[:,15], z[:,16], z[:,17], z[:,18], z[:,19]))            
               #self.atributos_ZM = self.atributos_ZM + self.df_ZM.columns[2] + '_' + self.df_ZM.columns[3] + '_' + self.df_ZM.columns[4] + '_' + self.df_ZM.columns[5] + '_' + self.df_ZM.columns[6] + '_' + self.df_ZM.columns[7] + '_' + self.df_ZM.columns[8] + '_' + self.df_ZM.columns[9] + '_' + self.df_ZM.columns[10] + '_' + self.df_ZM.columns[11] + '_' + self.df_ZM.columns[12] + '_' + self.df_ZM.columns[13] + '_' + self.df_ZM.columns[14] + '_' + self.df_ZM.columns[15] + '_' + self.df_ZM.columns[16] + '_' + self.df_ZM.columns[17] + '_' + self.df_ZM.columns[18] + '_' + self.df_ZM.columns[19] + '_' + self.df_ZM.columns[20] + '_' + self.df_ZM.columns[21]

            else: 
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Número Máximo de classes excedido.'))
                msg_box.exec_()               
                

            '''
            for ch in [' ', ')', '(', 'á', '?', '/', 'é', '.', 'í', 'ú', '-']:
                if ch in self.atributos_ZM:
                    self.atributos_ZM = self.atributos_ZM.replace(ch,"_")
            '''
     
            if self.dlg.checkBox_ZM_Normalizar.isChecked():  
                alldata = scale(alldata, axis=1, with_mean=True, with_std=True, copy=True)       #padroniza os dados por linha (axis=1)
                                                                                                 #alldata [3, 7860] = 3 atributos, 7860 amostras
            
            #cntr, u_orig, _, _, _, _, fpi = fuzz.cluster.cmeans(alldata, c=num_zones, m=coef_nebuloso, error=tol, maxiter=num_iteration)  #(when import all library)
            cntr, u_orig, _, _, _, _, fpi = _cmeans.cmeans(alldata, c=num_zones, m=coef_nebuloso, error=tol, maxiter=num_iteration)

            #cntr   ->  centroides das zonas de manejo
            #u_orig ->  matriz de pertinencia com os valores de cada classe para cada ponto amostrado ou interpolado 
            #cluster_membership >- maior valor do centroide, definindo a classe 
            #fpc   -> coeficiente (indice) de performance fuzzy
            
            cluster_membership = np.argmax(u_orig, axis=0)  #maior valor de cada coluna: u_orig [2, 7860] = 2 classes, 7860 amostras
                          
            cluster_membership = cluster_membership + 1     #adicinar 1 para fazer classe começar em 1
            
            #salvando o arquivo .cla  (arquivo que contem a coordenada X, Y, e a classe a qual pertence o ponto)    X, Y, Classe             
            lista = []
            
            for i in range(len(X)):
                lista.append([X[i,0], X[i,1], cluster_membership[i]])
                
                
            lista = np.array(lista)             
            
            lista_CoordX = list(set(lista[:,0]))  #get distincit elements of list 
            lista_CoordY = list(set(lista[:,1]))  #get distincit elements of list 

            lista_CoordX.sort()
            lista_CoordY.sort()

            self.Pixel_Size_X_ZM = int(lista_CoordX[1] - lista_CoordX[0])
            self.Pixel_Size_Y_ZM = int(lista_CoordY[1] - lista_CoordY[0])
            
            
            df_ZM_Classe = pd.DataFrame(np.atleast_2d(lista), columns=['CoordX_SM', 'CoordY_SM', 'Classe'])
            #cria uma coluna a partir do índice do dataframe
            #id_index = df_ZM_Classe.index.values
            #df_ZM_Classe.insert( 0, column="ID",value = id_index+1)
            df_ZM_Classe.to_csv(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.csv'), sep=',', index = False, encoding='utf-8')


            maximum = ( len(df_ZM_Classe.index) * len(df_ZM_Classe.columns) ) 
            progress = QProgressDialog(self.tr('Gerando Zonas de Manejo.') + '...', self.tr('Cancelar'),  1, maximum, self.dlg)
            progress.setWindowTitle('Smart-Map')
            progress.show() 
            progress.setCancelButton(None)                                     #remove button cancel 
            #progress.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)    #disable button 'X' 
            progress.setWindowModality(QtCore.Qt.WindowModal)                  #modal for parent form 
            #progress.setWindowModality(QtCore.Qt.ApplicationModal)            #modal for application 
            time.sleep(0.1)

      
            self.dlg.datatable_ZM_Classe.setColumnCount(len(df_ZM_Classe.columns))
            self.dlg.datatable_ZM_Classe.setRowCount(len(df_ZM_Classe.index))
            
            #preencher o cabeçalho
            try:                       
    
                cols = [] 
                cols = list(df_ZM_Classe.columns.values)  
                cols[2] = '   ' + self.tr('Classe') + '   '   
                   
                self.dlg.datatable_ZM_Classe.setHorizontalHeaderLabels(cols)
    
            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
                
           
            #preencher as linhas da planilha 
            cont = 1 
            try:                       
                for i in range(len(df_ZM_Classe.index)):           #linhas 
                    for j in range(len(df_ZM_Classe.columns)):     #colunas 

                        valor = df_ZM_Classe.iloc[i,j]
                        if j == 2: #coluna: Classe
                            valor = round(valor)                        
                        elif valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                                                    
                        valor = QTableWidgetItem(str(valor))                  
                        self.dlg.datatable_ZM_Classe.setItem(i,j, valor)
                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 

            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setWindowIcon(QtGui.QIcon(self.icon_path))        
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()

    
            #self.dlg.datatable_ZM_Classe.removeColumn(0)  #remove coluna ID da interface do usuário             

            self.dlg.datatable_ZM_Classe.resizeColumnsToContents()

            self.dlg.datatable_ZM_Classe.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

            
            u_orig = u_orig.T  #u_orig [2,7860]     #2 classes, 7860 amostras  , #u_orig.T [7860,2]

            if self.Calc_Nr_Ideal_ZM == True:      

                num_zones = self.dlg.spinBox_ZM_NrZonas.value()
    
                self.fpi  = '%.3f' % self.FPI[num_zones-2]      
                self.dlg.lineEdit_ZM_FPI.setText(str(self.fpi))  
                       
                self.nce  = '%.3f' % self.NCE[num_zones-2]               
                self.dlg.lineEdit_ZM_NCE.setText(str(self.nce))  


            else:    #NÃO calculou nr. ideal de ZM 

                #calculo de FPI e NCE -> Daniel Marçal                 
                N,NF = np.shape(alldata.T) #alldata[2,7860],   alldata.T [7860, 2],  N = nr. de linhas e NF = nr. de colunas 
                
                K = num_zones
                sum1=0
                sum2=0
                # inicia o loop do objeto
                for i in range(N):
                    # incia o loop das classes
                    for j in range(K):
                        # atualiza os somatórios
                        sum1=sum1+u_orig[i,j]*u_orig[i,j] 
                        sum2=sum2+u_orig[i,j]*math.log(u_orig[i,j])

                # calcula o valor do FPI
                fpi=1-(K*((1/N)*sum1)-1)/(K-1)
                # calcula o valor de NCE
                nce=(-1/N)*sum2/math.log(K)
        
                  
                self.fpi = '%.3f' % fpi
                self.dlg.lineEdit_ZM_FPI.setText(str(self.fpi))  
            
               
                self.nce = '%.3f' % nce   
                self.dlg.lineEdit_ZM_NCE.setText(str(self.nce))  


            #gerar matriz de pertinencia. (arquivo que contem a coordenada X, Y, e os valores de todos os pontos das classes)    X, Y, Classe1, Classe2, Classe3, ......              
            lista = []


            for i in range(len(u_orig)):

                if num_zones   == 1:                                   # possui 1 atributo 
                  lista.append([X[i,0], X[i,1], u_orig[i,0]])            
                  classes = ['1']
                elif num_zones == 2:                                   # possui 2 atributo  
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1]])            
                  classes = ['1', '2']
                elif num_zones == 3:                                  # possui 3 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2]])            
                  classes = ['1', '2', '3']
                elif num_zones == 4:                                  # possui 4 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3]])            
                  classes = ['1', '2', '3', '4']
                elif num_zones == 5:                                  # possui 5 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4]])            
                  classes = ['1', '2', '3', '4', '5']
                elif num_zones == 6:                                  # possui 6 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5]])
                  classes = ['1', '2', '3', '4', '5', '6']
                elif num_zones == 7:                                  # possui 7 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6]])
                  classes = ['1', '2', '3', '4', '5', '6', '7']
                elif num_zones == 8:                                  # possui 8 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8']
                elif num_zones == 9:                                  # possui 9 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
                elif num_zones == 10:                                  # possui 10 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
                elif num_zones == 11:                                  # possui 11 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
                elif num_zones == 12:                                  # possui 12 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
                elif num_zones == 13:                                  # possui 13 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13']
                elif num_zones == 14:                                  # possui 14 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14']
                elif num_zones == 15:                                  # possui 15 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
                elif num_zones == 16:                                  # possui 16 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14], u_orig[i,15]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16']
                elif num_zones == 17:                                  # possui 17 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14], u_orig[i,15], u_orig[i,16]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17']
                elif num_zones == 18:                                  # possui 18 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14], u_orig[i,15], u_orig[i,16], u_orig[i,17]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18']
                elif num_zones == 19:                                  # possui 19 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14], u_orig[i,15], u_orig[i,16], u_orig[i,17], u_orig[i,18]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19']
                elif num_zones == 20:                                  # possui 20 atributos 
                  lista.append([X[i,0], X[i,1], u_orig[i,0], u_orig[i,1], u_orig[i,2], u_orig[i,3], u_orig[i,4], u_orig[i,5], u_orig[i,6], u_orig[i,7], u_orig[i,8], u_orig[i,9], u_orig[i,10], u_orig[i,11], u_orig[i,12], u_orig[i,13], u_orig[i,14], u_orig[i,15], u_orig[i,16], u_orig[i,17], u_orig[i,18], u_orig[i,19]])
                  classes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20']
                else: 
                    #mensagem de retorno ao usuário 
                    msg_box = QMessageBox()
                    msg_box.setIcon(QMessageBox.Warning)
                    msg_box.setWindowTitle(self.tr('Mensagem'))
                    msg_box.setText(self.tr('Número Máximo de classes excedido.'))
                    msg_box.exec_()               


            self.Cord_X   =  'CoordX_SM' #self.dlg.comboBox_CordX.currentText()  
            self.Cord_Y   =  'CoordY_SM' #self.dlg.comboBox_CordY.currentText() 

            if num_zones   == 1:                                  #só possui 1 atributo 
              lista = np.array(lista)  
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1'])
              
            elif num_zones == 2:                                   # possui 2 atributo  
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2'])

            elif num_zones == 3:                                  # possui 3 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3'])

            elif num_zones == 4:                                  # possui 4 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4'])

            elif num_zones == 5:                                  # possui 5 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5'])

            elif num_zones == 6:                                  # possui 6 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6'])

            elif num_zones == 7:                                  # possui 7 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7'])

            elif num_zones == 8:                                  # possui 8 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8'])

            elif num_zones == 9:                                  # possui 9 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9'])

            elif num_zones == 10:                                 # possui 10 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10'])

            elif num_zones == 11:                                 # possui 11 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11'])

            elif num_zones == 12:                                 # possui 12 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12'])

            elif num_zones == 13:                                 # possui 13 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13'])

            elif num_zones == 14:                                 # possui 14 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14'])

            elif num_zones == 15:                                 # possui 15 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15'])

            elif num_zones == 16:                                 # possui 16 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15', 'Cls16'])

            elif num_zones == 17:                                 # possui 17 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15', 'Cls16', 'Cls17'])

            elif num_zones == 18:                                 # possui 18 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15', 'Cls16', 'Cls17', 'Cls18'])

            elif num_zones == 19:                                 # possui 19 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15', 'Cls16', 'Cls17', 'Cls18', 'Cls19'])

            elif num_zones == 20:                                 # possui 20 atributos 
              lista = np.array(lista)             
              df_MP = pd.DataFrame(np.atleast_2d(lista), columns=[self.Cord_X, self.Cord_Y, 'Cls1', 'Cls2', 'Cls3', 'Cls4', 'Cls5', 'Cls6', 'Cls7', 'Cls8', 'Cls9', 'Cls10', 'Cls11', 'Cls12', 'Cls13', 'Cls14', 'Cls15', 'Cls16', 'Cls17', 'Cls18', 'Cls19', 'Cls20'])

            else: 
                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Número Máximo de classes excedido.'))
                msg_box.exec_()               

             

            #cria uma coluna a partir do índice do dataframe
            #id_index = df_MP.index.values
            #df_MP.insert( 0, column="ID",value = id_index+1)
            df_MP.to_csv(os.path.join(self.path_absolute , '2_ZM' + '_' + self.VTarget_FileName + '_MP.csv'), sep=',', index = False, encoding='utf-8')


            '''
            #Carregar Matriz de pertinência 
            self.dlg.label_etapa_ZM.setText(self.tr('Gerando Matriz de Pertinência.') + '...')  
            self.dlg.progressBar_ZM.setMinimum(1)     
            self.dlg.progressBar_ZM.setMaximum( len(df_MP.index) * len(df_MP.columns) )


            self.dlg.datatable_MP.setColumnCount(len(df_MP.columns))
            self.dlg.datatable_MP.setRowCount(len(df_MP.index))
        
            #preencher o cabeçalho
            try:                       
                cols = [] 
                cols = list(df_MP.columns.values)
            
                self.dlg.datatable_MP.setHorizontalHeaderLabels(cols)

            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()
                
                
            #preencher as linhas da planilha 
            cont = 1     
            try:                       
                for i in range(len(df_MP.index)):         #linhas 
                    for j in range(len(df_MP.columns)):   #colunas 
                        valor = df_MP.iloc[i,j]

                        if valor.dtype == "float64": 
                            valor = '%.3f' % valor                       
                    
                        valor = QTableWidgetItem(str(valor))                  
                        self.dlg.datatable_MP.setItem(i,j, valor)
                        cont = cont + 1 
                        self.dlg.progressBar_ZM.setValue(cont)   

            except AttributeError: 

                #mensagem de retorno ao usuário 
                msg_box = QMessageBox()
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setWindowTitle(self.tr('Mensagem'))
                msg_box.setText(self.tr('Erro ao carregar tabela. Valor Inválido!'))
                msg_box.exec_()

   
            #self.dlg.datatable_MP.removeColumn(0)  #remove coluna ID da interface do usuário             

            self.dlg.datatable_MP.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers) #read-only para as celulas do datatable

        
                       
            self.dlg.tabWidget_ZM.setCurrentIndex(2)          
            '''


            self.df_ZM.to_csv(os.path.join(self.path_absolute , '2_ZM' + '_' + self.VTarget_FileName + '_Vars.csv'), sep=',', index = False, encoding='utf-8')




            Cord_X_min_ZM = self.df_ZM['CoordX_SM'].min() 
            Cord_Y_min_ZM = self.df_ZM['CoordY_SM'].min() 
            Cord_X_max_ZM = self.df_ZM['CoordX_SM'].max() 
            Cord_Y_max_ZM = self.df_ZM['CoordY_SM'].max() 


            if ((self.Var_Selected == False) and (self.Contorno_Definido == False)):           #Not selected Variable V_target   #Not selected Map Contourn 
            
                self.Cord_X_min = Cord_X_min_ZM 
                self.Cord_Y_min = Cord_Y_min_ZM 
                self.Cord_X_max = Cord_X_max_ZM 
                self.Cord_Y_max = Cord_Y_max_ZM  


            plt7.close()
            
            plt7.title(self.tr('ZM') + ': ' + self.v_target + '   FPI: ' + str(self.fpi) + '   NCE: ' + str(self.nce))                               
            plt7.xlabel('Longitude (X)')
            plt7.ylabel('Latitude  (Y)') 

            plt7.xlim(float(Cord_X_min_ZM-100), float(Cord_X_max_ZM+100))
            plt7.ylim(float(Cord_Y_min_ZM-100), float(Cord_Y_max_ZM+100))        


            interval_x = int((self.Cord_X_max-self.Cord_X_min)/5)
            
            if interval_x == 0:
                interval_x = 1 #int((self.Cord_X_max-self.Cord_X_min))

            xmarks=[i for i in range(int(Cord_X_min_ZM),int(Cord_X_max_ZM) , interval_x)]          
            plt7.xticks(xmarks)
    

            interval_y = int((Cord_Y_max_ZM - Cord_Y_min_ZM)/7)
            
            if interval_y == 0:
                interval_y = 1 #int((self.Cord_X_max-self.Cord_X_min))

            ymarks=[i for i in range(int(Cord_Y_min_ZM),int(Cord_Y_max_ZM) , interval_y)]          
            plt7.yticks(ymarks)

            
            classes = np.arange(1,num_zones+1)
            classes_string  = [str(i) for i in classes]
            scatter = plt7.scatter(X[:, 0], X[:, 1], c=cluster_membership, cmap='RdYlGn')
            plt7.legend(handles=scatter.legend_elements()[0], title=self.tr('Classe'), labels=classes_string)

            plt7.subplots_adjust(wspace=0.6, hspace=0.6, left=0.15, right=0.95, bottom=0.1, top=0.95)

            plt7.ticklabel_format(style='plain', useOffset=False, axis='both') #não exibir coordenadas em notação cientifica 

            #janela do plot exibir as coordenadas em notação decimal. 
            ax = plt7.gca()
            ax.format_coord = lambda x,y: '%10d, %10d' % (x,y)
            
            plt7.savefig(     os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.png'))
            pixmap7 = QPixmap(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.png'))
            self.dlg.label_ZM.show()
            self.dlg.label_ZM.setPixmap(pixmap7)

            
            if self.dlg.checkBox_Qgis_Maps.isChecked(): 
                plt7.show()         

                      
            self.dlg.tabWidget_ZM.setCurrentIndex(3)          
            
            
                
            ###################################################################
            #Exportando arquivo Raster para QGIS 

            if self.dlg.checkBox_Qgis_Raster.isChecked(): 
 

                Input_Table            =                                   '2_ZM_' + self.VTarget_FileName + '_Class.csv'
                Output_Layer_File_tiff = os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.tiff')
                Output_Layer_Name      =                                   '2_ZM_' + self.VTarget_FileName
                z_field   = 'Classe'

                try: 
                    self.dlg.mMapLayerComboBox.currentIndexChanged.disconnect()
                except TypeError:
                    pass  # Ignore the error if no connections exist               
                    

                Output_Layer_File_tiff = self.export_raster_to_qgis(Input_Table, Output_Layer_File_tiff, Output_Layer_Name, z_field) 



                ###################################################################
                #Exportando arquivo Shapefile de pontos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Points.isChecked(): 
    
                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopoints") 

                    else: 
                        self.dlg.checkBox_Qgis_Vector_Points.setChecked(False)           


                ###################################################################
                #Exportando arquivo Shapefile de poligonos para QGIS 
    
                if self.dlg.checkBox_Qgis_Vector_Polygons.isChecked(): 
                    
                    #    marcou area de contorno                       e   definiu a layer de contorno) 
                    if ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >= 0)): 

                        cont = cont + 1 
                        progress.setValue(cont)                        
                        if progress.wasCanceled():                          
                           progress.close() 
                           return 
        
                        
                        self.export_shapefile_to_qgis(Output_Layer_File_tiff, "native:pixelstopolygons") 

                    else: 
                        self.dlg.checkBox_Qgis_Vector_Polygons.setChecked(False)           


            if self.dlg.checkBox_Qgis_Raster.isChecked(): 

                self.dlg.mMapLayerComboBox.currentIndexChanged.connect(self.mMapLayerComboBox_changed)


            self.ZM_Calcular = True 
         
            progress.close() 
            
            
    def datatable_ZM_Classe_doubleClicked(self):  

        os.startfile(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.csv'))

            
            
    def label_ZM_clicked(self, value):

        if system != 'Darwin':  #PIL do not is install in MacOS  
        
            if  self.ZM_Calcular == True:                
               image = Image.open(os.path.join(self.path_absolute , '2_ZM_' + self.VTarget_FileName + '_Class.png'))
               image.show()   
        

    #############################################################################################################################



    def export_raster_to_qgis(self, Input_Table, Output_Layer_File_tiff, Output_Layer_Name, z_field):


        #Input_Table            =                                   '2_ZM_' + self.atributos_ZM + '_Class.csv'
        #Output_Layer_File_tiff = os.path.join(self.path_absolute , '2_ZM_' + self.atributos_ZM + '_Class.tiff')
        #Output_Layer_Name      =                                   '2_ZM_' + self.atributos_ZM

        
        filename  = Output_Layer_File_tiff[:-5]           #copia o nome do arquivo, retirando sua extensão: '.tiff'
        layername = Output_Layer_Name
        
        cont = 1
        
        Output_Layer_File_tiff = filename  + '_' + str(cont) + '.tiff'
        Output_Layer_Name      = layername + '_' + str(cont)  
        
        while os.path.isfile(Output_Layer_File_tiff):     #se já existe o arquivo na pasta, renomeia para:  *_1.tiff', *_2.tiff'...
            cont = cont + 1
            Output_Layer_File_tiff = filename  + '_' + str(cont) + '.tiff'
            Output_Layer_Name      = layername + '_' + str(cont)  


        # your directory with all your csv files in it
        dir_with_csvs = os.path.join(self.path_absolute)  #+ '/' 
        
        # make it the active directory
        os.chdir(dir_with_csvs)

        csvfiles = [Input_Table] 

        lon_field = self.Cord_X                         #set the name for the field containing the longitude
        lat_field = self.Cord_Y                         #set the name for the field containing the latitude
                  
        # loop through each CSV file
        # for each CSV file, make an associated VRT file to be used with gdal_grid command
        # and then run the gdal_grid util in a subprocess instance
        for fn in csvfiles:
            vrt_fn = fn.replace(".csv", ".vrt")
            lyr_name = fn.replace('.csv', '')
            out_tif = fn.replace('.csv', '.tiff')
            with open(vrt_fn, 'w') as fn_vrt:
                fn_vrt.write('<OGRVRTDataSource>\n')
                fn_vrt.write('\t<OGRVRTLayer name="%s">\n' % lyr_name)
                fn_vrt.write('\t\t<SrcDataSource>%s</SrcDataSource>\n' % fn)
                fn_vrt.write('\t\t<GeometryType>wkbPoint</GeometryType>\n')
                fn_vrt.write('\t\t<GeometryField encoding="PointFromColumns" x="' + lon_field + '" y="' + lat_field + '" z="' + z_field + '"/>\n')
                fn_vrt.write('\t</OGRVRTLayer>\n')
                fn_vrt.write('</OGRVRTDataSource>\n')
        
                
                
                if  '2_ZM_' in Input_Table:    #set Pixel_size of ZM Map 

                    Pixel_Size_X = float(self.Pixel_Size_X_ZM) 
                    Pixel_Size_Y = float(self.Pixel_Size_Y_ZM) 
                    self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X_ZM))         
                    self.Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y_ZM))  
                    

                else: 
                  
                    Pixel_Size_X = float(self.Pixel_Size_X) 
                    Pixel_Size_Y = float(self.Pixel_Size_Y) 
                    self.Num_Points_X = int((float(self.Cord_X_max) - float(self.Cord_X_min)) / float(self.Pixel_Size_X))         
                    self.Num_Points_Y = int((float(self.Cord_Y_max) - float(self.Cord_Y_min)) / float(self.Pixel_Size_Y))         


                Num_Points_X = float(self.Num_Points_X) 
                Cord_X_min   = self.Cord_X_min 
                Cord_X_max   = (Pixel_Size_X * Num_Points_X) + Cord_X_min 


                Num_Points_Y = float(self.Num_Points_Y) 
                Cord_Y_min   = self.Cord_Y_min 
                Cord_Y_max   = (Pixel_Size_Y * Num_Points_Y) + Cord_Y_min      #ajustar Cord_Y_max  para que o tamanho do pixel fique com valor exato de 5m. 


           
            if '2_ZM' in Output_Layer_File_tiff:   #para ZM utiliza interpolador do vizinho mais proximo -> não interpola, pega apenas o vizinho + proximo
                gdal_cmd = [
                    'gdal_grid',
                    '-a', 'nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0',
                    '-zfield', z_field,
                    '-txe', str(self.Cord_X_min), str(Cord_X_max),
                    '-tye', str(self.Cord_Y_min), str(Cord_Y_max),
                    '-outsize', str(self.Num_Points_X), str(self.Num_Points_Y),
                    '-ot', 'UInt16', '-of', 'GTiff',
                    '-l', lyr_name, vrt_fn, out_tif
                ]
            else:
                #sem metodo interpolador
                gdal_cmd = [
                    'gdal_grid',
                    '-zfield', z_field,
                    '-txe', str(self.Cord_X_min), str(Cord_X_max),
                    '-tye', str(self.Cord_Y_min), str(Cord_Y_max),
                    '-outsize', str(self.Num_Points_X), str(self.Num_Points_Y),
                    '-ot', 'Float64', '-of', 'GTiff',
                    '-l', lyr_name, vrt_fn, out_tif
                ]

            subprocess.call(gdal_cmd)  #criar arquivo .tiff   (arquivo sem area de contorno)


        #######################################################################
        #fazer o recorte do raster de acordo com o limite de contorno     


        #(não marcou area de contorno)                       ou  (marcou area de contorno                       e  não definiu a layer de contorno) 
        if (not self.dlg.checkBox_Area_Contorno.isChecked()) or ((self.dlg.checkBox_Area_Contorno.isChecked()) and (self.dlg.mMapLayerComboBox_AreaCont.currentIndex() < 0)): 

            #para criar e registrar uma  Rasterlayer no QGIS, adiciona apos a layer corrente selecionada 
            #self.iface.addRasterLayer(out_tif, lyr_name)                       

            #para adicionar a layer em uma posição absoluta no QGIS 

            #create a RasterLayer 
            rlayer = QgsRasterLayer(out_tif, lyr_name)
            # first add the layer without showing it
            QgsProject.instance().addMapLayer(rlayer, False)
            # obtain the layer tree of the top-level group in the project
            layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
            # the position is a number starting from 0, with -1 an alias for the end
            layerTree.insertChildNode(-1, QgsLayerTreeLayer(rlayer))
            #define color_ramp of raster layer  
            self.define_raster_color_ramp(rlayer, Output_Layer_Name)


            #set CRS da layer RasterLayer 
            #rasterLayer = self.iface.activeLayer()
            selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()

            coordenate_reference = selectedLayer.crs().description()
            
            if 'SAD69' in coordenate_reference: 
                
                crs = QgsProject.instance().crs().authid()  #get CRS of project   EX: EPSG:32723
            
            else:      

                crs = selectedLayer.crs().authid()  #EPSG:32723  -> pegar so depois de: 

                    
            crs = crs.split(':')               #gera uma lista:  ['EPSG', '32723'] 
            crs = crs[1]                       #segundo elemento da lista: '32723'
            CRS = QgsCoordinateReferenceSystem()
            CRS.createFromSrid(int(crs))
            rlayer.setCrs(CRS)
            rlayer.crs().postgisSrid()
            

            #recortar o arquivo raster (.tiff)  manualmente dentro do QGIS 

            #usar o QGIS ->  ir em Raster -> Extraction  -> Clip Raster by Mask Layer 
            #escolher a Input Layer (Layer Raster)
            #escolher a Mask Layer  (Poligono de Contorno)
            #escolher o Source CRS 
            #escolher o Target CRS 
            #Assign a specified nodata value to output bands ->  para excluir a área fora do poligono -> colocar -999999999.000000                

        else:  #usuário marcou area de contorno                  

            if self.dlg.mMapLayerComboBox_AreaCont.currentIndex() >=  0: #usuário definiu poligono para recorte da layerRaster    

                #recortar o arquivo raster (.tiff)  usando uma layer = polygonLayer 
                Input_Layer_File_tiff  = out_tif                                                #r"C:\Users\Gustavo\Documents\QGISProjects\ProjetoAraponga\2_ZM_K_Class.tiff"         
                Input_Layer_Poligon    = self.dlg.mMapLayerComboBox_AreaCont.currentLayer()     #r"C:\Users\Gustavo\Documents\QGISProjects\ProjetoAraponga\Limite_Area_Poligono.shp" 

                coordenate_reference = Input_Layer_Poligon.crs().description()
                
                if 'SAD69' in coordenate_reference: 
                    
                    crs = QgsProject.instance().crs().authid()                 #get CRS of project        #EPSG:32723
                
                else:      

                    crs = Input_Layer_Poligon.crs().authid()                   #get CRS of Poligon Layer  #EPSG:32723  


                    
                if not os.path.isfile(Input_Layer_File_tiff):
                    print ("File doesn't exists", Input_Layer_File_tiff)
                    return None
                else:
                    
                    params = {'INPUT': Input_Layer_File_tiff,
                              'MASK': Input_Layer_Poligon,
                              'SOURCE_CRS': crs, #'EPSG:32723',
                              'TARGET_CRS': crs, 
                              'NODATA': -999999999.0,
                              'ALPHA_BAND': False,
                              'CROP_TO_CUTLINE': True,
                              #'KEEP_RESOLUTION': True,
                              #'OPTIONS': 'COMPRESS=LZW',  
                              #'DATA_TYPE': 0,  # Byte
                              'OUTPUT': Output_Layer_File_tiff,
                              }
            
                    feedback = QgsProcessingFeedback()
                    alg_name = 'gdal:cliprasterbymasklayer'
                    #alg_name = 'saga:kmeansclusteringforgrids'
                    #print(processing.algorithmHelp(alg_name))  #imprime o Help do comando 
                    
                    processing.run(alg_name, params, feedback=feedback)

                    #else: 

                         #gdal_cmd = 'gdalwarp -overwrite -s_srs EPSG:32723 -t_srs EPSG:32723 -of GTiff -cutline F:/Projetos/QGISProjects/ProjetoBrauna/Limite_Area2.shp -cl Limite_Area2 -crop_to_cutline -dstnodata -999999999.0 F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map/1_Krig_P_Grid_Map.tiff F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map/1_Krig_P_Grid_Map_Cut.tiff'
    
                    #    gdal_cmd  = 'gdalwarp -overwrite -s_srs ' + crs + ' -t_srs ' +  crs + ' -of GTiff -cutline ' + Input_Layer_Poligon_path +  ' -cl ' + Input_Layer_Poligon_filename[0] + ' -crop_to_cutline -dstnodata -999999999.0 ' + os.path.join(self.path_absolute , Input_Layer_File_tiff)  + ' ' + Output_Layer_File_tiff
     
                         #print(gdal_cmd)
                    #    subprocess.call(gdal_cmd, shell=True)  #criar arquivo .tiff cut  (arquivo sem area de contorno)

    
                    #para criar e registrar uma  Rasterlayer no QGIS, adiciona apos a layer corrente selecionada 
                    #self.iface.addRasterLayer(Output_Layer_File_tiff, Output_Layer_Name)  

                    #para adicionar a layer em uma posição absoluta no QGIS 

                    #create a RasterLayer 
                    rlayer = QgsRasterLayer(Output_Layer_File_tiff, Output_Layer_Name)
                    # first add the layer without showing it
                    QgsProject.instance().addMapLayer(rlayer, False)
                    # obtain the layer tree of the top-level group in the project
                    layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
                    # the position is a number starting from 0, with -1 an alias for the end
                    layerTree.insertChildNode(-1, QgsLayerTreeLayer(rlayer))
                    #define color_ramp of raster layer  
                    self.define_raster_color_ramp(rlayer, Output_Layer_Name)


        return Output_Layer_File_tiff 



    # ============================================================
    # FUNÇÃO ORIGINAL — comentada (dependia de checagem de versão do QGIS)
    # O problema: rp['color1'], rp['stops'] e rp['color2'] retornam strings
    # com formato diferente em cada versão do QGIS (3.28/3.34 vs 3.40/3.44),
    # quebrando os índices fixos usados para extrair R,G,B,A.
    # ============================================================
    # def define_raster_color_ramp(self, layer, Output_Layer_Name):
    #
    #     #renderer = layer.renderer()
    #     provider = layer.dataProvider()
    #     extent = layer.extent()
    #     stats = provider.bandStatistics(1, QgsRasterBandStats.All, extent, 0)
    #     min_value = stats.minimumValue
    #     max_value = stats.maximumValue
    #
    #     myStyle = QgsStyle().defaultStyle()
    #     ramp_names = myStyle.colorRampNames()
    #     dict = {}
    #     for i, name in enumerate(ramp_names):
    #         dict[ramp_names[i]] = i
    #     ramp = myStyle.colorRamp('RdYlGn')
    #
    #     rp = ramp.properties()
    #     # rp['color1'] muda de formato entre versões do QGIS:
    #     #   3.28/3.34: '215,25,28,255'
    #     #   3.40/3.44: '215,25,28,255,rgb:0.843...,0.098...,0.109...,1'
    #     # O mesmo ocorre com rp['stops'] e rp['color2'].
    #
    #     if '2_ZM' in Output_Layer_Name:
    #         number_classes = self.dlg.spinBox_ZM_NrZonas.value()
    #     else:
    #         number_classes = 5
    #     interval = (max_value - min_value) / (number_classes - 1)
    #     soma = min_value
    #     classes = []
    #     for i in range(number_classes):
    #         classes.append(round(soma, 10))
    #         soma += interval
    #
    #     qgis_version = qgis.utils.Qgis.QGIS_VERSION
    #
    #     if ('3.40' in qgis_version) or ('3.44' in qgis_version):
    #         c1    = rp['color1'].replace(";", ",").split(",")
    #         stops = rp['stops'].replace(";", ",").split(",")
    #         c2    = rp['color2'].replace(";", ",").split(",")
    #         # índices para stops nesta versão: stop1=1..4, stop2=11..14, stop3=21..24
    #     else:  # 3.28 e 3.34
    #         c1    = [int(e) for e in rp['color1'].split(',')]
    #         stops = [e for e in re.split('[,;:]', rp['stops'])]
    #         c2    = [int(e) for e in rp['color2'].split(',')]
    #         # índices para stops nesta versão: stop1=1..4, stop2=8..11, stop3=15..18
    #
    #     if number_classes == 2:
    #         color_list = [ QgsColorRampShader.ColorRampItem(classes[0], QColor(int(c1[0]),int(c1[1]),int(c1[2]),int(c1[3])), '%.1f' % classes[0]),
    #                        QgsColorRampShader.ColorRampItem(classes[1], QColor(int(c2[0]),int(c2[1]),int(c2[2]),int(c2[3])), '%.1f' % classes[1]) ]
    #     elif number_classes == 3:
    #         color_list = [ QgsColorRampShader.ColorRampItem(classes[0], QColor(int(c1[0]),int(c1[1]),int(c1[2]),int(c1[3])),     '%.1f' % classes[0]),
    #                        QgsColorRampShader.ColorRampItem(classes[1], QColor(int(stops[1]),int(stops[2]),int(stops[3]),int(stops[4])), '%.1f' % classes[1]),
    #                        QgsColorRampShader.ColorRampItem(classes[2], QColor(int(c2[0]),int(c2[1]),int(c2[2]),int(c2[3])),     '%.1f' % classes[2]) ]
    #     elif number_classes == 4:
    #         if ('3.40' in qgis_version) or ('3.44' in qgis_version):
    #             color_list = [ ..., stops[11..14], ... ]   # índices diferentes por versão
    #         else:
    #             color_list = [ ..., stops[8..11], ... ]
    #     else:  # 5 classes
    #         if ('3.40' in qgis_version) or ('3.44' in qgis_version):
    #             color_list = [ ..., stops[1..4], stops[11..14], stops[21..24], ... ]
    #         else:
    #             color_list = [ ..., stops[1..4], stops[8..11], stops[15..18], ... ]
    #
    #     myRasterShader = QgsRasterShader()
    #     myColorRamp = QgsColorRampShader()
    #     myColorRamp.setColorRampItemList(color_list)
    #     myColorRamp.setColorRampType(QgsColorRampShader.Interpolated)
    #     myRasterShader.setRasterShaderFunction(myColorRamp)
    #     myPseudoRenderer = QgsSingleBandPseudoColorRenderer(layer.dataProvider(), 1, myRasterShader)
    #     myPseudoRenderer.setClassificationMax(max_value)
    #     myPseudoRenderer.setClassificationMin(min_value)
    #     layer.setRenderer(myPseudoRenderer)
    #     layer.triggerRepaint()
    # ============================================================


    # ============================================================
    # FUNÇÃO NOVA — genérica, independente de versão do QGIS
    # Usa a API direta do objeto QgsGradientColorRamp:
    #   ramp.color1()  → QColor da cor inicial (vermelho)
    #   ramp.color2()  → QColor da cor final   (verde)
    #   ramp.stops()   → lista de QgsGradientStop com atributo .color (QColor)
    # Não faz parse de strings, portanto não quebra com mudanças de formato.
    # ============================================================
    def define_raster_color_ramp(self, layer, Output_Layer_Name):

        provider  = layer.dataProvider()
        extent    = layer.extent()
        stats     = provider.bandStatistics(1, QgsRasterBandStats.All, extent, 0)
        min_value = stats.minimumValue
        max_value = stats.maximumValue

        myStyle = QgsStyle().defaultStyle()
        ramp    = myStyle.colorRamp('RdYlGn')

        # Cores extraídas via API — independente do formato interno da versão do QGIS
        c1_color    = ramp.color1()                        # QColor vermelho (offset 0.0)
        c2_color    = ramp.color2()                        # QColor verde    (offset 1.0)
        stop_colors = [s.color for s in ramp.stops()]      # [QColor@0.25, QColor@0.5, QColor@0.75]

        if '2_ZM' in Output_Layer_Name:
            number_classes = self.dlg.spinBox_ZM_NrZonas.value()
        else:
            number_classes = 5

        interval = (max_value - min_value) / (number_classes - 1)
        soma     = min_value
        classes  = []
        for i in range(number_classes):
            classes.append(round(soma, 10))
            soma += interval

        if number_classes == 2:

            color_list = [ QgsColorRampShader.ColorRampItem(classes[0], c1_color,       '%.1f' % classes[0]),
                           QgsColorRampShader.ColorRampItem(classes[1], c2_color,       '%.1f' % classes[1]) ]

        elif number_classes == 3:

            color_list = [ QgsColorRampShader.ColorRampItem(classes[0], c1_color,       '%.1f' % classes[0]),
                           QgsColorRampShader.ColorRampItem(classes[1], stop_colors[0], '%.1f' % classes[1]),
                           QgsColorRampShader.ColorRampItem(classes[2], c2_color,       '%.1f' % classes[2]) ]

        elif number_classes == 4:

            color_list = [ QgsColorRampShader.ColorRampItem(classes[0], c1_color,       '%.1f' % classes[0]),
                           QgsColorRampShader.ColorRampItem(classes[1], stop_colors[0], '%.1f' % classes[1]),
                           QgsColorRampShader.ColorRampItem(classes[2], stop_colors[1], '%.1f' % classes[2]),
                           QgsColorRampShader.ColorRampItem(classes[3], c2_color,       '%.1f' % classes[3]) ]

        else:

            color_list = [ QgsColorRampShader.ColorRampItem(classes[0], c1_color,       '%.6f' % classes[0]),
                           QgsColorRampShader.ColorRampItem(classes[1], stop_colors[0], '%.6f' % classes[1]),
                           QgsColorRampShader.ColorRampItem(classes[2], stop_colors[1], '%.6f' % classes[2]),
                           QgsColorRampShader.ColorRampItem(classes[3], stop_colors[2], '%.6f' % classes[3]),
                           QgsColorRampShader.ColorRampItem(classes[4], c2_color,       '%.6f' % classes[4]) ]

        myRasterShader = QgsRasterShader()
        myColorRamp    = QgsColorRampShader()

        myColorRamp.setColorRampItemList(color_list)
        myColorRamp.setColorRampType(QgsColorRampShader.Interpolated)
        myRasterShader.setRasterShaderFunction(myColorRamp)

        myPseudoRenderer = QgsSingleBandPseudoColorRenderer(layer.dataProvider(), 1, myRasterShader)
        myPseudoRenderer.setClassificationMax(max_value)
        myPseudoRenderer.setClassificationMin(min_value)

        layer.setRenderer(myPseudoRenderer)
        layer.triggerRepaint()
        



    def export_shapefile_to_qgis(self, Input_Layer_File_tiff, alg_name):


        
        (Input_Layer_directory, Input_Layer_filename) = os.path.split(Input_Layer_File_tiff)  #'F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map/1_Krig_CA_Grid_Map_5.tiff'
        #Input_Layer_directory <- F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map
        #Input_Layer_filename  <- 1_Krig_CA_Grid_Map_5.tiff

        Input_Layer_filename = Input_Layer_filename.split(".")                 #separa o nome do arquivo da sua extensão 
        #Input_Layer_filename[0] <- 1_Krig_CA_Grid_Map_5
        #Input_Layer_filename[1] <- tiff                
        
        if alg_name == "native:pixelstopoints":
            Output_Layer_File_shp = os.path.join(self.path_absolute , Input_Layer_filename[0] + '_points.shp')
        else: 
            Output_Layer_File_shp = os.path.join(self.path_absolute , Input_Layer_filename[0] + '_polygons.shp')
            

        params = { 'FIELD_NAME'   : self.v_target, 
                   'INPUT_RASTER' : Input_Layer_File_tiff,  #'F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map/1_Krig_CA_Grid_Map_5.tiff'
                   'OUTPUT'       : Output_Layer_File_shp,  #'F:/Projetos/QGISProjects/ProjetoBrauna/Smart-Map/1_Krig_CA_Grid_Map_8_points.shp', 
                   'RASTER_BAND' : 1 }


        #alg_name  #"native:pixelstopolygons"
                   #"native:pixelstopoints


        processing.run(alg_name, params)                

        #para adicionar a layer em uma posição absoluta no QGIS 
        #create a VectorLayer 
        if alg_name == "native:pixelstopoints":
            vlayer = QgsVectorLayer(Output_Layer_File_shp, Input_Layer_filename[0] + '_points', "ogr")
        else: 
            vlayer = QgsVectorLayer(Output_Layer_File_shp, Input_Layer_filename[0] + '_polygons', "ogr")
            
        # first add the layer without showing it
        QgsProject.instance().addMapLayer(vlayer, False)        
        # obtain the layer tree of the top-level group in the project
        layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
        # the position is a number starting from 0, with -1 an alias for the end
        layerTree.insertChildNode(-1, QgsLayerTreeLayer(vlayer))




    #used to create layer resampled of points
    def export_shapefile_resampled_to_qgis(self, Input_Table, Output_Layer_File_shp, Output_Layer_Name):


        #Input_Table            = os.path.join(self.path_absolute , '2_ZM_' + self.atributos_ZM + '_Class.csv') # set the filepath for the input CSV
        #Output_Layer_File_shp  = os.path.join(self.path_absolute , '2_ZM_' + self.atributos_ZM + '_Class.shp') # set the filepath for the output shapefile
        #Output_Layer_Name      =                                   '2_ZM_' + self.atributos_ZM
        
        Output_Layer_File_gpkg  = Output_Layer_File_shp + '.gpkg'

        filename  = Output_Layer_File_gpkg[:-9]                                #arquivo sem extensão:  .shp.gpkg
        layername = Output_Layer_Name
        
        cont = 1

        Output_Layer_File_gpkg = filename  + '_' + str(cont) + '.shp.gpkg'
        Output_Layer_File_shp  = filename  + '_' + str(cont) + '.shp'
        Output_Layer_Name      = layername + '_' + str(cont)  

        while os.path.isfile(Output_Layer_File_gpkg):                          #se já existe o arquivo na pasta, renomeia para:  *_1.shp.gpkg', *_2.shp.gpkg'...
            cont = cont + 1
            Output_Layer_File_gpkg = filename  + '_' + str(cont) + '.shp.gpkg'
            Output_Layer_File_shp  = filename  + '_' + str(cont) + '.shp'
            Output_Layer_Name      = layername + '_' + str(cont)  

        
        #converter o arquivo .csv  em um arquivo .shp (shapefile)
        lon_field = self.Cord_X                                                #set the name for the field containing the longitude
        lat_field = self.Cord_Y                                                #set the name for the field containing the latitude
        #set the crs as needed  selectedLayer = iface.activeLayer()            #selectedLayer.crs().authid()   ex: 'EPSG:4326'
        selectedLayer = self.dlg.mMapLayerComboBox.currentLayer()

        coordenate_reference = selectedLayer.crs().description()
        
        if 'SAD69' in coordenate_reference: 
            
            crs = QgsProject.instance().crs().authid()  #get CRS of project   EX: EPSG:32723
        
        else:      

            crs = selectedLayer.crs().authid()                                     #EPSG:32723  -> pegar so depois de : 
                
        crs = crs.split(':')                                                   #gera uma lista:  ['EPSG', '32723'] 
        crs = crs[1]                                                           #segundo elemento da lista: '32723'
         
        spatRef = QgsCoordinateReferenceSystem(int(crs), QgsCoordinateReferenceSystem.EpsgCrsId)

        inp_tab = QgsVectorLayer(Input_Table, 'Input_Table', 'ogr')
        prov = inp_tab.dataProvider()
        fields = [field.name() for field in prov.fields()]

        fields1 = QgsFields()

        for i in range(len(fields)): 
            fields1.append(QgsField(fields[i], QVariant.Double))
            #fields1.append(QgsField(fields[1], QVariant.Double))
            #fields1.append(QgsField(fields[2], QVariant.Double))

        outLayer = QgsVectorFileWriter(Output_Layer_File_shp, None, fields1, QgsWkbTypes.Point, spatRef)
         
        pt = QgsPointXY()
        outFeature = QgsFeature()
         
        for feat in inp_tab.getFeatures():
            attrs = feat.attributes()
            pt.setX(float(feat[lon_field]))
            pt.setY(float(feat[lat_field]))
            outFeature.setAttributes(attrs)
            outFeature.setGeometry(QgsGeometry.fromPointXY(pt))
            outLayer.addFeature(outFeature)
        del outLayer

        #para criar e registrar uma  Vectorlayer no QGIS, adiciona apos a layer corrente selecionada
        #self.iface.addVectorLayer(Output_Layer_File_gpkg, Output_Layer_Name, "ogr")

        #para adicionar a layer em uma posição absoluta no QGIS 
        #create a VectorLayer 
        vlayer = QgsVectorLayer(Output_Layer_File_gpkg, Output_Layer_Name, "ogr")
        # first add the layer without showing it
        QgsProject.instance().addMapLayer(vlayer, False)        
        # obtain the layer tree of the top-level group in the project
        layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
        # the position is a number starting from 0, with -1 an alias for the end
        layerTree.insertChildNode(-1, QgsLayerTreeLayer(vlayer))

        
                                
