Como borrar una gráfica para poner otra

publicado por: Anonymous

Tengo 2 dudas. Una es que cómo puedo borrar la gráfica anterior para plotear otra con algun dato modificado(freq o nº ciclos).

La segunda es que he creado un botón que me crea un fichero con los datos graficados, pero no me llega a funcionar porque le tengo que pasar una cadena con los datos, y no acierto en como devolver de las funciones las cadenas de datos para pasárselas a la función crear fichero.

adjunto mi programa:

import Tkinter as tk
import ttk

import matplotlib
matplotlib. use('TkAgg' )
from matplotlib.figure import Figure

from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg



def dibuja_senoidal():
        #a.clf(canvas_fig)
        try:
         f=float(frecuencia.get()) 
         ciclos_mostrados=(float(ciclos.get())*(1/f))
         ss=[]
         t = arange(0.0, ciclos_mostrados, 0.00001)#le ponemos un valor tan bajo para que haya suficientes puntos              
         s = sin(2*pi*f*t)
         for elemento in s:
             ss.append(str(elemento))
         a. plot(t, s)
         canvas_fig.show()
         #with open('fichero.txt' , 'w' ) as f:
            #valor = ' n' . join(ss)
            #f. write(valor)
         return ss
        except ValueError:
         pass

def dibuja_cuadrada():
    #a.clf(canvas_fig)
    try:
     f=float(frecuencia.get()) 
     ciclos_mostrados=(float(ciclos.get())*(1/f))
     t = arange(0.0, ciclos_mostrados, 0.00001)#le ponemos un valor tan bajo para que haya suficientes puntos                 
     s = sin(2*pi*f*t)
     c=[1 if elemento>=0 else -1 for elemento in s]
     a. plot(t, c)
     canvas_fig.show()
     return c         
    except ValueError:
        pass

def escribir_fichero():    
     try:
         with open('Datos_seno.txt' , 'w' ) as f:
            valor = ' n' . join(c)
            f. write(valor)
         with open('Datos_cuadrada.txt' , 'w' ) as f:
            valor = ' n' . join(c)
            f. write(valor)
     except ValueError:
         pass

root = tk. Tk()
root. title(u"GRAFICAR")



# creamos un frame a la izquierda para colocar los botones
frame_inf = ttk. Frame(root, padding="3 3 3 3")
frame_inf. grid(columnspan=4, row=1, sticky=(tk. N, tk. W, tk. E, tk. S))
frame_inf. columnconfigure(0, weight=1)
frame_inf. columnconfigure(1, weight=1)
frame_inf. columnconfigure(2, weight=1)
frame_inf. columnconfigure(3, weight=1)
frame_inf. rowconfigure(0, weight=1)
frame_inf. rowconfigure(1, weight=1)
frame_inf. rowconfigure(2, weight=1)


#creamos un frame SUPERIOR para colocar la grafica
frame_sup = ttk. Frame(root, padding="3 3 3 3")
frame_sup. grid(columnspan=4, row=0)

# creamos la figura y el widget asociado
f = Figure(figsize=(5, 4), dpi=100)
a = f. add_subplot(111)

canvas_fig = FigureCanvasTkAgg(f, master=frame_sup)
canvas_fig. get_tk_widget().grid(column=0, row=0,rowspan=2)

# añadimos los botones para mostrar las gráficas
ttk. Button(frame_inf, text="Dibuja senoidal", command=dibuja_senoidal). grid(column=0,columnspan=2, row=1, sticky=( tk. W, tk. E))
ttk. Button(frame_inf, text="Dibuja cuadrada", command=dibuja_cuadrada). grid(column=2,columnspan=2, row=1, sticky=( tk. W, tk. E))


frecuencia =tk.StringVar()
ciclos =tk.StringVar()   #DEFINICION DE VARIABLES

