def create_widgets(self):
        ''' Creates all widgets.
        '''
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        validate_btn = Button(self,
                              text='Validate weight restrictions',
                              command=self.on_validate_weights)
        validate_btn.grid(row=0, column=0, padx=10, pady=5, sticky=N + W)

        panel = LabelFrame(self, text='Weight restrictions')
        panel.columnconfigure(0, weight=1)
        panel.rowconfigure(0, weight=1)
        panel.grid(row=1, column=0, padx=5, pady=5, sticky=E + W + S + N)

        weight_tab_main = VerticalScrolledFrame(panel)
        weight_tab_main.grid(row=0, column=0, sticky=E + W + S + N)
        weights_tab = weight_tab_main.interior

        self.abs_weights = TextForWeights(weights_tab, 'absolute',
                                          'Input1 <= 0.02',
                                          self.current_categories, self.params,
                                          'ABS_WEIGHT_RESTRICTIONS')
        self.abs_weights.grid(row=0, column=0, padx=10, pady=5, sticky=N + W)
        self.virtual_weights = TextForWeights(weights_tab, 'virtual',
                                              'Input1 >= 0.34',
                                              self.current_categories,
                                              self.params,
                                              'VIRTUAL_WEIGHT_RESTRICTIONS')
        self.virtual_weights.grid(row=1,
                                  column=0,
                                  padx=10,
                                  pady=5,
                                  sticky=N + W)
        self.price_ratio_weights = TextForWeights(weights_tab, 'price ratio',
                                                  'Input1/Input2 <= 5',
                                                  self.current_categories,
                                                  self.params,
                                                  'PRICE_RATIO_RESTRICTIONS',
                                                  True)
        self.price_ratio_weights.grid(row=2,
                                      column=0,
                                      padx=10,
                                      pady=5,
                                      sticky=N + W)
    def create_widgets(self):
        ''' Creates all widgets.
        '''
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        validate_btn = Button(self, text='Validate weight restrictions',
                              command=self.on_validate_weights)
        validate_btn.grid(row=0, column=0, padx=10, pady=5, sticky=N+W)

        panel = LabelFrame(self, text='Weight restrictions')
        panel.columnconfigure(0, weight=1)
        panel.rowconfigure(0, weight=1)
        panel.grid(row=1, column=0,
                   padx=5, pady=5, sticky=E+W+S+N)

        weight_tab_main = VerticalScrolledFrame(panel)
        weight_tab_main.grid(row=0, column=0, sticky=E+W+S+N)
        weights_tab = weight_tab_main.interior

        self.abs_weights = TextForWeights(weights_tab, 'absolute',
                                          'Input1 <= 0.02',
                                          self.current_categories, self.params,
                                          'ABS_WEIGHT_RESTRICTIONS')
        self.abs_weights.grid(row=0, column=0, padx=10, pady=5, sticky=N+W)
        self.virtual_weights = TextForWeights(weights_tab, 'virtual',
                                              'Input1 >= 0.34',
                                              self.current_categories,
                                              self.params,
                                              'VIRTUAL_WEIGHT_RESTRICTIONS')
        self.virtual_weights.grid(row=1, column=0, padx=10, pady=5, sticky=N+W)
        self.price_ratio_weights = TextForWeights(weights_tab, 'price ratio',
                                                  'Input1/Input2 <= 5',
                                                  self.current_categories,
                                                  self.params,
                                                  'PRICE_RATIO_RESTRICTIONS',
                                                  True)
        self.price_ratio_weights.grid(row=2, column=0, padx=10, pady=5,
                                      sticky=N+W)
