sábado, 10 de septiembre de 2022

Código (Python)

 ¿Cómo funciona t-tester? Veamos el código de este programa con las explicaciones detalladas.

1) importamos librerías tkinter para la interfaz (en windows), csv para trabajar con archivos de datos (valores separados por coma), matplotlib para interpretación gráfica de datos. 

from tkinter import *
import tkinter as tk
import csv
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt

2) la ventana principal de la interfaz 

raiz = Tk()
raiz.title("Tester -tt BETA 1.1")
raiz.resizable(0,0)
raiz.iconbitmap("logoico.ico")
raiz.geometry("800x400")
raiz.config(bg="white")

3) campo azul (del receptor de datos)

miframe = Frame()# creamos un frame. Pero lo tenemos que meter dentro de la raiz.
miframe.pack(side = "left") # empaquetarlo en raiz
# para rellenado ver Curso Python. Interfaces gráficas II. Vídeo 43
# https://youtu.be/M80CzDC1Crc
miframe.config(bg="lightcyan2")
miframe.config(width="200", height = "400")
miframe.config(bd=1)
miframe.config(relief="ridge")

4) receptor de datos (del campo azul)

texto1 = Label(miframe, text ="TEST PRINCIPAL", bd = 0, bg = "lightcyan2", fg = "grey50", font=("calibri",12))
texto1.place(x = 10, y = 160)
opcion1 = IntVar() # Como StrinVar pero en entero
R1 = Radiobutton(miframe, text="NEGATIVO", value=0, var=opcion1, bg = "lightcyan2")
R2 = Radiobutton(miframe, text="POSITIVO", value=1, var=opcion1, bg = "lightcyan2")
R1.place(x = 10, y = 180)
R2.place(x = 90, y = 180)

texto2 = Label(miframe, text ="NUEVO TEST", bd = 0, bg = "lightcyan2", fg = "red", font=("calibri",12))
texto2.place(x = 10, y = 220)
opcion2 = IntVar() # Como StrinVar pero en entero
R3 = Radiobutton(miframe, text="NEGATIVO", value=0, var=opcion2, bg = "lightcyan2")
R4 = Radiobutton(miframe, text="POSITIVO", value=1, var=opcion2, bg = "lightcyan2")
R3.place(x = 10, y = 240)
R4.place(x = 90, y = 240)

5) motor principal del algoritmo (se refiere a la creación y el relleno del fichero)

# MOTOR PRINCIPAL DEL ALGORITMO
#declaración de variables enteras
p1 = int();
p2 = int();

def codigoknopa():
    p1 = opcion1.get();
    p2 = opcion2.get();
    #declaramos copias de variables para trabajar a parte sin perder los datos
    n1 = p1
    n2 = p2
    cad3 = [int(n1),int(n2)] # para cada paciente dos datos. Test bueno 
    # en primera coordenada y test a probar en segunda
    # escribimos en el archivo nuevos datos
   fichero2 = open("listanueva2.csv", "a")
    caract = str(cad3)
    carnuvo = caract.replace("[", "")
    carnuvo = carnuvo.replace("]", "")
    fichero2.write(carnuvo)
    fichero2.write("\n")
    fichero2.close()
    # tras escritura en el archivo de nuevos datos este se guarda y se cierra
    # ahora abrimos este y lo pasamos a una cadena en el programa
    list3 = [];
    with open('listanueva2.csv', newline='') as File: 
        reader = csv.reader(File)
        for row in reader:
            for c in range(2):
                row[c] = int(row[c])
            list3.append(row)

