martes, 24 de mayo de 2022

¿Cómo incorporar un Gráfico de Matplotlib en Tkinter y Guizero?


ventana de tkinter con gráfico insertado

¿Cómo incorporar un Gráfico de Matplotlib en Tkinter y Guizero?

A veces necesitamos incorporar gráficos de Matplotlib dentro de nuestras aplicaciones. Se puede enfocar este tema desde dos vertientes. (Lo primero no obstante es instalar esta librería, claro está.)

La primera es hacer un gráfico con la librería  Matplotlib, por ejemplo, guardarlo en un archivo en el mismo directorio y como hemos visto en un tema anterior cargarlo como cualquier otro gráfico en un widget.

Por ejemplo podemos construir un gráfico como el que se muestra a continuación utilizando la librería Matplotlib y guardándolo con la instrucción savefig() de esta librería. Puedes encontrar más información sobre como elaborar un gráfico en el siguiente enlace.

gráfico a insertar en una aplicación.


Y luego, una vez que tenemos el archivo lo podemos usar en nuestra GUI. En Guizero esto se realizaría usando PICTURE(). Matizar que Guizero solo permite usar imágenes en formato GIF o PNG.

El código puede ser parecido a este:

from guizero import *
'''Una forma de insertar un grafico es construyendolo con matplotlib,
guardandolo con la instrucion savefig()
y luego importarlo en guizero con Picture()'''

raiz=App()
Picture(raiz, image="grafico1.png", width=500, height=500)
raiz.display()

Lo que nos crea esta ventana con el gráfico dentro.

Gráfico insertado en una ventana


Código de esta aplicación en Github.


La segunda opción es incrustar ese gráfico en el widget directamente, aunque también es algo más compleja.

Podemos usar por ejemplo  este código que ya utilizamos en el capítulo de matplotlib para crear un simple gráfico de barras y trataremos de insertarlo en un widget.

import matplotlib.pyplot as plt
mascotas = [12, 9, 3, 1]
nombres = ["perros", "gatos", "peces", "tortugas"]
plt.bar(nombres, mascotas)
plt.plot()
plt.show()

Daría lugar al siguiente gráfico:

gráfico generado con matplotlib


Comenzamos importando las librerías que vamos a necesitar para crear una ventana y luego dibujar dentro el gráfico anterior.

# librerías de gráficos normales
import tkinter as tk
# librerías para insertar el gráfico
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# Librería para crear el gráfico
import matplotlib.pyplot as plt

Luego programamos la ventana de la aplicación y un contenedor tipo "frame" que será el que aloje el gráfico. 

# Creamos la ventana y el contenedor "frame" que contendrá el gráfico.
ventana = tk.Tk()
ventana.geometry('300x250')
ventana.title("Gráfica insertada en tkinter")
frame = tk.Frame(ventana, bg='yellow')
frame.grid(column=0, row=0, sticky='nsew')

Usando las listas con los datos que tenemos que son el nombre de las mascotas y su número o frecuencia procedemos a crear un gráfico.

mascotas = [12, 9, 3, 1]
nombres = ["perros", "gatos", "peces", "tortugas"]

fig, axs = plt.subplots(dpi=80, figsize=(4, 3))
fig.suptitle("Grafico Principal")

axs.bar(nombres, mascotas)

En este ejemplo creamos una figura que solamente tendrá un gráfico principal, es por ello que usamos la función fig, axs = plt.subplots().  Con dpi y figsize establecemos el tamaño del gráfico. También le añadimos un título y finalmente al ser solamente un gráfico usamos axs y el tipo de gráfico a crear, que en este caso es un gráfico de barras. 

Si queremos dibujar varios gráficos, habría que definirlos dentro de plt.subplots() y accederíamos a ellos con axs[0], ax[1] etc.

La novedad es que vamos a usar FigureCanvasTkAgg para dibujar el gráfico (fig) dentro del frame anteriormente definido, usando un canvas de tkinter:

# Dibujamos el gráfico dentro del frame definido usando
# un Canvas de tkinter.
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.draw()
canvas.get_tk_widget().grid(column=0, row=0)

ventana.mainloop()