Example #3
0
class Histogram(Frame):
    def __init__(self, parent, master):
        super(Histogram, self).__init__(parent)
        self.window = master  #type:VisAnaWindow
        self.parent = parent

        self.param_y = None
        self.param_x = None

        self.ds = self.window.ds  #type:DataSource

        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)

        self.tframe = LabelFrame(self, text="Tooltip")
        #self.tframe.grid(column=0, row=1, sticky=(S,W,N,E))
        self.tframe.rowconfigure(0, weight=1)
        self.tframe.columnconfigure(0, weight=1)
        self.tooltip = StringVar(self.tframe)
        self.tlabel = Label(self.tframe,
                            textvariable=self.tooltip,
                            justify="left",
                            anchor="nw",
                            wraplength=200)
        self.tlabel.grid(column=0, row=0, sticky=(W, N))

        self.select_rect = None

        if self.ds is None:
            self.settings = Label(
                self, text="No data, please open a file via File -> Open")
            self.settings.grid(column=1, row=1, sticky=(S, W, N, E))
            return

        self.settings = HControls(self, self.ds.base().get_attr_names())
        self.settings.grid(column=0, row=0, sticky=(S, W, N, E))
        self.apply_settings()

    ###################
    # PLOT-EVENT HANDLER

    ## is called by the plot to confirm if the mouseevent was inside/on a plotted line or a marker
    def handle_pick(self, line, mouseevent):
        if mouseevent.button == 1:
            return self.handle_mouse_event(mouseevent)
        else:
            return False, dict()

    ## is called to to do something when the mouse hovers over the plot and has changed its position.
    ## if no mousebutton is pressed and no points were selected, a hover-tooltip is shown.
    ## if the left button is pressed, (re-)draw the selection indicator
    def handle_hover(self, mouseevent):
        if not mouseevent.button in [1, 3] and self.select_rect is None:
            isover, props = self.handle_mouse_event(mouseevent)

            if isover:
                self.draw_tooltip(mouseevent, props["ind"])

        elif mouseevent.button in [1, 3]:
            ## handle case if mouse is outside the canvas
            if mouseevent.xdata == None:
                xmin = self.mouse_pressed[0]
                xmax = self.mouse_pressed[0]
                ymin = self.mouse_pressed[1]
                ymax = self.mouse_pressed[1]
            else:
                xmin = min(mouseevent.xdata, self.mouse_pressed[0])
                xmax = max(mouseevent.xdata, self.mouse_pressed[0])
                ymin = min(mouseevent.ydata, self.mouse_pressed[1])
                ymax = max(mouseevent.ydata, self.mouse_pressed[1])
            bbox = (xmin, ymin, xmax, ymax)
            self.clean_tooltip(True, emit=False)
            bbox2 = self.ax.transData.transform(bbox)
            c_height = self.canvas.figure.bbox.height
            bbox3 = (bbox2[0], c_height - bbox2[1], bbox2[2],
                     c_height - bbox2[3])
            self.select_rect = self.canvas.get_tk_widget().create_rectangle(
                bbox3, dash=".", outline=self.fgcol)

    ## is called whenever a mousebutton is clicked while the mouse is over the plot.
    ##  if the left button is pushed, we begin to draw a selection area
    def handle_mouse_down(self, mouseevent):
        if mouseevent.button in [1, 3]:
            self.clean_tooltip(True)
            self.mouse_pressed = (mouseevent.xdata, mouseevent.ydata)

    ## is called whenever a mouse button is released while hovering over the plot
    ## if the left button was pressed and there are points within the selection area, select those points and show a
    ##  tooltip containing information about those selected points. If not, clean up.
    def handle_mouse_up(self, mouseevent):
        if mouseevent.button in [1, 3]:
            ## handle case if mouse is outside the canvas
            if mouseevent.xdata == None:
                xmin = self.mouse_pressed[0]
                xmax = self.mouse_pressed[0]
                ymin = self.mouse_pressed[1]
                ymax = self.mouse_pressed[1]
            else:
                xmin = min(mouseevent.xdata, self.mouse_pressed[0])
                xmax = max(mouseevent.xdata, self.mouse_pressed[0])
                ymin = min(mouseevent.ydata, self.mouse_pressed[1])
                ymax = max(mouseevent.ydata, self.mouse_pressed[1])
            if xmin == xmax and ymin == ymax:
                self.clean_tooltip(True)
            else:
                if mouseevent.button == 1:
                    if self.param_x == self.ds.get_time_colname():
                        xmin = mdates.num2date(xmin)
                        xmax = mdates.num2date(xmax)
                    if self.param_y == self.ds.get_time_colname():
                        ymin = mdates.num2date(ymin)
                        ymax = mdates.num2date(ymax)
                    self.ds.select("ss_selected", self.param_x, xmin, xmax,
                                   "ss_show")
                    self.ds.select("ss_selected", self.param_y, ymin, ymax,
                                   "ss_selected")
                    ind = self.ds.df("ss_selected").index.values
                    if len(ind) > 0:
                        text = "Selected area from ({:.1f}; {:.1f})\n\t to ({:.1f}; {:.1f})"\
                                                        .format(xmin,ymin,xmax,ymax)
                        self.draw_tooltip(mouseevent, ind, True)
                        self.window.history.add(text)
                    else:
                        self.clean_tooltip(True)
                else:
                    self.clean_tooltip(True, emit=False)
                    self.ax.set_xlim((xmin, xmax), emit=False)
                    self.ax.set_ylim((ymin, ymax))
                    self.canvas.draw()

    ## handle any mouse event where it has to be clarified whether there's a marker under the mouse or not. If so,
    ##  return all index values of the concerning markers.
    def handle_mouse_event(self, mouseevent, radius=5):
        """
        find the points within a certain radius from the mouse in
        data coords and attach the index numbers of the found elements
        which are the data points that were picked
        """
        self.clean_tooltip()

        # print("PICKER")
        # print(mouseevent, vars(mouseevent))
        if self.param_x == self.ds.get_time_colname(
        ) or self.param_y == self.ds.get_time_colname():
            return False, dict()
        xydata = self.ax.transData.transform(
            self.ds.df("ss_show")[[self.param_x, self.param_y]]).transpose()
        try:
            mxy = self.ax.transData.transform(
                [mouseevent.xdata, mouseevent.ydata])
        except ValueError:
            return False, dict()
        xdata = xydata[0]
        ydata = xydata[1]
        mousex = mxy[0]
        mousey = mxy[1]
        if mouseevent.xdata is None:
            return False, dict()

        d = pd.np.sqrt((xdata - mousex)**2. + (ydata - mousey)**2.)
        ind = self.ds.df("ss_show").index.values[pd.np.nonzero(
            pd.np.less_equal(d, radius))[0]]

        if len(ind) > 0:
            props = dict(ind=ind)
            return True, props
        else:
            return False, dict()

    ## draws a tooltip and generates the information it contains from an event with/and a list of index values
    def draw_tooltip(self, event, ind=None, selected=False):
        if ind is None:
            ind = event.ind
            #event = event.mouseevent

        # Generate the Tooltip-String
        selstr = ""
        if selected:
            selstr = "selected "

        if len(ind) is 1:
            text = selstr + "value:"
            self.ds.select_ids("ss_selected", ind, "ss_show")
            for col, cdata in self.ds.df("ss_selected").iteritems():
                text += '\n{}: {}'.format(col, cdata[ind[0]])
        else:
            text = selstr + "%s values:" % len(ind)
            if not selected:
                self.ds.select_ids("ss_selected", ind, "ss_show")
            self.ds.aggregate("ss_sel_aggremin", "MIN", in_table="ss_selected")
            self.ds.aggregate("ss_sel_aggremax", "MAX", in_table="ss_selected")

            for col, cdata in self.ds.df("ss_sel_aggremin").iteritems():
                #text += '\n{}:\n  min:\t{}\n  max:\t{}'.format(col, cdata[0], self.ds.df("ss_sel_aggremax")[col][0])
                text += '\n{}: {} to {}'.format(
                    col, cdata[0],
                    self.ds.df("ss_sel_aggremax")[col][0])

        # write the tooltip
        self.tooltip.set(text)

        # # Draw the box and write the string on it
        #
        # c_height = self.canvas.figure.bbox.height
        # c_width = self.canvas.figure.bbox.width
        # y = c_height - event.y
        # x = event.x
        #
        # # get bounding box of a possible tooltip
        # self.plot_tooltip = self.canvas.get_tk_widget().create_text(x + 2, y, anchor=tk.NW, text=text)
        # bbox = self.canvas.get_tk_widget().bbox(self.plot_tooltip)
        # self.canvas.get_tk_widget().delete(self.plot_tooltip)
        #
        # # print("bbox:", bbox)
        #
        # # make sure the tooltip is within bounds
        # if bbox[2] > c_width:
        #     adj = -2
        #     if bbox[3] > c_height:
        #         anchor = tk.SE
        #     else:
        #         anchor = tk.NE
        # else:
        #     adj = 2
        #     if bbox[3] > c_height:
        #         anchor = tk.SW
        #     else:
        #         anchor = tk.NW
        # # get the new bounding box
        # if anchor is not tk.NW:  # =^= the anchor had to be modified
        #     self.plot_tooltip = self.canvas.get_tk_widget().create_text(x + adj, y, anchor=anchor, text=text)
        #     bbox = self.canvas.get_tk_widget().bbox(self.plot_tooltip)
        #     self.canvas.get_tk_widget().delete(self.plot_tooltip)
        #
        # self.plot_tooltip_rect = self.canvas.get_tk_widget().create_rectangle(bbox, fill="yellow")
        # self.plot_tooltip = self.canvas.get_tk_widget().create_text(x + adj, y, anchor=anchor, text=text)

    ## remove the tooltip if shown
    def clean_tooltip(self, with_select_rect=False, emit=True):
        self.tooltip.set("")
        if with_select_rect and self.select_rect is not None:
            self.canvas.get_tk_widget().delete(self.select_rect)
            self.select_rect = None
            #if emit:
            #self.action_str = None
            #TO-DO
            #self.trigger_update(self.TIMELINE_SELECTION)

    #### Handle Signals from Outside

    def apply_settings(self, ev=None):
        self.lgvar = self.settings.doLog()

        self.redraw_plot()

    def redraw_plot(self):
        self.window.status.set("Redraw Histogram...")
        self.draw_plot()
        self.window.status.set("")

    # the underlying data changed, called by VisAnaWindow.openFile
    def ds_changed(self):
        olds = self.ds
        self.ds = self.window.ds
        if olds is None:
            self.settings.destroy()
            newcols = self.window.calc.get_all_columns(with_time=True,
                                                       with_custom=False)
            self.settings = HControls(self, newcols)
            self.settings.grid(column=0, row=0, sticky=(S, W, N, E))

    # a cluster recalculation was processed, called by VisAnaWindow.redo_plots
    def cluster_changed(self, in_table):
        self.ds.link("h_show", in_table)

        self.apply_settings()

    def draw_plot(self):
        self.clean_tooltip(True)

        self.fig = Figure(figsize=(5, 5), dpi=100)  #type:Figure
        self.ax = self.fig.add_subplot(111)  #type:Axes

        self.ax.clear()
        self.ax.grid(True)
        tabl = self.ds.get_data("h_show")
        d = tabl.df()
        if tabl.centroids is not None:

            k = len(tabl.centroids)
            cluster_params = self.window.calc.cluster_params
            print("hist ", cluster_params)

            # subplot_num = 0
            # print(self.centroids)
            y_pos = pd.np.arange(len(cluster_params))
            # print(y_pos)
            width = 0.95 / k
            # colors = ["#d62728", "blue", "green", "brown"]
            max_y_val = 0
            for c in range(0, k):
                # subplot_num += 1
                ystdev = []
                one_value_cluster = d.loc[d['_cluster'] == c]

                # for i in range(0, len(datasource.GRAIN_COLS)):
                for i in range(0, len(cluster_params)):
                    col = one_value_cluster[cluster_params[i]]
                    stdev = pd.np.std(col)
                    ystdev.append(stdev)

                cen = [
                    tabl.centroids[c][i]
                    for i in range(0, len(cluster_params))
                ]
                ## cluster label for legend
                c_label = "Cluster " + str(c)
                self.ax.bar(
                    y_pos + width * (c - (k / 2.3)),
                    cen,
                    width,
                    align="center",
                    log=self.lgvar,  #alpha=0.75,
                    color=COLORS[c],
                    ecolor="black",
                    yerr=ystdev,
                    label=c_label)
                for i in range(0, len(cen)):
                    y_val = cen[i] + ystdev[i]
                    #print("y_val:",str(y_val))
                    if y_val > max_y_val:
                        max_y_val = y_val
                        #print("new max_y_val:",str(max_y_val))

                #print("cen:",str(cen))
                #print("ysdtev:",str(ystdev))
                #print("ypos:",str(y_pos))

            self.ax.grid(True)
            # self.ax.set_xticklabels
            # self.ax.set_ylim(0, 1, emit=False)
            #max_y_val = max(map(max, tabl.centroids))
            self.ax.set_ylim(0, max_y_val * 1.05, emit=False)

            self.ax.set_xticks(y_pos + width / 4)
            self.ax.set_xticklabels(cluster_params)

            #        self.ax.callbacks.connect('xlim_changed', self.handle_view_change)
            #        self.ax.callbacks.connect('ylim_changed', self.handle_view_change)

            ## add legend
            self.ax.legend(loc="upper right", shadow=True)
        else:
            cluster_params = [
                col
                for col in self.window.calc.get_all_columns(after_calc=True)
                if col not in ["OutdoorTemp", "RelHumidity", "Daytime"]
            ]
            print("hist ", cluster_params)

            # subplot_num = 0
            # print(self.centroids)
            y_pos = pd.np.arange(len(cluster_params))
            # print(y_pos)
            width = 0.95 / 1
            # colors = ["#d62728", "blue", "green", "brown"]
            # subplot_num += 1
            ystdev = []
            one_value_cluster = d

            # for i in range(0, len(datasource.GRAIN_COLS)):
            for i in range(0, len(cluster_params)):
                col = one_value_cluster[cluster_params[i]]
                stdev = pd.np.std(col)
                ystdev.append(stdev)

            cen = d[cluster_params].mean(axis=0)
            print(type(cen), type(cen.max()), cen.max())
            ## cluster label for legend
            self.ax.bar(
                y_pos + width * (0 - (1 / 2.3)),
                cen,
                width,
                align="center",
                log=self.lgvar,  # alpha=0.75,
                color="blue",
                ecolor="black",
                yerr=ystdev)
            self.ax.grid(True)
            # self.ax.set_xticklabels
            # self.ax.set_ylim(0, 1, emit=False)
            max_y_val = cen.max()
            self.ax.set_ylim(0, max_y_val * 1.1, emit=False)

            self.ax.set_xticks(y_pos + width / 4)
            self.ax.set_xticklabels(cluster_params)

        ## add legend
