import pandas as pd
import numpy as np
import matplotlib
import random
import os
import sys
from matplotlib.figure import Figure
import matplotlib.colors as colors
import matplotlib.pyplot as plt
import pathlib
import warnings
from decimal import Decimal
from motus import Funciones_Auxiliares as fa

warnings.filterwarnings("error")

matplotlib.use('TkAgg')


class Experimento:

    def __init__(self, nombre_archivo, dimension_caja=[100, 100], cantidad_filas=10, cantidad_columnas=10,
                 procesar_tiempo_archivo_irregular=False, puntos_importantes=None, objeto_a_promediar=1,
                 tamanio_intervalo_para_promedio=100, genera_matriz_recurrencia=False,
                 tamanio_cilindros=24, div_cilindros=2):
        self.nombre_archivo = nombre_archivo
        print("NOMBRE_ARCHIVO:", self.nombre_archivo, "\n TIPO_ARCHIVO:", type(self.nombre_archivo))
        self.dimension_caja = dimension_caja
        self.cantidad_filas = cantidad_filas
        self.cantidad_columnas = cantidad_columnas

        self.lista_de_indices_para_subsucesiones = None
        self.lista_ordenada_de_indices_mas_altos = None

        nombre_recortado = pathlib.Path(self.nombre_archivo)
        try:
            dataframe_a_recortar = pd.DataFrame(pd.read_csv(self.nombre_archivo,
                                                            header=None,
                                                            sep=',',
                                                            na_values='-',
                                                            usecols=[0],
                                                            engine='python',
                                                            ))
        except:
            try:
                dataframe_a_recortar = pd.DataFrame(pd.read_csv(self.nombre_archivo,
                                                                header=None,
                                                                sep=';',
                                                                na_values='-',
                                                                usecols=[0],
                                                                engine='python',
                                                                ))
            except:
                raise Exception('El archivo ', self.nombre_archivo,
                                'no es un archivo separado por comas o puntos y comas.')
        print("Obteniendo datos de csv...")
        df = dataframe_a_recortar
        print(df)
        print(df.values[0])
        try:
            inicio_datos = df.index[df[0] == 'Sample no.'].tolist()
            print("Los datos empiezan en la fila", inicio_datos)
            inicio_datos = inicio_datos[0]
            lista_filas = list(range(0, inicio_datos))
            print("Lista de filas:", lista_filas)
            self.datos = pd.DataFrame(pd.read_csv(self.nombre_archivo,
                                                  header=0,
                                                  na_values='-',
                                                  skiprows=lista_filas,
                                                  index_col=False))
            print("Datos procesados.")
        except:
            raise Exception('El archivo ', nombre_recortado.stem, 'no es compatible con motus.')

        print(self.datos)
        longitud_datos = len(self.datos)
        try:
            arreglo_samples = pd.to_numeric(self.datos['Sample no.'].tail(longitud_datos))
            arreglo_tiempo = pd.to_numeric(self.datos['Time'].tail(longitud_datos))
            arreglo_posicion_x = pd.to_numeric(self.datos['X'].tail(longitud_datos))
            arreglo_posicion_y = pd.to_numeric(self.datos['Y'].tail(longitud_datos))
            arreglo_consecuencias = pd.to_numeric(self.datos['Consecuences'].tail(longitud_datos))
        except:
            raise Exception('Alguno de los nombres de las columnas del CSV no es correcto. Esto podría ser por un'
                            ' espacio en blanco al principio del nombre.')

        print("--------------------------------------")

        print(arreglo_tiempo)
        print(arreglo_posicion_x)
        print(arreglo_posicion_y)

        if puntos_importantes is None:

            self.objeto_relevante_1 = [50, 0]
            self.objeto_relevante_2 = [0, 50]
            self.objeto_relevante_3 = [50, 100]
            self.objeto_relevante_4 = [100, 50]

        else:

            self.objeto_relevante_1 = puntos_importantes[0]
            self.objeto_relevante_2 = puntos_importantes[1]
            self.objeto_relevante_3 = puntos_importantes[2]
            self.objeto_relevante_4 = puntos_importantes[3]

        self.cantidad_posiciones_cilindros_1 = None
        self.cantidad_posiciones_cilindros_2 = None
        self.cantidad_posiciones_cilindros_3 = None
        self.cantidad_posiciones_cilindros_4 = None

        self.radios_cilindros = None

        self.distancia_a_objeto_promediado = None

        self.indice_region_objeto_1 = None
        self.indice_region_objeto_2 = None
        self.indice_region_objeto_3 = None
        self.indice_region_objeto_4 = None

        print(self.objeto_relevante_1)
        print(self.objeto_relevante_2)
        print(self.objeto_relevante_3)
        print(self.objeto_relevante_4)

        self.posiciones_x = arreglo_posicion_x
        self.posiciones_y = arreglo_posicion_y
        self.tiempo = arreglo_tiempo
        self.samples = arreglo_samples
        self.consecuencias = arreglo_consecuencias

        print("self.consecuencias: ", self.consecuencias)
        print(np.where(self.consecuencias == 1)[0])

        self.consecuencias_valores_1 = np.where(self.consecuencias == 1)[0]

        self.valor_intervalos_tiempo = arreglo_tiempo.iloc[1] - arreglo_tiempo.iloc[0]

        print("Procesar tiempo irregular: ", procesar_tiempo_archivo_irregular)

        if procesar_tiempo_archivo_irregular is False:
            if self.verifica_intervalo_tiempo() is False:
                raise Warning("Los intervalos entre frames del archivo son irregulares. Si desea continuar con el "
                              "procesamiento del archivo, active la casilla  \"Procesamiento tiempo irregular\". "
                              "Tenga presente que el procesamiento de datos estará basado en el valor medio del "
                              "total de frames. Le sugerimos explicitar que el procesamiento de datos se realizó "
                              "ajustando el valor de los intervalos entre frames a un valor medio, con base en el "
                              "siguiente cálculo: Intervalo = (Tiempo final - tiempo inicial)/total de registros")
        else:
            print("Llego aquí")
            self.genera_tiempos_regulares()

        print("2")

        self.distancia_total_recorrida = 0

        self.dist_objeto_1 = None
        self.dist_objeto_2 = None
        self.dist_objeto_3 = None
        self.dist_objeto_4 = None

        self.distancia_minima_objetos_2_3_4 = None
        self.distancia_minima_todos_objetos = None

        self.serie_velocidad = None
        self.serie_velocidad_promediada = None
        self.velocidad_maxima = None

        self.serie_aceleracion = None
        self.serie_aceleracion_promediada = None
        self.aceleracion_maxima = None

        self.arreglo_region_cuadriculada = None

        self.matriz_recurrencia_objeto_1 = None
        self.matriz_recurrencia_objeto_2 = None
        self.matriz_recurrencia_objeto_3 = None
        self.matriz_recurrencia_objeto_4 = None

        self.matriz_recurrencia_combinada = None

        self.matriz_recurrencia_region_cuadriculada = None
        self.matriz_cuadriculada = None

        print("Construcción de series de tiempo y de posición.")

        if self.posiciones_x.max() > dimension_caja[0]:
            raise Exception('Hay un dato en el eje X que es mayor que la dimensión de la caja. Valor: ',
                            self.posiciones_x.max())
        if self.posiciones_y.max() > dimension_caja[1]:
            raise Exception('Hay un dato en el eje Y que es mayor que la dimensión de la caja. Valor: ',
                            self.posiciones_y.max())

        self.realiza_procesamiento_MOTUS(objeto_a_promediar, tamanio_intervalo_para_promedio,
                                         genera_matriz_recurrencia)

        """
        self.reduce_elementos_sesion_con_modulo(tamanio=tamanio_de_subsucesiones,
                                                epsilon=epsilon,
                                                subsucesiones_iniciales=subsucesiones_iniciales,
                                                subsucesiones_aleatorias=subsucesiones_aleatorias)
        """

    def realiza_procesamiento_MOTUS(self, objeto, intervalo, genera_matriz_recurrencia):
        self.calcula_distancias()
        self.calcula_distancia_promediada_con_objeto(objeto, intervalo)
        self.calcula_velocidades()
        self.calcula_velocidades_promediadas()
        if genera_matriz_recurrencia is True:
            self.calcula_regiones_cuadriculadas()

    def verifica_intervalo_tiempo(self):
        arreglo_tiempo = self.tiempo
        valor = True
        nuevo_valor = 0
        print(arreglo_tiempo)
        for i in range(len(arreglo_tiempo)):
            print("Nuevo valor:", nuevo_valor)
            print("Valor a comparar:", arreglo_tiempo[i])
            if not nuevo_valor == arreglo_tiempo[i]:
                valor = False
                break
            nuevo_valor = round(nuevo_valor + self.valor_intervalos_tiempo, 3)
        print(valor)
        return valor

    def genera_tiempos_regulares(self):
        tiempo_a_utilizar = self.tiempo.values
        tiempo_total = len(tiempo_a_utilizar)
        tiempo_inicial = tiempo_a_utilizar[0]
        tiempo_final = tiempo_a_utilizar[-1]
        nuevos_tiempos = pd.Series(np.linspace(tiempo_inicial, tiempo_final, tiempo_total), name='Time')
        print(self.tiempo)
        print(nuevos_tiempos)
        self.tiempo = nuevos_tiempos

    def calcula_distancias(self):
        # Este método calcula las distancias dependiendo del tipo de experimento definido en el constructor, además de
        # obtener las distancias mínimas y la palanca asociada a la distancia.

        print("Cálculo de distancias...")

        posiciones_x = self.posiciones_x.copy()
        posiciones_y = self.posiciones_y.copy()

        objeto_1_x = self.objeto_relevante_1[0]
        objeto_1_y = self.objeto_relevante_1[1]

        objeto_2_x = self.objeto_relevante_2[0]
        objeto_2_y = self.objeto_relevante_2[1]

        objeto_3_x = self.objeto_relevante_3[0]
        objeto_3_y = self.objeto_relevante_3[1]

        objeto_4_x = self.objeto_relevante_4[0]
        objeto_4_y = self.objeto_relevante_4[1]

        self.dist_objeto_1 = ((objeto_1_x - posiciones_x) ** 2 + (objeto_1_y - posiciones_y) ** 2) ** 0.5
        self.dist_objeto_2 = ((objeto_2_x - posiciones_x) ** 2 + (objeto_2_y - posiciones_y) ** 2) ** 0.5
        self.dist_objeto_3 = ((objeto_3_x - posiciones_x) ** 2 + (objeto_3_y - posiciones_y) ** 2) ** 0.5
        self.dist_objeto_4 = ((objeto_4_x - posiciones_x) ** 2 + (objeto_4_y - posiciones_y) ** 2) ** 0.5

        print("Distancias calculadas.")

        self.distancia_minima_objetos_2_3_4 = np.minimum(self.dist_objeto_2,
                                                         np.minimum(self.dist_objeto_3, self.dist_objeto_4))
        self.distancia_minima_todos_objetos = np.minimum(self.dist_objeto_1, np.minimum(self.dist_objeto_2,
                                                                                        np.minimum(self.dist_objeto_3,
                                                                                                   self.dist_objeto_4)))

        longitud_distancias = len(posiciones_x)

        posiciones_x = posiciones_x.fillna(0)
        posiciones_y = posiciones_y.fillna(0)

        for i in range(1, longitud_distancias):
            self.distancia_total_recorrida = self.distancia_total_recorrida + \
                                             ((posiciones_x.iloc[i] - posiciones_x.iloc[i - 1]) ** 2 +
                                              (posiciones_y.iloc[i] - posiciones_y.iloc[i - 1]) ** 2) ** (1 / 2)

    def calcula_distancia_promediada_con_objeto(self, objeto, intervalo):
        arreglo_elegido = []
        if objeto is 1:
            arreglo_elegido = self.dist_objeto_1.tolist()
        elif objeto is 2:
            arreglo_elegido = self.dist_objeto_2.tolist()
        elif objeto is 3:
            arreglo_elegido = self.dist_objeto_3.tolist()
        elif objeto is 4:
            arreglo_elegido = self.dist_objeto_4.tolist()
        self.distancia_a_objeto_promediado = \
            fa.obtener_arreglo_con_valores_promediados_para_distancia_a_objeto(arreglo_elegido, intervalo)

    def calcula_velocidades(self):

        print("Calculando la velocidad y aceleración del ratón...")
        # valor_tiempo = self.valor_intervalos_tiempo

        tiempos = self.tiempo

        posiciones_x = self.posiciones_x
        posiciones_y = self.posiciones_y

        longitud_movimientos = len(posiciones_x)

        lista_velocidad = np.zeros(longitud_movimientos)
        for i in range(1, longitud_movimientos):

            valor_tiempo = tiempos[i] - tiempos[i - 1]

            if np.isnan(posiciones_x.iloc[i - 1]):
                lista_velocidad[i - 1] == 0
            elif np.isnan(posiciones_x.iloc[i]):
                lista_velocidad[i - 1] == 0
            else:
                lista_velocidad[i - 1] = (((posiciones_x.iloc[i] - posiciones_x.iloc[i - 1]) ** 2 + (
                        posiciones_y.iloc[i] - posiciones_y.iloc[i - 1]) ** 2) ** 0.5) / valor_tiempo
        self.serie_velocidad = pd.Series(lista_velocidad)
        self.velocidad_maxima = round(self.serie_velocidad.max(), 3)
        longitud_velocidad = len(lista_velocidad)
        lista_aceleracion = np.zeros(longitud_velocidad)
        for i in range(1, longitud_velocidad):
            valor_tiempo = tiempos[i] - tiempos[i - 1]
            lista_aceleracion[i - 1] = (self.serie_velocidad.iloc[i] - self.serie_velocidad.iloc[i - 1]) / valor_tiempo
        self.serie_aceleracion = pd.Series(lista_aceleracion)
        self.aceleracion_maxima = round(self.serie_aceleracion.max(), 3)
        print("Velocidad y aceleración del ratón calculdadas.")

    def calcula_velocidades_promediadas(self):
        longitud_serie_velocidad = len(self.serie_velocidad)
        longitud_serie_aceleracion = len(self.serie_aceleracion)
        if longitud_serie_velocidad % 5 > 0:
            x = 1
        else:
            x = 0
        longitud_serie_velocidad_promedio = int(longitud_serie_velocidad / 5 + x)
        lista_velocidad_promediada = np.zeros(longitud_serie_velocidad_promedio)
        for i in range(0, longitud_serie_velocidad_promedio - 1):
            for j in range(5):
                lista_velocidad_promediada[i] = lista_velocidad_promediada[i] + self.serie_velocidad.iloc[5 * i + j]
            lista_velocidad_promediada[i] = lista_velocidad_promediada[i] / 5
        for j in range(len(self.serie_velocidad) % 5):
            lista_velocidad_promediada[longitud_serie_velocidad_promedio - 1] = \
                self.serie_velocidad.iloc[5 * (longitud_serie_velocidad_promedio - 1) + j]
        self.serie_velocidad_promediada = pd.Series(lista_velocidad_promediada)
        if longitud_serie_aceleracion % 5 > 0:
            x = 1
        else:
            x = 0
        longitud_serie_aceleracion_promedio = int(longitud_serie_aceleracion / 5 + x)
        lista_aceleracion_promediada = np.zeros(longitud_serie_aceleracion_promedio)
        for i in range(0, longitud_serie_aceleracion_promedio - 1):
            # print(i)
            for j in range(5):
                lista_aceleracion_promediada[i] = lista_aceleracion_promediada[i] + self.serie_aceleracion.iloc[
                    5 * i + j]
            lista_aceleracion_promediada[i] = lista_aceleracion_promediada[i] / 5
            # print (longVelProm-1)
        for j in range(longitud_serie_aceleracion % 5):
            lista_aceleracion_promediada[longitud_serie_aceleracion_promedio - 1] = \
                self.serie_aceleracion.iloc[5 * (longitud_serie_aceleracion_promedio - 1) + j]
        self.serie_aceleracion_promediada = pd.Series(lista_aceleracion_promediada)

    def calcula_regiones_cuadriculadas(self):

        print("Calculando regiones en la caja...")

        posiciones_x = self.posiciones_x
        posiciones_y = self.posiciones_y

        cantidad_tiempos = len(self.tiempo)
        cantidad_filas = self.cantidad_filas
        cantidad_columnas = self.cantidad_columnas

        self.matriz_cuadriculada = np.zeros((cantidad_filas, cantidad_columnas))

        tamanio_horizontal = self.dimension_caja[0] / cantidad_columnas
        tamanio_vertical = self.dimension_caja[1] / cantidad_filas

        print("Tamaño de los cuadros: ", tamanio_horizontal, "x", tamanio_vertical)

        self.arreglo_region_cuadriculada = np.zeros(cantidad_tiempos)

        arreglo_region_cuadriculada = self.arreglo_region_cuadriculada

        longitud_matriz_recurrencia = len(arreglo_region_cuadriculada)

        self.matriz_recurrencia_region_cuadriculada = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))

        self.matriz_recurrencia_objeto_1 = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))
        self.matriz_recurrencia_objeto_2 = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))
        self.matriz_recurrencia_objeto_3 = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))
        self.matriz_recurrencia_objeto_4 = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))

        self.matriz_recurrencia_combinada = \
            np.zeros((longitud_matriz_recurrencia, longitud_matriz_recurrencia))

        for k in range(cantidad_tiempos):
            # print("Posicion de k:", k)

            if not (np.isnan(posiciones_x.iloc[k])) or not (np.isnan(posiciones_y.iloc[k])):

                posicion_x = posiciones_x.iloc[k]
                posicion_y = posiciones_y.iloc[k]
                # print("Indice:", k)
                if posicion_x == self.dimension_caja[0]:
                    # print(cantidad_columnas)
                    j = cantidad_columnas - 1
                    # print("Entro en opción 1-x")
                else:
                    # print("Entro en opcion 2-x")
                    j = int(posiciones_x.iloc[k] // tamanio_horizontal)
                if posicion_y == self.dimension_caja[1]:
                    # print(cantidad_filas)
                    i = cantidad_filas - 1
                    # print("Entro en opcion 1-y")
                else:
                    i = int(posiciones_y.iloc[k] // tamanio_vertical)
                    # print("Entro en opcion 2-y")
                # print("i: ", i)
                # print("j: ", j)
                self.matriz_cuadriculada[i][j] = self.matriz_cuadriculada[i][j] + 1
                arreglo_region_cuadriculada[k] = cantidad_columnas * i + j

        self.obtener_indice_regiones_objeto()

        for i in range(cantidad_tiempos):
            valor = arreglo_region_cuadriculada[i]
            for j in range(cantidad_tiempos):
                if valor == arreglo_region_cuadriculada[j]:
                    self.matriz_recurrencia_region_cuadriculada[i][j] = 1
                    if valor == self.indice_region_objeto_1:
                        print("Entro en 1")
                        self.matriz_recurrencia_objeto_1[i][j] = 1
                        self.matriz_recurrencia_combinada[i][j] = 1
                    if valor == self.indice_region_objeto_2:
                        print("Entro en 2")
                        self.matriz_recurrencia_objeto_2[i][j] = 1
                        self.matriz_recurrencia_combinada[i][j] = 2
                    if valor == self.indice_region_objeto_3:
                        print("Entro en 3")
                        self.matriz_recurrencia_objeto_3[i][j] = 1
                        self.matriz_recurrencia_combinada[i][j] = 3
                    if valor == self.indice_region_objeto_4:
                        print("Entro en 4")
                        self.matriz_recurrencia_objeto_4[i][j] = 1
                        self.matriz_recurrencia_combinada[i][j] = 4

        self.matriz_cuadriculada = np.flipud(self.matriz_cuadriculada)

        print(self.matriz_cuadriculada)

    def calcula_alturas_cilindros_objetos_relevantes(self, tamanio=24, divisiones=2):
        longitud_movimientos = len(self.posiciones_x)
        valor_min_divivido = int(tamanio / divisiones)
        radios_cilindros = list(range(valor_min_divivido, tamanio + 1, valor_min_divivido))
        cantidad_posiciones_cilindros_1 = list(np.zeros(len(radios_cilindros)))
        cantidad_posiciones_cilindros_2 = list(np.zeros(len(radios_cilindros)))
        cantidad_posiciones_cilindros_3 = list(np.zeros(len(radios_cilindros)))
        cantidad_posiciones_cilindros_4 = list(np.zeros(len(radios_cilindros)))
        for i in range(0, longitud_movimientos):
            x_pos = self.posiciones_x[i]
            y_pos = self.posiciones_y[i]
            dist_1 = fa.calcula_distancia_entre_puntos(self.objeto_relevante_1[0], x_pos, self.objeto_relevante_1[1],
                                                    y_pos)
            dist_2 = fa.calcula_distancia_entre_puntos(self.objeto_relevante_2[0], x_pos, self.objeto_relevante_2[1],
                                                    y_pos)
            dist_3 = fa.calcula_distancia_entre_puntos(self.objeto_relevante_3[0], x_pos, self.objeto_relevante_3[1],
                                                    y_pos)
            dist_4 = fa.calcula_distancia_entre_puntos(self.objeto_relevante_4[0], x_pos, self.objeto_relevante_4[1],
                                                    y_pos)
            if dist_1 < tamanio:
                cantidad_posiciones_cilindros_1 = fa.modificar_lista_para_cilindros(cantidad_posiciones_cilindros_1,
                                                                                    radios_cilindros,
                                                                                    dist_1)
            if dist_2 < tamanio:
                cantidad_posiciones_cilindros_2 = fa.modificar_lista_para_cilindros(cantidad_posiciones_cilindros_2,
                                                                                    radios_cilindros,
                                                                                    dist_2)
            if dist_3 < tamanio:
                cantidad_posiciones_cilindros_3 = fa.modificar_lista_para_cilindros(cantidad_posiciones_cilindros_3,
                                                                                    radios_cilindros,
                                                                                    dist_3)
            if dist_4 < tamanio:
                cantidad_posiciones_cilindros_4 = fa.modificar_lista_para_cilindros(cantidad_posiciones_cilindros_4,
                                                                                    radios_cilindros,
                                                                                    dist_4)

        print("Cantidad de posiciones para cilindro 1:")
        print(cantidad_posiciones_cilindros_1)
        print("Cantidad de posiciones para cilindro 2:")
        print(cantidad_posiciones_cilindros_2)
        print("Cantidad de posiciones para cilindro 3:")
        print(cantidad_posiciones_cilindros_3)
        print("Cantidad de posiciones para cilindro 4:")
        print(cantidad_posiciones_cilindros_4)

        self.cantidad_posiciones_cilindros_1 = cantidad_posiciones_cilindros_1
        self.cantidad_posiciones_cilindros_2 = cantidad_posiciones_cilindros_2
        self.cantidad_posiciones_cilindros_3 = cantidad_posiciones_cilindros_3
        self.cantidad_posiciones_cilindros_4 = cantidad_posiciones_cilindros_4
        self.radios_cilindros = radios_cilindros

    def obtener_indice_regiones_objeto(self):
        lista_objetos_relevantes = [self.objeto_relevante_1,
                                    self.objeto_relevante_2,
                                    self.objeto_relevante_3,
                                    self.objeto_relevante_4]

        cantidad_filas = self.cantidad_filas
        cantidad_columnas = self.cantidad_columnas

        tamanio_horizontal = self.dimension_caja[0] / cantidad_columnas
        tamanio_vertical = self.dimension_caja[1] / cantidad_filas

        for objeto in lista_objetos_relevantes:

            posicion_x = objeto[0]
            posicion_y = objeto[1]

            if posicion_x == self.dimension_caja[0]:
                j = cantidad_columnas - 1
            else:
                j = posicion_x // tamanio_horizontal
            if posicion_y == self.dimension_caja[1]:
                i = cantidad_filas - 1
            else:
                i = posicion_y // tamanio_vertical

            if self.indice_region_objeto_1 is None:
                self.indice_region_objeto_1 = cantidad_columnas * i + j
            elif self.indice_region_objeto_2 is None:
                self.indice_region_objeto_2 = cantidad_columnas * i + j
            elif self.indice_region_objeto_3 is None:
                self.indice_region_objeto_3 = cantidad_columnas * i + j
            elif self.indice_region_objeto_4 is None:
                self.indice_region_objeto_4 = cantidad_columnas * i + j

        print("Región de objeto 1: ", self.indice_region_objeto_1)
        print("Región de objeto 2: ", self.indice_region_objeto_2)
        print("Región de objeto 3: ", self.indice_region_objeto_3)
        print("Región de objeto 4: ", self.indice_region_objeto_4)
        print("-------------------------------------------------------------------")

    def genera_modulo_para_reducir_sesiones(self):

        cantidad_filas = self.cantidad_filas

        cantidad_columnas = self.cantidad_columnas

        tamanio_horizontal = self.dimension_caja[0] / cantidad_columnas

        print("Tamaño horizontal:", tamanio_horizontal)

        velocidad_promedio = self.serie_velocidad.mean()

        print("Velocidad promedio", velocidad_promedio)

        nominador = tamanio_horizontal / velocidad_promedio

        print("Nominador:", nominador)

        modulo = nominador / 0.2

        print("Modulo:", modulo)

        return int(modulo)

    def obtener_coeficientes_de_regiones_mas_visitadas(self, cantidad_indices_a_obtener):
        matriz_regiones_aplastada = np.flipud(self.matriz_cuadriculada).flatten()
        regiones_mas_visitadas = np.argpartition(matriz_regiones_aplastada, -cantidad_indices_a_obtener)
        regiones_mas_visitadas = regiones_mas_visitadas[-(cantidad_indices_a_obtener + 1):]
        valores_mas_altos = matriz_regiones_aplastada[regiones_mas_visitadas]
        lista_ordenada_de_indices_mas_altos = [x for y, x in sorted(zip(valores_mas_altos, regiones_mas_visitadas))]
        print("Lista ordenada de indices mas altos",
              lista_ordenada_de_indices_mas_altos[(cantidad_indices_a_obtener + 1):0:-1])
        return lista_ordenada_de_indices_mas_altos[(cantidad_indices_a_obtener + 1):0:-1]

    def crea_sucesiones_a_evaluar(self, arreglo_de_subsucesiones, tamanio_de_subsucesiones):
        copia_sucesion_original = arreglo_de_subsucesiones.copy()
        lista_resultado_final = []
        lista_indices_final = []
        for i in range(0, len(copia_sucesion_original) - tamanio_de_subsucesiones):
            lista_resultado_final.append(copia_sucesion_original[i:(i + tamanio_de_subsucesiones)])
            lista_indices_final.append(
                list(range(self.modulo * i, self.modulo * (i + tamanio_de_subsucesiones), self.modulo)))
        print("Subsucesiones formadas: ", lista_resultado_final)
        print("indices_correspondientes", lista_indices_final)
        return lista_resultado_final, lista_indices_final

    def obtener_indices_subsucesiones_iniciales_para_distancias(self, cantidad_indices_a_obtener):
        lista_de_indices_de_subsucesiones_iniciales = []
        print("Obteniendo índices más altos...")
        if self.lista_ordenada_de_indices_mas_altos is None:
            print("Calculando nueva lista de índices más altos.")
            self.lista_ordenada_de_indices_mas_altos = self.obtener_coeficientes_de_regiones_mas_visitadas(
                cantidad_indices_a_obtener)
        print("Lista ordenada de índices más altos: ", self.lista_ordenada_de_indices_mas_altos)
        for indice in self.lista_ordenada_de_indices_mas_altos:
            for i in range(len(self.lista_con_subsucesiones)):
                subsucesion = self.lista_con_subsucesiones[i]
                if subsucesion[0] == indice:
                    lista_de_indices_de_subsucesiones_iniciales.append(i)
                    break
        self.lista_de_indices_para_subsucesiones = lista_de_indices_de_subsucesiones_iniciales

    def reduce_elementos_sesion_con_modulo(self,
                                           tamanio,
                                           epsilon,
                                           subsucesiones_iniciales,
                                           subsucesiones_aleatorias,
                                           multiples_sesiones=False):
        self.modulo = self.genera_modulo_para_reducir_sesiones()
        self.tamanio = tamanio
        self.serie_a_utilizar = pd.Series(self.arreglo_region_cuadriculada)
        self.serie_a_utilizar = self.serie_a_utilizar[self.serie_a_utilizar.index % self.modulo == 0]
        print(self.serie_a_utilizar)
        arreglo_a_utilizar = self.serie_a_utilizar.to_numpy()
        self.calcula_distancias_entre_subsucesiones_aleatorias(tamanio_de_subsucesiones=tamanio,
                                                               epsilon=epsilon,
                                                               cantidad_subgrupos_sucesiones=subsucesiones_iniciales,
                                                               subsucesiones_aleatorias=subsucesiones_aleatorias,
                                                               arreglo_reducido_con_modulo=arreglo_a_utilizar)
        if multiples_sesiones is False:
            self.grafica_subsucesiones_parecidas(modulo=self.modulo, tamanio=self.tamanio)

    def grafica_subsucesiones_parecidas(self, modulo, tamanio):
        lista_colores = ["blue", "red", "green", "orange", "purple", "cyan", "magenta", "brown", "pink", "gray"]
        print(self.lista_indices_subsucesiones_parecidas)
        plt.clf()
        for i in range(len(self.lista_indices_subsucesiones_parecidas)):
            sublista_indice = self.lista_indices_subsucesiones_parecidas[i]
            print(sublista_indice)
            color = lista_colores[i]
            for j in range(len(sublista_indice)):
                indice_de_subsucesion = sublista_indice[j]
                valores = list(range(modulo * indice_de_subsucesion, modulo * indice_de_subsucesion + modulo * tamanio))
                plt.plot(self.posiciones_x[valores], self.posiciones_y[valores], color=color)
        plt.xlim(0, self.dimension_caja[0])
        plt.ylim(0, self.dimension_caja[1])
        plt.grid(True)
        plt.show()

    def calcula_distancias_entre_subsucesiones_aleatorias(self, tamanio_de_subsucesiones, epsilon,
                                                          cantidad_subgrupos_sucesiones,
                                                          subsucesiones_aleatorias,
                                                          arreglo_reducido_con_modulo=None):

        print(arreglo_reducido_con_modulo)

        if arreglo_reducido_con_modulo is None:
            arreglo_reducido_con_modulo = self.arreglo_region_cuadriculada

        self.lista_con_subsucesiones, self.lista_con_trazo_de_subsucesiones = self.crea_sucesiones_a_evaluar(
            arreglo_reducido_con_modulo,
            tamanio_de_subsucesiones)

        lista_de_indices_de_subsucesiones = list(range(0, len(self.lista_con_subsucesiones)))

        if subsucesiones_aleatorias == True:
            self.lista_de_indices_para_subsucesiones = random.sample(lista_de_indices_de_subsucesiones,
                                                                     cantidad_subgrupos_sucesiones)
        else:
            self.obtener_indices_subsucesiones_iniciales_para_distancias(cantidad_subgrupos_sucesiones)

        print("Subsucesiones iniciales elegidas: ", self.lista_de_indices_para_subsucesiones)

        lista_con_subsucesiones_aleatorias = []
        self.lista_indices_subsucesiones_parecidas = []

        print(self.lista_de_indices_para_subsucesiones)

        for i in self.lista_de_indices_para_subsucesiones:
            lista_con_subsucesiones_aleatorias.append(self.lista_con_subsucesiones[i])
            self.lista_indices_subsucesiones_parecidas.append([i])

        self.lista_dataframes_subsucesiones_parecidas = []

        print("Lista con subsucesiobes aleatorias: ", lista_con_subsucesiones_aleatorias)

        for i in range(len(self.lista_de_indices_para_subsucesiones)):
            self.lista_dataframes_subsucesiones_parecidas.append(pd.DataFrame())
            sucesion_a_comparar = lista_con_subsucesiones_aleatorias[i]
            dataframe_de_sucesion_a_comparar = self.lista_dataframes_subsucesiones_parecidas[i]
            dataframe_de_sucesion_a_comparar[0] = sucesion_a_comparar

            for j in range(len(self.lista_con_subsucesiones)):
                if j != self.lista_de_indices_para_subsucesiones[i]:
                    sucesion_nueva = self.lista_con_subsucesiones[j]
                    se_encontro_epsilon = self.distancia_entre_sucesiones(sucesion_a_comparar, sucesion_nueva, epsilon)
                    if se_encontro_epsilon:
                        dataframe_de_sucesion_a_comparar[len(dataframe_de_sucesion_a_comparar.columns)] = \
                            sucesion_nueva
                        self.lista_indices_subsucesiones_parecidas[i].append(j)

    """
    def calcula_distancias_entre_subsucesiones(self, tamanio, epsilon):
        lista_con_subsucesiones = self.crea_sucesiones_a_evaluar(tamanio)
        for i in range(len(lista_con_subsucesiones)):
            dataframe_subsucesiones_parecidas = pd.DataFrame()
            indices = [i]
            sucesion_1 = lista_con_subsucesiones[i]
            print(sucesion_1)
            dataframe_subsucesiones_parecidas[0] = sucesion_1
            print("Indice:", i)
            print(dataframe_subsucesiones_parecidas)
            for j in range(i+(tamanio-1), len(lista_con_subsucesiones)):
                sucesion_2 = lista_con_subsucesiones[j]
                se_encontro_epsilon = self.distancia_entre_sucesiones(sucesion_1, sucesion_2, epsilon)
                if se_encontro_epsilon:
                    dataframe_subsucesiones_parecidas[len(dataframe_subsucesiones_parecidas.columns)+1] = sucesion_2
                    print(dataframe_subsucesiones_parecidas)
                    indices.append(j)
                    print("Indice:", j)
            print("Se termina de buscar subsucesiones.")
            if len(dataframe_subsucesiones_parecidas.columns) > 1:
                break
        print("Indices de subsucesiones: ", indices)
        print("Dataframe resultante")
        print(dataframe_subsucesiones_parecidas)
    """

    def calcula_distancias_entre_sucesiones(self, brinco, epsilon=1):
        print("---------------------------------------------------------------")
        copia_sucesion_original = self.arreglo_region_cuadriculada.copy()
        for i in range(0, len(copia_sucesion_original), brinco):
            copia_segunda_sucesion = copia_sucesion_original.copy()
            for j in range(0, len(copia_segunda_sucesion), brinco):
                self.funcion_sigma_sucesion_2(copia_segunda_sucesion, j)
                se_encontro_epsilon = self.distancia_entre_sucesiones(copia_sucesion_original,
                                                                      copia_segunda_sucesion,
                                                                      epsilon)
                if se_encontro_epsilon:
                    break
            if se_encontro_epsilon:
                break
            else:
                copia_sucesion_original = self.funcion_sigma_sucesion_1(copia_sucesion_original, brinco)
        print("Las sucesiones similares son: ")
        print(copia_sucesion_original)
        print(copia_segunda_sucesion)

    def funcion_sigma_sucesion_1(self, sucesion, brinco):
        copia_sucesion = sucesion.copy()
        if (len(copia_sucesion) >= brinco):
            for i in range(0, brinco):
                copia_sucesion = np.delete(copia_sucesion, 0)
        else:
            return []
        return copia_sucesion

    def funcion_sigma_sucesion_2(self, sucesion, indice):
        sucesion[indice] = 0

    def distancia_entre_sucesiones(self, sucesion_1, sucesion_2, epsilon):
        operacion = 0
        total_de_regiones_en_sucesion = len(set(sucesion_1))
        for n in range(len(sucesion_1)):
            operacion += abs(Decimal(sucesion_1[n]) - Decimal(sucesion_2[n])) / (Decimal(2 ** n))
        if (operacion < epsilon):
            return True
        else:
            return False

    def genera_dataframe_de_datos(self):
        diccionario_csv = {'Sample no.': self.samples,
                           'Time': self.tiempo,
                           'X': self.posiciones_x,
                           'Y': self.posiciones_y,
                           'Obj_Dist_1': self.dist_objeto_1,
                           'Obj_Dist_Prom_1': self.distancia_a_objeto_promediado,
                           'Obj_Dist_2': self.dist_objeto_2,
                           'Obj_Dist_3': self.dist_objeto_3,
                           'Obj_Dist_4': self.dist_objeto_4,
                           'Obj_Dist_Min_2_3_4': self.distancia_minima_objetos_2_3_4,
                           'Velocity': self.serie_velocidad,
                           'Acceleration': self.serie_aceleracion}
        tabla_csv = pd.DataFrame(diccionario_csv)
        print(diccionario_csv)
        return tabla_csv

    def exporta_csv(self, nombre):

        tabla_csv = self.genera_dataframe_de_datos()

        print(tabla_csv)

        tabla_csv.to_csv(nombre, index=None)

    def exporta_estadisticas(self, nombre):
        data = {'1': ['Max_Vel', 'Max_Accel', 'Total_Dist', 'Recurrence Matrix'],
                '2': [round(self.velocidad_maxima, 3), round(self.aceleracion_maxima, 3),
                      round(self.distancia_total_recorrida, 3),
                      '']}
        data = pd.DataFrame(data)
        datos_a_exportar = data.append(pd.DataFrame(np.flipud(self.matriz_recurrencia_region_cuadriculada)))
        print(datos_a_exportar)
        print('Aquí voy bien')
        data_para_matriz_tiempos = {'1': ['Time_in_Region_Matrix']}
        data_para_matriz_tiempos = pd.DataFrame(data_para_matriz_tiempos)
        data_para_matriz_tiempos = data_para_matriz_tiempos.append(pd.DataFrame(self.matriz_cuadriculada))
        print("------------------------------------------------------------------------")
        print(data_para_matriz_tiempos)
        datos_a_exportar = datos_a_exportar.append(data_para_matriz_tiempos)
        print("------------------------------------------------------------------------")
        print(datos_a_exportar)
        pd.DataFrame(datos_a_exportar).to_csv(nombre, header=None, index=None)

    def exporta_estadisticas_2(self, nombre):
        data = {'1': ['Max_Vel',
                      'Max_Accel',
                      'Total_Dist',
                      'Recurrence_Matrix',
                      '',
                      'Time_in_region_Matrix'],
                '2': [round(self.velocidad_maxima, 3),
                      round(self.aceleracion_maxima, 3),
                      round(self.distancia_total_recorrida, 3),
                      pd.DataFrame(np.flipud(self.matriz_recurrencia_region_cuadriculada), columns=None, index=None),
                      '',
                      pd.DataFrame(self.matriz_cuadriculada, columns=None, index=None)
                      ]}
        data = pd.DataFrame(data)
        data.to_csv(nombre, header=None, index=None)

    def exporta_matriz_tiempo_regiones(self, nombre):
        data = pd.DataFrame(self.matriz_cuadriculada, columns=None, index=None)
        data.to_csv(nombre, header=None, index=None)

    def grafica(self, grafica, lim_inf_x=None, lim_sup_x=None, lim_inf_y=None, lim_sup_y=None,
                tamanio_vectores=100, brinco_temporal=int(1), consencuencia_elegida=None,
                tamanio_cilindros=24, div_cilindros=2, arreglo_grafica_distancias=[True, True, True, True],
                rotacion_grafica_3d=220):

        print("-----------------------------------------------------------")
        print("Tipo de gráfica", grafica)

        print("Valores de límites de gráfica:", lim_inf_x, lim_sup_x, lim_inf_y, lim_sup_y)

        fig = Figure(figsize=(6, 6))
        plt = fig.add_subplot(111)
        plt.grid(True)

        if grafica is not 'region_cuadricula_3d':
            if lim_inf_x is not None and lim_sup_x is not None:
                plt.set_xlim(lim_inf_x, lim_sup_x)
            if lim_inf_y is not None and lim_sup_y is not None:
                plt.set_ylim(lim_inf_y, lim_sup_y)

        if grafica == 'subrutas':
            # print("----------------------------------------------------------------")
            # print("Graficando subrutas: ")
            lista_colores = ["blue", "red", "green", "orange", "purple", "cyan", "magenta", "brown", "pink", "gray"]
            # print("Lista total de subsucesiones parecidas:", self.lista_indices_subsucesiones_parecidas)
            for i in range(len(self.lista_indices_subsucesiones_parecidas)):
                conjunto_subsucesiones_similares = self.lista_indices_subsucesiones_parecidas[i]
                # print("Sucesiones parecidas: ", conjunto_subsucesiones_similares)
                color = lista_colores[i]
                """

                """
                punto_inicial = False
                for subsucesion in conjunto_subsucesiones_similares:
                    trazo_subsucesion_actual = self.lista_con_trazo_de_subsucesiones[subsucesion]
                    if punto_inicial is False:
                        plt.scatter(self.posiciones_x[trazo_subsucesion_actual[0]],
                                    self.posiciones_y[trazo_subsucesion_actual[0]],
                                    s=50, edgecolors="black", color=color)
                        punto_inicial = True
                    print("Subsucesion actual: ", subsucesion)
                    print("List con trazo de subsucesiones: ", trazo_subsucesion_actual)
                    """
                    valores = list(
                        range(self.modulo * indice_de_subsucesion, self.modulo * indice_de_subsucesion + self.modulo * self.tamanio))
                    """
                    plt.plot(self.posiciones_x[trazo_subsucesion_actual],
                             self.posiciones_y[trazo_subsucesion_actual],
                             color=color)
            plt.set_xlim(0, self.dimension_caja[0])
            plt.set_ylim(0, self.dimension_caja[1])

        if grafica == 'ruta':
            print("Entro a ruta")

            if (lim_inf_x is None) and (lim_sup_x is None):
                plt.set_xlim(0, self.dimension_caja[0])
            if (lim_inf_y is None) and (lim_sup_y is None):
                plt.set_ylim(0, self.dimension_caja[1])
            plt.plot(self.posiciones_x, self.posiciones_y, color='blue')
            plt.plot(self.objeto_relevante_1[0], self.objeto_relevante_1[1], '*', color='blue')
            plt.plot(self.objeto_relevante_2[0], self.objeto_relevante_2[1], 'o', color='green')
            plt.plot(self.objeto_relevante_3[0], self.objeto_relevante_3[1], 'o', color='red')
            plt.plot(self.objeto_relevante_4[0], self.objeto_relevante_4[1], 'o', color='orange')

        if grafica == 'ruta_vectores':

            print("Brinco temporal: ", brinco_temporal)
            print("Tamanio vectores: ", tamanio_vectores)
            print("Consecuencia elegida:", consencuencia_elegida)

            x_pos_antes_consecuencia = self.posiciones_x.tolist()
            y_pos_antes_consecuencia = self.posiciones_y.tolist()

            x_pos_despues_consecuencia = self.posiciones_x.tolist()
            y_pos_despues_consecuencia = self.posiciones_y.tolist()

            x_pos_antes_consecuencia = x_pos_antes_consecuencia[int(consencuencia_elegida - tamanio_vectores):
                                                                int(consencuencia_elegida):
                                                                int(brinco_temporal)]

            y_pos_antes_consecuencia = y_pos_antes_consecuencia[int(consencuencia_elegida - tamanio_vectores):
                                                                int(consencuencia_elegida):
                                                                int(brinco_temporal)]

            print("Tamanios iguales : ", len(x_pos_antes_consecuencia) == len(y_pos_antes_consecuencia))

            x_pos_despues_consecuencia = x_pos_despues_consecuencia[int(consencuencia_elegida):
                                                                    int(consencuencia_elegida + tamanio_vectores):
                                                                    int(brinco_temporal)]
            y_pos_despues_consecuencia = y_pos_despues_consecuencia[int(consencuencia_elegida):
                                                                    int(consencuencia_elegida + tamanio_vectores):
                                                                    int(brinco_temporal)]

            new_x_pos_antes = x_pos_antes_consecuencia.copy()
            new_x_pos_antes.append(self.posiciones_x[consencuencia_elegida])
            new_y_pos_antes = y_pos_antes_consecuencia.copy()
            new_y_pos_antes.append(self.posiciones_y[consencuencia_elegida])

            x_direct_antes, y_direct_antes = fa.obtener_vectores_posicion_flechas(new_x_pos_antes,
                                                                                  new_y_pos_antes)

            print("x_pos_antes_consecuencia: ", x_pos_antes_consecuencia)
            print("y_pos_antes_consecuencia: ", y_pos_antes_consecuencia)

            print("x_direct_antes: ", x_direct_antes)
            print("y_direct_antes: ", y_direct_antes)

            x_direct_despues, y_direct_despues = fa.obtener_vectores_posicion_flechas(x_pos_despues_consecuencia,
                                                                                      y_pos_despues_consecuencia)

            print("-----------------------------------------------------------")

            print("x_pos_despues_consecuencia: ", x_pos_despues_consecuencia)
            print("y_pos_antes_consecuencia: ", y_pos_despues_consecuencia)

            print("x_direct_despues: ", x_direct_despues)
            print("y_direct_despues: ", y_direct_despues)

            plt.quiver(x_pos_antes_consecuencia, y_pos_antes_consecuencia,
                       x_direct_antes, y_direct_antes,
                       angles='xy', scale_units='xy', scale=1, color='blue')
            plt.quiver(x_pos_despues_consecuencia[:-1], y_pos_despues_consecuencia[:-1],
                       x_direct_despues, y_direct_despues,
                       angles='xy', scale_units='xy', scale=1, color='red')
            plt.set_xlim(0, self.dimension_caja[0])
            plt.set_ylim(0, self.dimension_caja[1])

        elif grafica == 'distancias':
            print("Entro a distancias")
            lista_valores_minimos = []
            lista_valores_maximos = []
            if arreglo_grafica_distancias[0] is True:
                print(1)
                print(self.dist_objeto_1)
                print(self.dist_objeto_1.max())
                plt.plot(self.tiempo, self.dist_objeto_1, color='blue', label='Objeto 1')
                lista_valores_minimos.append(self.dist_objeto_1.min())
                lista_valores_maximos.append(self.dist_objeto_1.max())
            if arreglo_grafica_distancias[1] is True:
                print(2)
                print(self.dist_objeto_2)
                print(self.dist_objeto_2.max())
                plt.plot(self.tiempo, self.dist_objeto_2, color='green', label='Objeto 2')
                lista_valores_minimos.append(self.dist_objeto_2.min())
                lista_valores_maximos.append(self.dist_objeto_2.max())
            if arreglo_grafica_distancias[2] is True:
                print(3)
                print(self.dist_objeto_3)
                print(self.dist_objeto_3.max())
                plt.plot(self.tiempo, self.dist_objeto_3, color='red', label='Objeto 3')
                lista_valores_minimos.append(self.dist_objeto_3.min())
                lista_valores_maximos.append(self.dist_objeto_3.max())
            if arreglo_grafica_distancias[3] is True:
                print(4)
                print(self.dist_objeto_4)
                print(self.dist_objeto_4.max())
                plt.plot(self.tiempo, self.dist_objeto_4, color='orange', label='Objeto 4')
                lista_valores_minimos.append(self.dist_objeto_4.min())
                lista_valores_maximos.append(self.dist_objeto_4.max())
            y_min = min(lista_valores_minimos)
            y_max = max(lista_valores_maximos)

            if lim_inf_y is None and lim_sup_y is None:
                plt.set_ylim(y_min, y_max + 30)

            # plt.legend()

        elif grafica == 'dist_prom':
            print("Entro a distancia promediada a objeto")

            if lim_inf_y is None and lim_sup_y is None:
                plt.set_ylim(min(self.dist_objeto_1), max(self.dist_objeto_1) + 5)

            plt.plot(self.tiempo, self.dist_objeto_1, linestyle=':', color='gray', label='Distancia original')
            plt.plot(self.tiempo, self.distancia_a_objeto_promediado, color='red',
                     label='Distancia a objeto promediado')

            # plt.legend()

        elif grafica == 'dist_min':

            print("Entro a dist_min")

            if lim_inf_y is None and lim_sup_y is None:
                plt.set_ylim(min(self.distancia_minima_objetos_2_3_4.min(), self.dist_objeto_1.min()),
                             max(self.distancia_minima_objetos_2_3_4.max(), self.dist_objeto_1.max()) + 30)

            plt.plot(self.tiempo, self.distancia_minima_objetos_2_3_4, color='red', label='Resto de objetos')
            plt.plot(self.tiempo, self.dist_objeto_1, color='blue', label='Objeto 1')

            # plt.legend()

        elif grafica == 'vel':

            print("Entro a vel")
            plt.scatter(self.tiempo, self.serie_velocidad, s=1)

        elif grafica == 'vel_prom':
            print("Entro a vel_prom")
            longitud_serie_velocidad_promediada = len(self.serie_velocidad_promediada)
            tiempo = np.linspace(0, longitud_serie_velocidad_promediada, longitud_serie_velocidad_promediada)
            plt.scatter(tiempo, self.serie_velocidad_promediada, s=1)

        elif grafica == 'vel_hist':
            print("Entro a vel_hist")
            print(plt.hist(self.serie_velocidad))
            plt.hist(self.serie_velocidad)

        elif grafica == 'acel':

            print("Entro a acel")
            plt.scatter(self.tiempo, self.serie_aceleracion, s=1)

        elif grafica == 'acel_prom':

            # Se hace el cálculo de la velocidad en cada momento del tiempo
            # v_{t-1} = [((x_i - x_{i-1})^2 + (y_i - y_{i-1})^2)^(1/2)]/0.2
            # y se grafica sobre el tiempo.
            print("Entro a acelPrm")
            longitud_serie_aceleracion_promediada = len(self.serie_aceleracion_promediada)
            tiempo = np.linspace(0, longitud_serie_aceleracion_promediada, longitud_serie_aceleracion_promediada)
            plt.scatter(tiempo, self.serie_aceleracion_promediada, s=1)

        # elif grafica == 'distPeso':
        #    print("Entro a distPeso")
        #    plt.plot(self.t, self.distPeso, color='black')

        # Usa la distancia mínima a las palancas y grafica 1 si estuvo más próxima a la palanca 1,
        # 2 si estuvo más próxima a la palanca 2 y 3 si estuvo más próxima a la palanca 3.

        # elif grafica == 'clasePalanca':
        #    plt.set_ylim(0.8, 3.2)
        #    plt.scatter(self.t.values, self.claseMinPalanca.values, s=5, c='black')

        # Similar a la gráfica 'clasePalanca', pero agregando la distancia mínima al comedero y usando 0 para
        # graficarla.

        # elif grafica == 'claseTodoPalanca':
        #    plt.set_ylim(-0.2, 3.2)
        #    plt.scatter(self.t.values, self.claseMinTodo.values, s=5, c='black')

        # elif grafica == 'claseRegionesExtendidas':
        #    r_1 = 0
        #    r_2 = 0
        #    suma_total = self.regionesFrecAc['Frecuencia'].sum()
        #    for i in range(len(self.regionesFrecAc)):
        #        r_1 = r_2
        #        r_2 = ((self.regionesFrecAc['Frecuencia'].iloc[i]) / suma_total) + r_1
        #        plt.plot(np.array([r_1, r_2]),
        #                 np.array([self.regionesFrecAc['Región'].iloc[i], self.regionesFrecAc['Región'].iloc[i]]),
        #                 color='blue')
        #    plt.set_ylim(-1.2, 3.2)

        # elif grafica == 'aceleraciónRegiones':
        #    plt.plot(np.arange(1, (len(self.regionesFrecAc)), 1), self.acelRegiones)

        # elif grafica == 'cambioRegiones/Acel':
        #    plt.set_ylim(-0.2, 3.2)
        #    plt.scatter(np.arange(0, len(self.regionesFrecAc['Región'])), self.regionesFrecAc['Región'], s=5, c='black')
        #    plt.plot(np.arange(1, (len(self.regionesFrecAc)), 1), coeficiente * self.acelRegiones, '-', color='red')

        # elif grafica == 'matriz_recurrencia':
        #    plt.grid(False)
        #    plt.imshow(self.matrizRec, cmap='gray', interpolation='nearest', vmin=0, vmax=5)
        #    plt.legend()

        elif grafica == 'matriz_recurrencia_cuadriculada':
            plt.grid(False)
            plt.imshow(-1 * self.matriz_recurrencia_region_cuadriculada, origin='lower', cmap='gray',
                       interpolation='nearest', vmin=-1, vmax=0)

        elif grafica == 'matriz_recurrencia_cuadriculada_objeto_1':

            plt.grid(False)
            plt.imshow(-1 * self.matriz_recurrencia_region_cuadriculada, origin='lower', cmap='gray',
                       interpolation='nearest', vmin=-1, vmax=0)
            plt.imshow(-1 * self.matriz_recurrencia_objeto_1, origin='lower', cmap='gray',
                       interpolation='nearest', vmin=-1, vmax=0)

        elif grafica == 'matriz_recurrencia_cuadriculada_objeto_2':
            plt.grid(False)
            plt.imshow(-1 * self.matriz_recurrencia_objeto_2, origin='lower', cmap='gray',
                       interpolation='nearest')

        elif grafica == 'matriz_recurrencia_cuadriculada_objeto_3':
            plt.grid(False)
            plt.imshow(-1 * self.matriz_recurrencia_objeto_3, origin='lower', cmap='gray',
                       interpolation='nearest')

        elif grafica == 'matriz_recurrencia_cuadriculada_objeto_4':
            plt.grid(False)
            plt.imshow(-1 * self.matriz_recurrencia_objeto_4, origin='lower', cmap='gray',
                       interpolation='nearest')

        elif grafica == 'matriz_recurrencia_cuadriculada_combinada':
            plt.grid(False)
            nueva_matriz_recurrencia_combinada = self.matriz_recurrencia_combinada + self.matriz_recurrencia_region_cuadriculada
            cmap = colors.ListedColormap(['white', 'black', 'blue', 'red', 'green', 'orange'])
            bounds = [0, 1, 2, 3, 4, 5]
            norm = colors.BoundaryNorm(bounds, cmap.N)
            plt.imshow(nueva_matriz_recurrencia_combinada, origin='lower', cmap=cmap, norm=norm,
                       interpolation='nearest')

        # elif grafica == 'matrizRecurrenciaColor':
        #    plt.grid(False)
        #    cmap = colors.ListedColormap(['blue', 'green', 'red', 'yellow', 'gray', 'white'])
        #    bounds = [0, 1, 2, 3, 4, 5, 6]
        #    norm = colors.BoundaryNorm(bounds, cmap.N)
        #    plt.imshow(self.matrizRec, cmap=cmap, norm=norm, interpolation='nearest')

        # elif grafica == 'regionCuadricula':
        #    import matplotlib.pyplot as plt
        #    print(self.matriz_cuadriculada)
        #    plt.grid(False)
        #    plt.colorbar(
        #        plt.imshow(np.flipud(self.matriz_cuadriculada)))

        elif grafica == 'cilindros_objetos_importantes':
            print("Entro a cilindros_objetos_importantes")

            self.calcula_alturas_cilindros_objetos_relevantes(tamanio=tamanio_cilindros,
                                                              divisiones=div_cilindros)
            rot_grafica_3d = rotacion_grafica_3d

            if getattr(sys, 'frozen', False):
                os.environ['BASEMAPDATA'] = os.path.join(os.path.dirname(sys.executable), 'mplot3d')

            ax = fig.add_subplot(111, projection='3d')
            ax.view_init(azim=rot_grafica_3d % 360, elev=0)

            for i in range(0, len(self.cantidad_posiciones_cilindros_1)):
                fa.pintar_cilindro(self.objeto_relevante_1[0],
                                   self.objeto_relevante_1[1],
                                   self.radios_cilindros[i],
                                   self.cantidad_posiciones_cilindros_1[i],
                                   ax)
                fa.pintar_cilindro(self.objeto_relevante_2[0],
                                   self.objeto_relevante_2[1],
                                   self.radios_cilindros[i],
                                   self.cantidad_posiciones_cilindros_2[i],
                                   ax)
                fa.pintar_cilindro(self.objeto_relevante_3[0],
                                   self.objeto_relevante_3[1],
                                   self.radios_cilindros[i],
                                   self.cantidad_posiciones_cilindros_3[i],
                                   ax)
                fa.pintar_cilindro(self.objeto_relevante_4[0],
                                   self.objeto_relevante_4[1],
                                   self.radios_cilindros[i],
                                   self.cantidad_posiciones_cilindros_4[i],
                                   ax)

            ax.set_xlim(0, 100)
            ax.set_ylim(0, 100)
            ax.set_zlim(0, len(self.posiciones_x))

            if 0 < rot_grafica_3d <= 90:
                ax.xaxis._axinfo['juggled'] = (0, 0, 0)
                ax.yaxis._axinfo['juggled'] = (1, 1, 1)
                ax.zaxis._axinfo['juggled'] = (2, 2, 2)
            elif 90 < rot_grafica_3d <= 180:
                ax.xaxis._axinfo['juggled'] = (0, 0, 0)
                ax.yaxis._axinfo['juggled'] = (0, 1, 2)
                ax.zaxis._axinfo['juggled'] = (0, 2, 1)
            elif 180 < rot_grafica_3d <= 270:
                ax.xaxis._axinfo['juggled'] = (1, 0, 2)
                ax.yaxis._axinfo['juggled'] = (0, 1, 2)
                ax.zaxis._axinfo['juggled'] = (2, 2, 2)
            elif 270 < rot_grafica_3d <= 360:
                ax.xaxis._axinfo['juggled'] = (1, 0, 2)
                ax.yaxis._axinfo['juggled'] = (1, 1, 1)
                ax.zaxis._axinfo['juggled'] = (1, 2, 0)

            ax.view_init(azim=rot_grafica_3d)

        elif grafica == 'region_cuadricula_3d':

            print("Entro a regionCuadricula3d")

            rot_grafica_3d = rotacion_grafica_3d

            objeto_1_x = self.objeto_relevante_1[0]
            objeto_1_y = self.objeto_relevante_1[1]

            objeto_2_x = self.objeto_relevante_2[0]
            objeto_2_y = self.objeto_relevante_2[1]

            objeto_3_x = self.objeto_relevante_3[0]
            objeto_3_y = self.objeto_relevante_3[1]

            objeto_4_x = self.objeto_relevante_4[0]
            objeto_4_y = self.objeto_relevante_4[1]

            if getattr(sys, 'frozen', False):
                os.environ['BASEMAPDATA'] = os.path.join(os.path.dirname(sys.executable), 'mplot3d')

            data_array = np.array(np.flipud(self.matriz_cuadriculada))

            print(data_array)

            ax = fig.add_subplot(111, projection='3d')

            ax.view_init(azim=rot_grafica_3d % 360, elev=0)

            x_data, y_data = np.meshgrid(np.arange(data_array.shape[1]),
                                         np.arange(data_array.shape[0]))

            x_data = x_data.flatten()
            y_data = y_data.flatten()
            z_data = data_array.flatten()

            tamanio_horizontal = self.dimension_caja[0] / self.cantidad_columnas
            tamanio_vertical = self.dimension_caja[1] / self.cantidad_filas

            objeto_1_x_pos_matriz_cuadriculada = int(objeto_1_x // tamanio_horizontal)
            objeto_1_y_pos_matriz_cuadriculada = int(objeto_1_y // tamanio_vertical)

            objeto_2_x_pos_matriz_cuadriculada = int(objeto_2_x // tamanio_horizontal)
            objeto_2_y_pos_matriz_cuadriculada = int(objeto_2_y // tamanio_vertical)

            objeto_3_x_pos_matriz_cuadriculada = int(objeto_3_x // tamanio_horizontal)
            objeto_3_y_pos_matriz_cuadriculada = int(objeto_3_y // tamanio_vertical)

            objeto_4_x_pos_matriz_cuadriculada = int(objeto_4_x // tamanio_horizontal)
            objeto_4_y_pos_matriz_cuadriculada = int(objeto_4_y // tamanio_vertical)

            print([objeto_1_x_pos_matriz_cuadriculada],
                  [objeto_2_x_pos_matriz_cuadriculada],
                  [objeto_3_x_pos_matriz_cuadriculada],
                  [objeto_4_x_pos_matriz_cuadriculada])
            print([objeto_1_y_pos_matriz_cuadriculada],
                  [objeto_2_y_pos_matriz_cuadriculada],
                  [objeto_3_y_pos_matriz_cuadriculada],
                  [objeto_4_y_pos_matriz_cuadriculada])

            ax.bar3d(x_data,
                     y_data,
                     np.zeros(len(z_data)),
                     1, 1, z_data)

            if 0 < rot_grafica_3d <= 90:
                ax.xaxis._axinfo['juggled'] = (0, 0, 0)
                ax.yaxis._axinfo['juggled'] = (1, 1, 1)
                ax.zaxis._axinfo['juggled'] = (2, 2, 2)
            elif 90 < rot_grafica_3d <= 180:
                ax.xaxis._axinfo['juggled'] = (0, 0, 0)
                ax.yaxis._axinfo['juggled'] = (0, 1, 2)
                ax.zaxis._axinfo['juggled'] = (0, 2, 1)
            elif 180 < rot_grafica_3d <= 270:
                ax.xaxis._axinfo['juggled'] = (1, 0, 2)
                ax.yaxis._axinfo['juggled'] = (0, 1, 2)
                ax.zaxis._axinfo['juggled'] = (2, 2, 2)
            elif 270 < rot_grafica_3d <= 360:
                ax.xaxis._axinfo['juggled'] = (1, 0, 2)
                ax.yaxis._axinfo['juggled'] = (1, 1, 1)
                ax.zaxis._axinfo['juggled'] = (1, 2, 0)

            ax.view_init(azim=rot_grafica_3d)

        return fig