6) componente matemático (seguimos en la misma línea de la función "codigocnopa")

    # creamos valores de verdaderos y falsos positivos y negativos 
    # !!! EN ESTE ALGORITMO NE SE USA REGLA BAYES. SE CALCULAN LOS
    # DATOS DE LA LISTA Y finalmente solo hay que dividir entre tamaño de 
    # la muestra para obtener la proporción (regla Laplace)

    vn = 0; # verdadero negativo
    vp = 0; # verdadero positivo
    fn = 0; # falso negativo
    fp = 0; # falso positivo
    p = 0;# los positivos test principal
    n = 0;# los negativos test principal
    m = len(list3); # tamaño de la muestra 

    for i in range(m):
        if list3[i][0] == 0: # analiza 1a columna [0] y se da negativo
            n = n + 1; # PERSONA SANA
            if list3[i][1] ==0: # segunda columna [1] los sintomas negativos
                vn = vn + 1; # VERDADERO NEGATIVO
            else:# si en la segunda columna se da el caso positivo
                fp = fp + 1; # es un negativo pero con sintomas. Falso positivo
        else :# es un caso positivo, la primera columna [0] es 1
            p = p + 1; # cálculo de los positivos reales
            if list3[i][1] ==1: # con síntomas positivos
                vp = vp + 1; # test es un verdadero positivo
            else:
                fn = fn + 1; # es un falso negativo

    # la proporci-on de los mal diagnosticados respecto la muestra total
    prmd = (fn+fp)/m
    # sencibilidad delos test. Capacidad de obtener el resultado POSITIVO en el caso 
    # si el test real es POSITIVO p(P/E)

    if p!= 0:
        sens = round(vp/p,3)
    else:
        sens = 0
    # especificidad vn/n p(N/S)
    if n!=0:
        espe = round(vn/n,3)
    else:
        espe = 0
    # proporcion positivos de la muestra
    posmues = round(p/m,2)
    cad4 = float(prmd) # dicha proporcion
    fichero3 = open("listanueva3.csv", "a")
    caract3 = str(cad4)
    carnuvo3 = caract3.replace("[", "")
    carnuvo3 = carnuvo3.replace("]", "")
    fichero3.write(carnuvo3)
    fichero3.write("\n")
    fichero3.close()

    # pasamos el archivo a una cadena en el programa

    list4 = [];
    with open('listanueva3.csv', newline='') as File: 
        reader = csv.reader(File)
        for row in reader: 
            list4.append(row)

    vn = round(vn/m,3);
    vp = round(vp/m,3);
    fn = round(fn/m,3);
    fp = round(fp/m,3);

    ####!!! error conceptual??? si hacemos probabilidad de un verdadero positivo 
    #### nos puede salir cosa rara. Ya que hay muy poco positivos, la intersección
    #### es mas pequeña aun y comparando con el total tiene valor muy pequeño
    #### esto no da info buena. 

7) interpretación de datos por la interfaz (seguimos en la misma línea de la función "cofigocnopa")

    texto8 = Label(miframe2, text ="composición de casos", bd = 0, bg = "white", fg = "grey50", font=        ("calibri",12))
    texto8.place(x = 10, y = 80)
    fig1 = plt.figure(figsize=(4,4), dpi = 100)
    fig1.set_size_inches(2,2)
    valores = [fn*m,vn*m,fp*m,vp*m]
    nombres =["FN","VN","FP","VP"]
    plt.pie(valores, explode = (0.04,0.04,0.04,0.04), labels = nombres, colors =                                ["Brown","Darkseagreen","IndianRed","Mediumseagreen"])
    plt.axis("equal")
    canvasbar = FigureCanvasTkAgg(fig1, master = miframe2)
    canvasbar.draw()
    canvasbar.get_tk_widget().place(x = 10, y = 100)    

    # los datos obtenidos del algoritmo

    texto6 = Label(miframe2, text =str(fn), bd = 0, bg = "white", fg = "red", font=("calibri",12))
    texto6.place(x = 110, y = 10)
    texto7 = Label(miframe2, text =str(fp), bd = 0, bg = "white", fg = "red", font=("calibri",12))
    texto7.place(x = 110, y = 30)
    texto12 = Label(miframe2, text =str(sens), bd = 0, bg = "white", fg = "red", font=("calibri",12))
    texto12.place(x = 340, y = 10)
    texto13 = Label(miframe2, text =str(espe), bd = 0, bg = "white", fg = "red", font=("calibri",12))
    texto13.place(x = 340, y = 30)
    texto14 = Label(miframe2, text =str(posmues), bd = 0, bg = "white", fg = "red", font=("calibri",12))
    texto14.place(x = 490, y = 10)

    ## desarrollo de mal diagnosticado histórico

    texto9 = Label(miframe2, text ="desarrollo MD histórico", bd = 0, bg = "white", fg = "grey50",             font=  ("calibri",12))
    texto9.place(x = 250, y = 80) 
    m = len(list4); # tamaño de la muestra 
    x = [0]*(m)
    y = [0]*(m)
    for i in range(m):
        x[i] = i
        y[i] = float(list4[i][0])
    fig2 = plt.figure(figsize=(6,4), dpi = 50)
    a = fig2.add_subplot()
    a.plot(x,y, marker = "")# entre comillas puede venir . o
    #    a.legend("")
    a.grid()
    # Creating Canvas
    canv = FigureCanvasTkAgg(fig2, master = miframe2)
    canv.draw()
    get_widz = canv.get_tk_widget().place(x = 220, y= 100)