#            self.ax.legend(loc="upper right", shadow=True)

        self.canvas = FigureCanvasTkAgg(self.fig,
                                        self)  #type:FigureCanvasTkAgg

        self.canvas.get_tk_widget().grid(column=1,
                                         row=0,
                                         sticky=(N, E, W, S),
                                         rowspan=2)
    def crea_GUI(self):
        root = self.root
        #Menús
        self.menubar = Menu(root, tearoff=0)

        m_archivo = Menu(self.menubar, tearoff=0)
        m_archivo.add_command(label='Abrir',
                              command=self.abrir_dataset,
                              accelerator='Ctrl+O')
        m_archivo.add_separator()
        m_archivo.add_command(label='Salir', command=self.cerrar_aplicacion)
        self.menubar.add_cascade(label='Archivo', menu=m_archivo)

        m_proyecto = Menu(self.menubar, tearoff=0)
        m_proyecto.add_command(label='Abrir',
                               command=self.abrir_proyecto,
                               state="disabled")
        m_proyecto.add_separator()
        m_proyecto.add_checkbutton(label='Clase al final',
                                   onvalue=True,
                                   offvalue=False,
                                   variable=self.clase_al_final)
        self.menubar.add_cascade(label='Proyecto', menu=m_proyecto)

        self.m_configuracion = Menu(self.menubar, tearoff=0)
        self.m_configuracion.add_command(
            label='Ruta datasets', command=lambda: self.rutas('datasets'))
        self.m_configuracion.add_command(
            label='Ruta resultados', command=lambda: self.rutas('resultados'))
        self.m_configuracion.add_checkbutton(label='Rutas relativas',
                                             onvalue=True,
                                             offvalue=False,
                                             variable=self.rutas_relativas,
                                             command=self.cambia_rutas)
        self.m_configuracion.add_separator()
        #TODO Revisar self.v_tamanyo_muestra, no la uso
        #        self.v_tamanyo_muestra = StringVar(root, 'Tamaño muestra ({:,})'.\
        #                                           format(self._tamanyo_muestra))
        self.m_cfg_tamanyo_muestra = \
            self.m_configuracion.add_command(label='Tamaño muestra ({:,})'.\
                                           format(self._tamanyo_muestra),
                                        command=lambda: self.tamanyo_muestra(\
                                                        self._tamanyo_muestra))
        self.m_configuracion.add_separator()
        self.m_configuracion.add_checkbutton(label='Utiliza sha1',
                                             onvalue=True,
                                             offvalue=False,
                                             variable=self.usa_sha1)
        self.menubar.add_cascade(label='Configuración',
                                 menu=self.m_configuracion)

        m_ver = Menu(self.menubar, tearoff=0)
        self.v_tipo_dataset = StringVar(self.root, 'Dataset original')
        m_ver.add_radiobutton(label='Dataset original',
                              value='Dataset original',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Dataset sin evidencias incompletas',
                              value='Dataset sin evidencias incompletas',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Dataset sin atributos constantes',
                              value='Dataset sin atributos constantes',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Catálogo',
                              value='Catálogo',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Catálogo Robusto',
                              value='Catálogo Robusto',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_separator()
        m_ver.add_checkbutton(label='Log del proceso',
                              onvalue=True,
                              offvalue=False,
                              variable=self.mostrar_proceso,
                              state='disabled')
        self.menubar.add_cascade(label='Ver', menu=m_ver)

        root.config(menu=self.menubar)

        #Dataset de clasificación
        lf_dataset = LabelFrame(root, text='Dataset de Clasificación')
        lf_dataset.pack(fill='both', expand=True, padx=5, pady=5)

        Label(lf_dataset, text='Nombre:').grid(row=0, column=0, sticky='e')
        self.v_nombre_dataset = StringVar(root, '-------')
        self.l_nombre_dataset = Label(lf_dataset,
                                      textvariable=self.v_nombre_dataset)
        self.l_nombre_dataset.grid(row=0, column=1, sticky='w')

        Label(lf_dataset, text='Tamaño:').grid(row=0, column=2, sticky='e')
        self.v_tamanyo_dataset = StringVar(root, '-------')
        Label(lf_dataset, textvariable=self.v_tamanyo_dataset).grid(row=0,
                                                                    column=3,
                                                                    sticky='w')

        Label(lf_dataset, text='Ubicación:').grid(row=1, column=0, sticky='e')
        self.v_ruta_dataset = StringVar(root, '-------------------------')
        #TODO Expandir en columnas 1-3, puede ser muy larga
        Label(lf_dataset, textvariable=self.v_ruta_dataset).grid(row=1,
                                                                 column=1,
                                                                 sticky='w',
                                                                 columnspan=3)

        #Dataset de clasificación / Muestra
        lf_dataset_muestra = LabelFrame(lf_dataset, text='Muestra')
        lf_dataset_muestra.grid(row=2,
                                column=0,
                                sticky='nsew',
                                columnspan=4,
                                padx=5,
                                pady=5)

        self.sb_v_t_muestra = Scrollbar(lf_dataset_muestra)
        self.sb_v_t_muestra.grid(row=0, column=1, sticky='sn')

        self.sb_h_t_muestra = Scrollbar(lf_dataset_muestra,
                                        orient='horizontal')
        self.sb_h_t_muestra.grid(row=1, column=0, sticky='ew')

        self.t_muestra = Text(lf_dataset_muestra,
                              yscrollcommand=self.sb_v_t_muestra.set,
                              xscrollcommand=self.sb_h_t_muestra.set,
                              bd=0,
                              wrap='none',
                              state='disabled',
                              height=8)
        self.t_muestra.grid(row=0, column=0, sticky='nswe')

        self.sb_v_t_muestra.config(command=self.t_muestra.yview)
        self.sb_h_t_muestra.config(command=self.t_muestra.xview)

        lf_dataset_muestra.rowconfigure(0, weight=1)
        lf_dataset_muestra.columnconfigure(0, weight=1)

        lf_dataset.rowconfigure(2, weight=3)
        lf_dataset.columnconfigure(1, weight=1)
        lf_dataset.columnconfigure(3, weight=1)

        #Dataset de clasificación / Evidencias
        lf_dataset_evidencias = LabelFrame(lf_dataset, text='Evidencias')
        lf_dataset_evidencias.grid(row=3,
                                   column=0,
                                   sticky='nsew',
                                   padx=5,
                                   pady=5)

        Label(lf_dataset_evidencias, text='Total:').grid(row=0,
                                                         column=0,
                                                         sticky='e')
        self.v_evidencias_total = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_total).\
              grid(row=0, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Completas:').grid(row=1,
                                                             column=0,
                                                             sticky='e')
        self.v_evidencias_completas = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_completas).\
              grid(row=1, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Únicas:').grid(row=2,
                                                          column=0,
                                                          sticky='e')
        self.v_evidencias_catalogo = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_catalogo).\
              grid(row=2, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Robustas:').grid(row=3,
                                                            column=0,
                                                            sticky='e')
        self.v_evidencias_robustas = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_robustas).\
              grid(row=3, column=1, sticky='w')

        #Dataset de clasificación / Atributos
        lf_dataset_clase_y_atributos = LabelFrame(lf_dataset,
                                                  text='Clase y atributos')
        lf_dataset_clase_y_atributos.grid(row=3,
                                          column=1,
                                          sticky='nsew',
                                          columnspan=3,
                                          padx=5,
                                          pady=5)

        PROPIEDADES_ATRIBUTOS = ('Nombre', 'count', 'unique', 'top', 'freq',
                                 'mean', 'std', 'min', '25%', '50%', '75%',
                                 'max')

        self.sb_h_tv_clase = Scrollbar(lf_dataset_clase_y_atributos,
                                       orient='horizontal')
        self.sb_h_tv_clase.grid(row=1, column=0, sticky='ew')
        self.tv_clase = Treeview(lf_dataset_clase_y_atributos,
                                 columns=PROPIEDADES_ATRIBUTOS,
                                 height=1,
                                 xscrollcommand=self.sb_h_tv_clase.set)
        self.tv_clase.grid(row=0, column=0, sticky='ew')
        self.sb_h_tv_clase.config(command=self.tv_clase.xview)
        self.tv_clase.heading("#0", text="#")
        self.tv_clase.column("#0", minwidth=30, width=40, stretch=False)

        self.sb_v_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos)
        self.sb_v_tv_atributos.grid(row=2, column=1, sticky='sn')
        self.sb_h_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos,
                                           orient='horizontal')
        self.sb_h_tv_atributos.grid(row=3, column=0, sticky='ew')
        self.tv_atributos = Treeview(lf_dataset_clase_y_atributos,
                                     columns=PROPIEDADES_ATRIBUTOS,
                                     yscrollcommand=self.sb_v_tv_atributos.set,
                                     xscrollcommand=self.sb_h_tv_atributos.set)
        self.tv_atributos.grid(row=2, column=0, sticky='nsew')
        self.tv_atributos.bind('<ButtonRelease-1>', self.selectItem)
        self.sb_v_tv_atributos.config(command=self.tv_atributos.yview)
        self.sb_h_tv_atributos.config(command=self.tv_atributos.xview)
        self.tv_atributos.heading("#0", text="#")
        self.tv_atributos.column("#0", minwidth=30, width=40, stretch=False)

        for i in PROPIEDADES_ATRIBUTOS:
            self.tv_clase.heading(i, text=i)
            self.tv_clase.column(i, minwidth=50, width=50, stretch=False)
            self.tv_atributos.heading(i, text=i)
            self.tv_atributos.column(i, minwidth=50, width=50, stretch=False)

        lf_dataset_clase_y_atributos.rowconfigure(2, weight=1)
        lf_dataset_clase_y_atributos.columnconfigure(0, weight=1)

        lf_dataset.rowconfigure(3, weight=1)