tk.Label(frame_inf, text="Frecuencia: ").grid(column=0,row=2,sticky=(tk.W,tk.E)) #TEXTO DE ENTRADA
frecuencia_entry=tk.Entry(frame_inf,width=7,textvariable=frecuencia)             #DEFINICION DEL ENTRY
frecuencia_entry.grid(column=1,row=2,sticky=( tk. W, tk. E))                       #GRID DEL ENTRY

tk.Label(frame_inf, text="Nº Ciclos: ").grid(column=2,row=2,sticky=(tk.W,tk.E))   #TEXTO DE ENTRADA
ciclos_entry=tk.Entry(frame_inf,width=7,textvariable=ciclos)                     #DEFINICION DEL ENTRY
ciclos_entry.grid(column=3,row=2,sticky=(tk. W, tk. E))                           #GRID DEL ENTRY

#Boton de creacion de fichero
ttk. Button(frame_inf, text="Crear Fichero", command=escribir_fichero). grid(column=0,columnspan=4, row=3, sticky=( tk. W, tk. E))

for child in frame_inf. winfo_children(): child. grid_configure(padx=5, pady=5)

root. mainloop()

solución

Bienvenido a stackoverflow Miguel. Vamos a ir por partes:

❶ En cuanto a la primera duda, el problema es que las variables c y ss son variables locales, que solo existen dentro de las funciones dibuja_cuadrada() y dibuja_senoidal() respectivamente. Esto hace que no puedas llamarlas desde la función escribir_fichero(). Existen varias formas posibles de hacer esto:

  • Hacer que ss y c sean globales usando global. Personalmente me gusta evitar en lo posible las variables globales pero es una opción simple.

  • Llamar desde escribir_fichero() de nuevo a las funciones para que retornen las listas correspondientes, esto es ineficiente ya que tenemos que recalcular todo de nuevo.

  • Mi opción preferida (y más aún al trabajar con interfaces gráficas) es usar POO (programación oirientada a objetos). En este caso basta con hacer que ss y c sean atributos de nuestra clase y las funciones dibuja_cuadrada(), dibuja_senoidal() y escribir_fichero() pasan a ser métodos de la clase. Esta opción es la que implemento al final de la respuesta.

❷ En cuanto a actualizar la gráfica lo más eficiente es usar el método set_data(). En el código que te pongo cada vez que haces click en uno de los dos botones (Dibuja senoidal y Dibuja cuadrada) se actualiza la gráfica corespondiente manteniendo la otra como estaba. Es decir, cada botón actualiza solo su gráfica asociada(si los datos han cambiado).

A continuación te pongo el código usando POO y modificando lo menos posible tu propio código. Tiene algunos comentarios añadidos pero si algo no entiendes solo coméntalo.

import Tkinter as tk
import ttk 
import matplotlib
matplotlib. use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from numpy import arange, sin, pi