8) interfaz del botón "añadir" con referencia al comando "codigocnopa" 

knopa = Button(miframe, text = "añadir", command= codigoknopa, ).place(x = 70, y = 270)
miframe2 = Frame()# creamos un frame. Pero lo tenemos que meter dentro de la raiz.
miframe2.pack(side = "left") # empaquetarlo en raiz
# para rellenado ver Curso Python. Interfaces gráficas II. Vídeo 43
# https://youtu.be/M80CzDC1Crc
miframe2.config(bg="white")
miframe2.config(width="600", height = "400")
miframe2.config(bd=1)
miframe2.config(relief="ridge")
texto3 = Label(miframe2, text ="proporción F-", bd = 0, bg = "white", fg = "grey50", font=("calibri",12))
texto3.place(x = 10, y = 10)
texto4 = Label(miframe2, text ="proporción F+", bd = 0, bg = "white", fg = "grey50", font=("calibri",12))
texto4.place(x = 10, y = 30)
texto10 = Label(miframe2, text ="Sensibilidad p(P/E)", bd = 0, bg = "white", fg = "grey50", font=("calibri",12))
texto10.place(x = 190, y = 10)
texto11 = Label(miframe2, text ="Especificidad p(N/S)", bd = 0, bg = "white", fg = "grey50", font=("calibri",12))
texto11.place(x = 190, y = 30)
texto15 = Label(miframe2, text ="+ Muestra", bd = 0, bg = "white", fg = "grey50", font=("calibri",12))
texto15.place(x = 400, y = 10)

9) botón de información 

### BUTTOB INFORMACIÓN
def codigoknopa2():
    info = open("info.txt",'r')
    mensaje = info.read()
    info.close()
    def clear()
        text_widget.destroy()
        knopa3.destroy()
    text_widget = tk.Text(miframe2)
    # Pack it into our tkinter application
    text_widget.place(x = 10, y = 10, width = 550, height = 320)
    # Insert text into the text widget
    # tk.END specifies insertion after the last character in our buffe
    text_widget.insert(tk.END, mensaje)
    knopa3 = Button(miframe2, text = "cerrar", command= clear,  borderwidth=0)
    knopa3.place(x = 10, y = 365)
knopa2 = Button(miframe, text = "info", command= codigoknopa2,  borderwidth=0).place(x = 10, y = 365)

10) botón de eliminación de todos los datos guardados

def codigoknopa4():
    mens = messagebox.askokcancel(message="Se van a borrar todos los datos acomulados del experimento. Antes de continuar se aconceja hacer copias de archivos listanueva2 y listanueva3 en la carpeta del programa ¿Desea continuar?", title="¡Advertencia!")
    if mens == True:   
        d1 = open("listanueva2.csv",'w')
        d2 = open("listanueva3.csv",'w')
        d1.write('')
        d1.close()
        d2.write('')
        d2.close()

knopa4 = Button(miframe, text = "Borrar", command= codigoknopa4,  borderwidth=0).place(x = 40, y = 365)

11) boocle para mantener la venta de la interfaz abierta

raiz.mainloop()# un boocle infinito que mantiene la ventana

No hay comentarios:

Publicar un comentario