308 lines
9.5 KiB
Python
308 lines
9.5 KiB
Python
#! /usr/bin/env python
|
|
# pyright: basic
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
import pandas as pd
|
|
|
|
from utils import crud, filters, parser, stats, utils, visuals
|
|
|
|
HEADER = """=== Terramotos ==="""
|
|
|
|
EVENT_COLS = [
|
|
"Data",
|
|
"Latitude",
|
|
"Longitude",
|
|
"Profundidade",
|
|
"Tipo Evento",
|
|
"Gap",
|
|
"Magnitudes",
|
|
"Regiao",
|
|
"Sentido",
|
|
"Pub",
|
|
"SZ",
|
|
"VZ",
|
|
]
|
|
STATION_COLS = [
|
|
"Estacao",
|
|
"Hora",
|
|
"Min",
|
|
"Seg",
|
|
"Componente",
|
|
"Distancia Epicentro",
|
|
"Tipo Onda",
|
|
]
|
|
|
|
MENU = """[1] Criar a base de dados
|
|
[2] Apagar um evento
|
|
[3] Apagar uma entrada de um evento
|
|
[4] Visualizar um evento
|
|
[5] Guardar como JSON
|
|
[6] Guardar como CSV
|
|
[7] Estatísticas
|
|
[8] Criar uma entrada
|
|
[9] Gráficos
|
|
[10] Filtros (T7)
|
|
|
|
[Q] Sair
|
|
"""
|
|
|
|
|
|
def guardar_csv(df: pd.DataFrame, fname: str):
|
|
"""Guarda uma DataFrame num ficheiro csv
|
|
|
|
Args:
|
|
df (pd.DataFrame): Dataframe com os dados
|
|
fname (str): nome do ficheiro csv
|
|
|
|
Returns:
|
|
bool: Retorna se a operação foi bem sucedida ou não
|
|
"""
|
|
with open(fname, "w") as fp:
|
|
try:
|
|
df.to_csv(fp, index=False)
|
|
except ValueError:
|
|
return False
|
|
return True
|
|
|
|
|
|
def main():
|
|
"""Ponto de entrada do programa.
|
|
|
|
Constituido por um while loop a correr um menu onde o utilizador pode
|
|
interagir com os vários módulos implementados.
|
|
|
|
"""
|
|
isRunning = True
|
|
db = None
|
|
original_db = None
|
|
|
|
retInfo = None
|
|
|
|
while isRunning:
|
|
os.system("cls" if sys.platform == "windows" else "clear")
|
|
print(HEADER + "\n" + MENU)
|
|
usrIn = input("Opção: ").lower()
|
|
|
|
match usrIn:
|
|
case "1":
|
|
fname = _get_usr_input("Qual os dados a ler? (dados.txt por defeito): ")
|
|
if fname is None:
|
|
fname = "dados.txt"
|
|
|
|
if _file_exists(fname) and fname.endswith(".json"):
|
|
db = pd.read_json(fname)
|
|
original_db = db.copy()
|
|
print("Base de dados populada.")
|
|
elif _file_exists(fname):
|
|
db = parser.parse(fname)
|
|
original_db = db.copy()
|
|
input("Base de dados populada. Enter para voltar ao menu inicial")
|
|
else:
|
|
input("Base de dados não encontrada. Por favor tenta de novo.")
|
|
|
|
case "2":
|
|
if db is not None:
|
|
crud.read_ids(db)
|
|
choice: int = _get_usr_input("Escolhe o ID para apagar: ", int)
|
|
|
|
if not _event_exists(db, choice):
|
|
retInfo = "ID do event não encontrado!"
|
|
|
|
else:
|
|
db = crud.delete_event(db, choice)
|
|
input()
|
|
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "3":
|
|
if db is not None:
|
|
crud.read_ids(db)
|
|
eid_choice: int = _get_usr_input("Escolhe o ID: ", int)
|
|
|
|
if not _event_exists(db, eid_choice):
|
|
retInfo = "ID do event não encontrado!"
|
|
|
|
else:
|
|
os.system("cls" if sys.platform == "windows" else "clear")
|
|
table = crud.get_table(db, eid_choice)
|
|
_prettify_event(table)
|
|
crud.show_table(table)
|
|
|
|
row_choice = _get_usr_input("Escolhe a linha a apagar:", int)
|
|
|
|
db, msg = crud.delete_table_row(db, eid_choice, row_choice)
|
|
new_table = crud.get_table(db, eid_choice)
|
|
crud.show_table(new_table)
|
|
print(msg)
|
|
input()
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "4":
|
|
if db is not None:
|
|
crud.read_ids(db)
|
|
choice = _get_usr_input("Escolhe o ID para ver os dados: ", int)
|
|
|
|
if not _event_exists(db, choice):
|
|
retInfo = "ID do event não encontrado!"
|
|
|
|
else:
|
|
os.system("cls" if sys.platform == "windows" else "clear")
|
|
table = crud.get_table(db, choice)
|
|
_prettify_event(table)
|
|
crud.show_table(table)
|
|
input()
|
|
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "5":
|
|
if db is not None:
|
|
fname = _get_usr_input("Nome do ficheiro a guardar? ")
|
|
if fname is None:
|
|
fname = "valores.json"
|
|
utils.save_as_json(db, fname, EVENT_COLS)
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "6":
|
|
if db is not None:
|
|
fname = _get_usr_input("Nome do ficheiro a guardar? ")
|
|
if fname is None:
|
|
fname = "valores.csv"
|
|
guardar_csv(db, fname)
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "7":
|
|
if db is not None:
|
|
stats.stat_menu(db)
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "8":
|
|
if db is not None:
|
|
crud.read_ids(db)
|
|
eid_choice = _get_usr_input("Escolhe o ID: ", int)
|
|
|
|
if not _event_exists(db, eid_choice):
|
|
retInfo = "ID do event não encontrado!"
|
|
|
|
else:
|
|
os.system("cls" if sys.platform == "windows" else "clear")
|
|
table = crud.get_table(db, eid_choice)
|
|
_prettify_event(table)
|
|
crud.show_table(table)
|
|
|
|
insertion_point = _get_usr_input("Posição da nova linha: ", int)
|
|
|
|
db, msg = crud.create_table_row(db, eid_choice, insertion_point)
|
|
new_table = crud.get_table(db, eid_choice)
|
|
crud.show_table(new_table)
|
|
print(msg)
|
|
input()
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "9":
|
|
if db is not None:
|
|
visuals.visual_menu(db)
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "10":
|
|
if db is not None:
|
|
# Passa db e original_db para o menu de filtros
|
|
# Retorna a nova db ativa (filtrada ou redefinida)
|
|
db = filters.filter_menu(db, original_db)
|
|
else:
|
|
retInfo = "Base de dados não encontrada!"
|
|
|
|
case "q":
|
|
isRunning = False
|
|
continue
|
|
case _:
|
|
pass
|
|
|
|
if retInfo:
|
|
print(retInfo)
|
|
retInfo = None
|
|
input("Clique Enter para continuar")
|
|
|
|
|
|
def _file_exists(name: str) -> bool:
|
|
"""Verifica se um ficheiro existe no diretório onde o programa correntemente
|
|
corre, através de os.getcwd()
|
|
|
|
Args:
|
|
name (str): Nome do ficheiro a verificar
|
|
|
|
Returns:
|
|
bool: True se existe, False caso contrário
|
|
"""
|
|
currFiles = os.listdir(os.getcwd())
|
|
if name in currFiles:
|
|
return True
|
|
return False
|
|
|
|
|
|
def _event_exists(df: pd.DataFrame, eid: int) -> bool:
|
|
"""Função privada de verificação de eventos
|
|
|
|
Verifica se um certo ID de evento existe ou não dentro de uma DataFrame
|
|
|
|
Args:
|
|
df (pd.DataFrame): DataFrame a pesquisar
|
|
eid (int): Evento específico a pesquisar
|
|
|
|
Returns:
|
|
bool: True se evento existe dentro da DataFrame, False caso contrário
|
|
"""
|
|
allEvents = set(df["ID"])
|
|
return eid in allEvents
|
|
|
|
|
|
def _get_usr_input(msg: str, asType: Any = str) -> Any:
|
|
"""Modifica o stdin do utilizador para o tipo especificado. Por defeito retorna uma str.
|
|
|
|
Args:
|
|
msg (str): String a ser alterada
|
|
asType (Any): tipo no qual msg deverá ser intepretado como (default: `str`)
|
|
|
|
Returns:
|
|
[type]: [description]
|
|
"""
|
|
usrIn = input(msg)
|
|
|
|
if usrIn == "":
|
|
return None
|
|
return asType(usrIn)
|
|
|
|
|
|
def _prettify_event(df: pd.DataFrame) -> None:
|
|
"""Função privada para utilização na visualização de um evento singular através
|
|
do menu de `Visualizar um evento`
|
|
|
|
Args:
|
|
df (pd.DataFrame): DataFrame com os dados do evento
|
|
"""
|
|
# preambleInfo = df.drop_duplicates(subset="ID", keep="first")
|
|
# stations = df[["Estacao", "Componente", "Tipo Onda", "Amplitude"]]
|
|
info = df.drop_duplicates(subset="Data", keep="first")
|
|
data = datetime.fromisoformat(info.Data.values[0]).strftime("%c")
|
|
print(
|
|
f"Região: {info['Regiao'].values[0]}\nData: {data}\nLatitude: {info['Latitude'].values[0]}\nLongitude: {info['Longitude'].values[0]}"
|
|
+ f"\nProfundidade: {info['Profundidade'].values[0]}\nTipo de evento: {info['Tipo Evento'].values[0]}\n"
|
|
)
|
|
|
|
|
|
# entry point
|
|
if __name__ == "__main__":
|
|
main()
|