Elige la métrica: por defecto es euclídea
norma 1
norma 2 (Euclideana)
polares planos [radio,ángulo]
polares espacio [Radio,Latitud, Longitud] (distancia euclidiana)*
polares espacio [Radio,Latitud, Longitud] (distancias esféricas)*
coordenadas geográficas [Latitud,Longitud] (distancias esféricas)*
Tiempo (referencia google maps)*
ida y vuelta
todas rutas
orden creciente
ruta mas corta
# importamos librerias
import io
import asyncio
import pandas as pd
import matplotlib.pyplot as plt
import math
import numpy as np
import itertools # permutaciones
import copy
from time import time
#from statsmodels.graphics.gofplots import qqplot # para qq test
#import statsmodels.api as sm
from js import document, FileReader
from pyodide.ffi import create_proxy
################################### las funciones que se llaman aparte cada una tras cargar los datos pulsando botones
# norma 1 (usando valor absoluto) #### value = 1
def norm_1(a,b):
t = 0;
for i in range(len(a)):
t = t + abs(a[i]-b[i])
return t
# coordenadas polares planas #### value = 3
def polares_2(a,b):
ax = a[0]*math.cos(a[1]*math.pi/180) # a = [radio_a, angulo_a] b = [radio_b, angulo_b]
ay = a[0]*math.sin(a[1]*math.pi/180)
bx = b[0]*math.cos(b[1]*math.pi/180)
by = b[0]*math.sin(b[1]*math.pi/180)
av = [ax,ay]
bv = [bx,by]
return math.dist(av,bv)
# coordenadas polares esféricas pero con distancia en recta #### value = 4
def esfericas_1(a,b): # a[0] = RAD a[1] = LAT a[2] = LON distancia esféricas pero en rectas
ax = math.cos(a[2]*math.pi/180)*math.cos(a[1]*math.pi/180)*a[0]
ay = math.sin(a[2]*math.pi/180)*math.cos(a[1]*math.pi/180)*a[0]
az = math.sin(a[1]*math.pi/180)*a[0]
bx = math.cos(b[2]*math.pi/180)*math.cos(b[1]*math.pi/180)*b[0]
by = math.sin(b[2]*math.pi/180)*math.cos(b[1]*math.pi/180)*b[0]
bz = math.sin(b[1]*math.pi/180)*b[0]
av = [ax,ay,az]
bv = [bx,by,bz]
return math.dist(av,bv)
# coordenadas esféricas con distancia en arco según radio #### value = 5
def esfericas_2(a,b): # radio fijo pero dado en primera columna de datos
# vamos a recurrir a bibliotecas de numpy que ayudan trabajar con matrices y vectores
ax = math.cos(a[2]*math.pi/180)*math.cos(a[1]*math.pi/180)*a[0]
ay = math.sin(a[2]*math.pi/180)*math.cos(a[1]*math.pi/180)*a[0]
az = math.sin(a[1]*math.pi/180)*a[0]
bx = math.cos(b[2]*math.pi/180)*math.cos(b[1]*math.pi/180)*b[0]
by = math.sin(b[2]*math.pi/180)*math.cos(b[1]*math.pi/180)*b[0]
bz = math.sin(b[1]*math.pi/180)*b[0]
av = np.array([ax,ay,az])
bv = np.array([bx,by,bz])
# calculamos el ángulo entre vectores con defincición de producto escalar
pab = av@bv
pa = math.sqrt(av@av)
pb = math.sqrt(bv@bv)
cos_alpha = pab/(pa*pb)
alpha = math.acos(cos_alpha)
dist = a[0]*alpha # el angulo ya viene dado en radianes
return dist
# coordenadas geográficas #### value = 6
def coordenadas(a,b): # radio fijo 6371 distancia en arco terrestre
# vamos a recurrir a bibliotecas de numpy que ayudan trabajar con matrices y vectores
r = 6371
ax = math.cos(a[1]*math.pi/180)*math.cos(a[0]*math.pi/180)*r
ay = math.sin(a[1]*math.pi/180)*math.cos(a[0]*math.pi/180)*r
az = math.sin(a[0]*math.pi/180)*r
bx = math.cos(b[1]*math.pi/180)*math.cos(b[0]*math.pi/180)*r
by = math.sin(b[1]*math.pi/180)*math.cos(b[0]*math.pi/180)*r
bz = math.sin(b[0]*math.pi/180)*r
av = np.array([ax,ay,az])
bv = np.array([bx,by,bz])
# calculamos el ángulo entre vectores con defincición de producto escalar
pab = av@bv
pa = math.sqrt(av@av)
pb = math.sqrt(bv@bv)
cos_alpha = pab/(pa*pb)
alpha = math.acos(cos_alpha)
dist = r*alpha # el angulo ya viene dado en radianes
return dist
# función distancia (normas)
def norma(a,b):
# aquí se introduce valor de radiobox para eligir la métrica
if document.getElementById("norma1").checked:
rate_value = document.getElementById("norma1").value;
elif document.getElementById("norma2").checked:
rate_value = document.getElementById("norma2").value;
elif document.getElementById("polar_plana").checked:
rate_value = document.getElementById("polar_plana").value;
elif document.getElementById("polar_espacio").checked:
rate_value = document.getElementById("polar_espacio").value;
elif document.getElementById("polar_espacio_esféricas").checked:
rate_value = document.getElementById("polar_espacio_esféricas").value;
elif document.getElementById("coordenadas").checked:
rate_value = document.getElementById("coordenadas").value;
elif document.getElementById("tiempo").checked:
rate_value = document.getElementById("tiempo").value;
if rate_value == "1":
norma = round(norm_1(a,b),2)
elif rate_value == "2":
norma = round(math.dist(a,b),2)
elif rate_value == "3":
norma = round(polares_2(a,b),2)
elif rate_value == "4":
norma = round(esfericas_1(a,b),2)
elif rate_value == "5":
norma = round(esfericas_2(a,b),2)
elif rate_value == "6":
norma = round(coordenadas(a,b),2)
return norma
def principal():
list_dist = [] # lista de distancias ordenada
manual_div0 = Element("dato2") # indicamos donde lo vamos a representar
l = len(df.iloc[:,0])
n = len(df.iloc[0,:])
k = 0;
while k < l:
r = k+1;
while r <= l-1:
a = df.iloc[k,1:n].to_list() # el primer elemento nocuenta porque es "nombre" apartir del segundo son coordenadas "-1" calcula hasta último
b = df.iloc[r,1:n].to_list()
d = norma(a,b)
elem_1 = df.iloc[k,0]
elem_2 = df.iloc[r,0]
lista_val=[elem_1,elem_2,d]
list_dist.append(lista_val) # hacemos lista de listas (matriz) donde cada elemento es elemento 1, elemento 2 y distancia entre ellos.
r = r + 1;
k = k + 1;
manual_div0.element.innerText = []; # borrar todo
manual_div0.element.innerText = list_dist;
def rutas_posibles():
tiempo_inicial = time()
l = len(df)
listadeobjetos = []
listadeobjetos_titulos = []
for i in range(l):
listadeobjetos.append(df.iloc[i,:].to_list()) # convertimos en lista todos objetos con todas parámetros
permutations = list(itertools.permutations(listadeobjetos))
# hacemos salidas recortadas o normales en función de tectacles 2 que corresponde a linea de un punto concreto.
# Solo se muestran rutas desde un punto concreto. Modificamos lista anterior añadiendo Solo
# elementos que comienzan por dado punto de salida
if int(document.getElementById("tentacles2").value)!= 0:
value_3 = int(document.getElementById("tentacles2").value) - 1 # este indica posición en archivo y en dataframe del punto correspondente
lista_reducida = [];
# para acceder al numbre del unto debemos referirnos a df en este caso
nombre = df.iloc[value_3,0]
for j in range(len(permutations)):
if permutations[j][0][0] == nombre:
lista_reducida.append(permutations[j])
permutations = lista_reducida;
# ahora voy a meter aqui en cada ruta su diustancia
# como rutas no son variables globales es mejor hacerlo desde esta misma función
# para cada elemento de permutations
for k in range(len(permutations)):
dist_total = 0;
n = len(permutations[0][0])
j_len = len(permutations[0])
listadeobjetos_titulos.append([])
for j in range(j_len-1):
dist_total = round(dist_total + norma(permutations[k][j][1:n],permutations[k][j+1][1:n]),2)
listadeobjetos_titulos[k].append(permutations[k][j][0])
listadeobjetos_titulos[k].append(permutations[k][j_len-1][0]) # no se añade la última ciudad con el boocle por esto se hace aquí
listadeobjetos_titulos[k].append(dist_total)
# si está eligido checkbox de ida y vuelta quiere decir que tenemos que añadir ida desde el último punto hasta el primero
if document.getElementById("ida_y_vuelta").checked:
listadeobjetos_titulos[k][j_len] = round(dist_total + norma(permutations[k][0][1:n],permutations[k][j_len-1][1:n]),2)
# eligimos entre varias opciones. Mostrar toda la ruta o solo la ruta minimal
if document.getElementById("todas").checked:
manual_div2 = Element("dato2") # indicamos donde lo vamos a representar
manual_div2.element.innerText = ""; # borrar todo
manual_div2.element.innerText = listadeobjetos_titulos;
elif document.getElementById("ordenadas").checked:
manual_div2 = Element("dato2") # indicamos donde lo vamos a representar
manual_div2.element.innerText = ""; # borrar todo
manual_div2.element.innerText = [2];
# rate_value_2 = document.getElementById("ordenadas").value;
elif document.getElementById("minimal").checked:
lista_distancias = []
len_elemento = len(listadeobjetos_titulos[0])
for i in range(len(listadeobjetos_titulos)):
lista_distancias.append(listadeobjetos_titulos[i][len_elemento-1])
result = lista_distancias.index(min(lista_distancias))
manual_div2 = Element("dato2") # indicamos donde lo vamos a representar
manual_div2.element.innerText = ""; # borrar todo
manual_div2.element.innerText = listadeobjetos_titulos[result];
#### parte final de la función que imprime el resultado.
tiempo_final = time()
tiempo_total = tiempo_final - tiempo_inicial
# borrar todao
def borrar2():
manual_div = Element("dato2")
manual_div.element.innerText = " ";
### ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
### ///////////////////////////// el código de abajo carga el archivo desde boton (1), define variables a partir de este (3),
### además representa parte de archivo en div content y define variables globales (4),
### el resto de código (superior) funciona ya correctamente con estas variables
### procesado de archivo
async def process_file(event):
fileList = event.target.files.to_py()
### 4. esta función se ejecuta automáticamente al cargar el archivo (en boocle de abajo)
### solo representa por pantalla rsumen del archivo
### y define variables globales para el resto del código
def representar(dataframe):
nombres_1 = dataframe.columns.values
nombres_2 = str(nombres_1)
document.getElementById("content").innerHTML = nombres_2 # también puede usarse innerHTML o innerText
# ahora de una vez se guarda esta variable global para poder usarla en todo el script
global df;
df = dataframe;
global tamanio;
tamanio = len(dataframe)
minimal = min(tamanio,4) # para decidir lineas máximo a representar
# se imrime en ventana principal (capa 1)
for x in range(minimal):
document.getElementById("content" + str(x)).innerHTML = list(dataframe.iloc[x])
document.getElementById("content5").innerHTML = "... ... tamaño total: " + str(tamanio)
### 3. definimos variable df (no global de momento) a partir del texto
### y llamamos función para representar (que también define variables flobales)
for f in fileList:
data = await f.text()
# read_csv recibe como parámetro archivo de texto pero en este caso le pasamos simple contenido del archivo
# para que read_csv pueda recibir este formato hay que añadir io.stringIO función creada para esto
df_0 = pd.read_csv(io.StringIO(data))
# representar parte de archivo en un div
representar(df_0)
### 1. inicia aquí. Se carga desde el botón "myfile"
def main():
# Create a Python proxy for the callback function
# process_file() is your function to process events from FileReader
file_event = create_proxy(process_file)
# Set the listener to the callback
e = document.getElementById("myfile")
e.addEventListener("change", file_event, False)
main()