Si todo ha ido bien el resultado será algo parecido a esto:

ventana de tkinter con gráfico insertado


Puedes encontrar el código en el siguiente enlace.



martes, 3 de mayo de 2022

Menús, Barras de Herramientas y Barras de Estado.

 Menús de Opciones.

Este tipo de objetos nos van a servir para mostrar un menú en la parte superior de la pantalla y cada uno de estos menús conduce a su vez a submenús.

Imagen de un menú de opciones.



Las Opciones de un menú pueden incluir iconos y asociarse a atajos o combinaciones de teclas. También en un momento dado pueden deshabilitarse para impedir que puedan ser seleccionadas.

Barra de Herramientas.

En las aplicaciones además de los menús también puede haber barras de herramientas que se construyen a base de botones agrupados de manera horizontal o vertical. Además suelen colocarse justo debajo de la barra de menú de la aplicación.


Imagen de barra de Herramientas.


Barra de estado.

Se utilizan para mostrar información que resulte útil a los usuarios. Normalmente ocupan la última línea de la ventana de la aplicación.


Imagen de barra de estado.


Ejemplo de implementación en una Aplicación en Tkinter.

Vamos a crear un ejemplo de como puede ser una aplicación sencilla usando los elementos que hemos comentado anteriormente. Este ejemplo esta sacado del Blog "Python para Impacientes" que puedes encontrar en el siguiente enlace.

La ventana principal de esta aplicación cuenta con una ventana de título

La ventana principal de esta aplicación cuenta con una barra de título, una barra de menú con tres submenús desplegables con distintos tipos de opciones, un menú contextual que se activa haciendo clic con el botón secundario del ratón en cualquier lugar de la ventana, una barra de herramientas con dos botones con imágenes y una barra de estado que es posible ocultar o mostrar mediante la opción "Ver barra de estado" del submenú "Opciones".

ejemplo de aplicación con menus, submenus etc



menú de opciones desplegado.


En el submenú "Opciones" se encuentra la opción "Guardar" que se habilitará cuando se elija alguna opción de entre las disponibles en este submenú; y se deshabilitará cuando se utilice la propia opción "Guardar", -prevista- para salvar las preferencias seleccionadas por el usuario.

iconos usados en la aplicación.


La aplicación de ejemplo utiliza imágenes de diferentes tamaños que se localizan en una carpeta llamada "imagen". Estas imágenes son utilizadas en la barra de título, los submenús, la barra de herramientas y en la ventana de diálogo "Acerca de" del submenú "Ayuda". Han sido obtenidas del sitio flaticon.com que ofrece colecciones de imágenes organizadas por distintas temáticas a programadores y a diseñadores gráficos.


menús de la aplicación desplegados.


También, en el programa se incluyen varias combinaciones de teclas asociadas a distintas opciones del menú, declaradas con el método bind().


¿Cómo funciona?

La aplicación la inicia la función main() que comprueba que todas las imágenes de la aplicación existen en la carpeta "imagen". Si todas las imágenes están disponibles se creará el objeto aplicación mediante la clase PyRemoto(). Esta clase cuenta con un método __init__() que construye la ventana de la aplicación, los menús, la barra de herramientas y una barra de estado.

La aplicación está incompleta pero enseña cómo organizar los métodos que son llamados desde las distintas opciones de los menús y barras.

Por último, el ejemplo incluye la ventana de diálogo "Acerca de", que es de tipo modal, para mostrar el modo de abrir este tipo de ventanas desde una opción del menú.

Como el código es bastante extenso puedes encontrarlo en el siguiente enlace.


Ejemplo de implementación en una Aplicación en Guizero.

La aplicación va a ser la misma solamente que usando como constructor Guizero y mezclado con algún elemento de Tkinter que directamente Guizero no tiene aun implementado. Puedes encontrar la forma detallada de construir los menús en la guia oficial de Guizero.

Una novedad que se incluye en el código es que se implementa la forma para calcular las dimensiones de la ventana del ordenador y en base a eso y al tamaño de la ventana de la aplicación, centrar la misma.

Puedes en contar el código de la aplicación en el siguiente enlace.