class App_Window(tk. Tk):
    def __init__(self,parent):
        tk.Tk.__init__(self,parent)
        self.parent = parent
        self.title(u"GRAFICAR")
        self.inicializar()

    def inicializar(self):
        #Inicializamos las dos listas que contienen los datos y que podemos usar para guardarlas en el tct
        self.c = list()
        self.ss = list()

        # creamos un frame a la izquierda para colocar los botones
        frame_inf = ttk. Frame(self, padding="3 3 3 3")
        frame_inf. grid(columnspan=4, row=1, sticky=(tk. N, tk. W, tk. E, tk. S))
        frame_inf. columnconfigure(0, weight=1)
        frame_inf. columnconfigure(1, weight=1)
        frame_inf. columnconfigure(2, weight=1)
        frame_inf. columnconfigure(3, weight=1)
        frame_inf. rowconfigure(0, weight=1)
        frame_inf. rowconfigure(1, weight=1)
        frame_inf. rowconfigure(2, weight=1)

        #creamos un frame SUPERIOR para colocar la grafica
        frame_sup = ttk. Frame(self, padding="3 3 3 3")
        frame_sup. grid(columnspan=4, row=0)

        # creamos la figura y el widget asociado
        f = Figure(figsize=(5, 4), dpi=100)
        self.a = f.add_subplot(111)
        #Activamos el autoescalado del os ejes
        self.a.set_autoscale_on(True)
        self.a.autoscale_view(True,True,True)

        #Inicializamos las dos graficas
        self.lineC, = self.a.plot([], [], color='b')
        self.lineSS, = self.a.plot([], [], color='r')


        self.canvas_fig = FigureCanvasTkAgg(f, master = frame_sup)
        self.canvas_fig. get_tk_widget().grid(column=0, row=0,rowspan=2)



        # añadimos los botones para mostrar las gráficas
        ttk. Button(frame_inf, text="Dibuja senoidal", command=self.dibuja_senoidal).grid(column=0,columnspan=2, row=1, sticky=( tk. W, tk. E))
        ttk. Button(frame_inf, text="Dibuja cuadrada", command=self.dibuja_cuadrada).grid(column=2,columnspan=2, row=1, sticky=( tk. W, tk. E))

        self.frecuencia = tk.StringVar()
        self.ciclos = tk.StringVar()

        #DEFINICION DE VARIABLES
        tk.Label(frame_inf, text="Frecuencia: ").grid(column=0,row=2,sticky=(tk.W,tk.E))
        #TEXTO DE ENTRADA
        frecuencia_entry = tk.Entry(frame_inf,width=7,textvariable = self.frecuencia)
        #DEFINICION DEL ENTRY
        frecuencia_entry.grid(column=1,row=2,sticky=( tk. W, tk. E))
        #GRID DEL ENTRY

        tk.Label(frame_inf, text="Nº Ciclos: ").grid(column=2,row=2,sticky=(tk.W,tk.E))
        #TEXTO DE ENTRADA
        ciclos_entry=tk.Entry(frame_inf,width=7,textvariable=self.ciclos)
        #DEFINICION DEL ENTRY
        ciclos_entry.grid(column=3,row=2,sticky=(tk. W, tk. E))
        #GRID DEL ENTRY

        #Boton de creacion de fichero
        ttk. Button(frame_inf, text="Crear Fichero",    command=self.escribir_fichero).     grid(column=0,columnspan=4, row=3, sticky=( tk. W, tk. E))

        for child in frame_inf. winfo_children(): child. grid_configure(padx=5, pady=5)


    def dibuja_senoidal(self):
        try:
            f = float(self.frecuencia.get())
            ciclos_mostrados=(float(self.ciclos.get())*(1/f))
            t = arange(0.0, ciclos_mostrados, 0.00001)#le ponemos un valor tan bajo para que haya suficientes puntos              
            self.ss = sin(2*pi*f*t)
            self.lineSS.set_data(t, self.ss)

            #Recalculamos los ejes
            self.a.relim()
            self.a.autoscale_view(True,True,True)

            self.canvas_fig.show()            
        except ValueError:
            pass


    def dibuja_cuadrada(self):
        try:
            f = float(self.frecuencia.get()) 
            ciclos_mostrados=(float(self.ciclos.get())*(1/f))
            t = arange(0.0, ciclos_mostrados, 0.00001)#le ponemos un valor tan bajo para que haya suficientes puntos                 
            self.c = [1 if elemento>=0 else -1 for elemento in sin(2*pi*f*t)]
            self.lineC.set_data(t, self.c)

            #Recalculamos los ejes
            self.a.relim()
            self.a.autoscale_view(True,True,True)

            self.canvas_fig.show()        
        except ValueError:
            pass


    def escribir_fichero(self):    
        try:
            with open('Datos_seno.txt' , 'w' ) as f:
                valor = ' n' . join((str(n) for n in self.ss))
                f. write(valor)
            with open('Datos_cuadrada.txt' , 'w' ) as f:
                valor = ' n' . join((str(n) for n in self.c))
                f. write(valor)
        except ValueError:
            pass

if __name__ == "__main__":
    MainWindow = App_Window(None)
    MainWindow.mainloop()

Saludos.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *