Mostrando entradas con la etiqueta Gráficos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Gráficos. Mostrar todas las entradas

miércoles, 9 de julio de 2025

Gráficos. Python

PyGame. Eventos de ratón


Los eventos de ratón afectan a los botones, la rueda y el desplazamiento del ratón por la superficie. Los dos primeros son similares a los de teclado (presionar - soltar), pero el de desplazamiento o movimiento ofrece otras posibilidades.


Veamos en primer lugar los que afectan a los botones (1 - 2 - 3) y a la rueda (4 - 5) y a su estado (MOUSEBUTTONDOWN vs MOUSEBUTTOMUP)

elif event.type == pygame.MOUSEBUTTONDOWN:
            print("Botón del mouse presionado:", event.button)
            if event.button == 1:
                print ("Se ha pulsado el botón izquierdo del ratón (botón ",event.button,")")
            elif event.button == 2:
                print ("Se ha pulsado el botón central del ratón (botón ",event.button,")")
            elif event.button == 3:
                print ("Se ha pulsado el botón derecho del ratón (botón ",event.button,")")
            elif event.button == 4:
           print ("Se ha accionado la rueda del botón hacia delante (evento ratón ",event.button,")") 
            elif event.button == 5:
              print ("Se ha accionado la rueda del botón hacia atrás (evento ratón ",event.button,")") 

Una vez capturado el evento  MOUSEBUTTONDOWN MOUSEBUTTONUP (v.g. event.type == pygame.MOUSEBUTTONDOWN), podemos identificar el botón pulsado (event.button) y, tomando como referencia la equivalencia entre identificador numéricos (v.g. if event.button == 1:) ...

  • 1 para el botón izquierdo
  • 2 para el central
  • 3 para el derecho
  • 4 para el avance de la rueda
  • y 5 para el retroceso
...  asociarlo a alguna acción o conjunto de acciones (en el ejemplo print ("Se ha pulsado el botón izquierdo del ratón (botón ",event.button,")") ).

Las posibilidades de trabajo con este procedimiento es similar al que tenemos con la identificación de los eventos de teclado (aunque es dudoso que podemos desarrollar procedimientos complejos, a modo de paneles de control), pero las que nos ofrece la captura del desplazamiento del ratón (pygame.MOUSEMOTION:)...

if event.type == pygame.MOUSEMOTION:
    print(f'Ratón movido a {event.pos} ')

...  nos abren un amplio mundo de opciones (antes sólo print(f'Ratón movido a {event.pos} ')) una vez que capturamos los valores numéricos de las posiciones cartesianas x - y, como es el caso del [script que sigue]...

import pygame

# Inicializar Pygame

pygame.init() 

# Configurar la pantalla

window_size = ( 800 , 600 ) 

screen = pygame.display.set_mode(window_size) 

pygame.display.set_caption( 'Ejemplo de posición del mouse' ) 

# Configurar la fuente para mostrar texto

font = pygame.font.Font( None , 36 ) 

# Bucle principal (game loop)

running = True 

while running:

#Captura todos los eventos que suceden en la ventana

    for event in pygame.event.get():

#Captura evento de ventana (QUIT) para cerrarla

        if event.type == pygame.QUIT:

            running = False

# Rellena la pantalla con blanco (RGB 255,255,255)

    screen.fill(( 255 , 255 , 255 ))

# Obtiene la posición actual del mouse...

    x, y = pygame.mouse.get_pos()

# ... y la presenta en el texto en color rojo (RGB 250,0,0)

    text = font.render( f'Posición del puntero del ratón: {x} - {y}' , True , ( 250 , 0 , 0 ))

# Redibuja el texto en la pantalla...

    screen.blit(text, ( 20 , 20 ))

#... y la actualiza

    pygame.display.flip()

# Salir de Pygame

pygame.quit() 

... que es sólo un ejercicio sin pretensiones de utilidad práctica, pero que nos permite pensar en posibilidades de aplicación como mapas, cronogramas, gráficos interactivos...

Gráficos. Python

PyGame. Eventos de teclado


Los eventos de teclado permiten identificar las teclas sobre las que ha pulsado el usuario. A partir de ahí podemos transformar este conocimiento en una forma de interacción entre el usuario y el programa.


Vamos a ver en esta entrada las formas en las que podemos capturar estos eventos. Algunas de ellas ya son conocidas, aunque no nos detuvimos especialmente en explicarlas. Por ejemplo, el modo en el que controlamos la ruptura del game loop:

running = True
while running:
    for event in pygame.event.get():
#Capturamos el evento ventana para cerrar el bucle
        if event.type == pygame.QUIT:
            running = False

Después de capturar los eventos mediante un for  con la función event.get() (for event in pygame.event.get():), controlamos el evento pygame.QUIT para generar la ruptura del bucle, modificando el valor de la variable que lo controla (running = False) mediante el condicional (if event.type == pygame.QUIT:).

Pero en sentido estricto (el anterior es un evento de ventana), los eventos de teclado (pygame.KEYUP pygame.KEYDOWN ) se refieren al control de qué tecla ha sido pulsada o liberada, identificándola por su "nombre" ( if event.key == pygame.K_f:)...

elif event.type == pygame.KEYUP:
            if event.key == pygame.K_f:
                print ("Hemos presionado la tecla f")

... o por su código o número (if event.key == 97:)

elif event.type == pygame.KEYDOWN:
            if event.key == 97:
                print("Tecla presionada la tecla A (", event.key,")")

Otra cosa es qué hagamos con ese control. De momento nos sirve únicamente para identificar la tecla, a fin de centrar la explicación en el propio evento. En posteriores desarrollos veremos posibles aplicaciones; por ahora apuntar únicamente que, gracias al control de los eventos de teclado podríamos construir teclados orientados a funciones específicas, a modo de paneles de control. Este ya es un tema que requiere algo de bricolaje informático, no sólo programación.

Gráficos. Python

PyGame. Eventos


Dentro de la ventana del juego (o de la pantalla, si se prefiere) se producen eventos que resultan de la acción del usuario sobre los elementos que sirven de interfaz, como son el teclado y el ratón.


En PyGame, la función pygame.event.get() devuelve una lista de todos los eventos que suceden en pantalla, que son los siguientes:

- pygame.QUIT -> Cierre de ventana (pulsando la [X] de la ventana)

Eventos de teclado:

- pygame.KEYDOWN -> Cuando se presiona una tecla.
- pygame.KEYUP -> Cuando se suelta una tecla.

Eventos de ratón:

- pygame.MOUSEBUTTONDOWN -> Cuando se presiona un botón del ratón.
- pygame.MOUSEBUTTOMUP -> Cuando se suelta un botón del ratón.
- pygame.MOUSEMOTION -> Cuando el ratón se mueve.

Eventos de joystick:

- pygame.JOYAXISMOTION -> Cuando se mueve un eje del joystick.
- pygame.JOYBUTTONDOWN -> Cuando se presiona un botón del joystick.
- pygame.JOYBUTTONUP -> Cuando se suelta un botón del joystick.

Para mostrar en consola los eventos usamos la función print(event). Algunos de ellos son los siguientes:

Algunos eventos de ventana:

<Event(4352-AudioDeviceAdded {'which': 0, 'iscapture': 0})>
<Event(4352-AudioDeviceAdded {'which': 0, 'iscapture': 1})>
<Event(32774-WindowShown {'window': None})>
<Event(32768-ActiveEvent {'gain': 1, 'state': 2})>
<Event(32785-WindowFocusGained {'window': None})>
<Event(770-TextEditing {'text': '', 'start': 0, 'length': 0, 'window': None})>
<Event(32783-WindowEnter {'window': None})>

Algunos eventos de ratón:

<Event(1024-MouseMotion {'pos': (605, 211), 'rel': (0, 0), 'buttons': (0, 0, 0), 'touch': False, 'window': None})>
<Event(1024-MouseMotion {'pos': (615, 207), 'rel': (10, -4), 'buttons': (0, 0, 0), 'touch': False, 'window': None})>

Algunos eventos de teclado:

<Event(768-KeyDown {'unicode': '1', 'key': 49, 'mod': 0, 'scancode': 30, 'window': None})>
<Event(771-TextInput {'text': '1', 'window': None})>
<Event(769-KeyUp {'unicode': '1', 'key': 49, 'mod': 0, 'scancode': 30, 'window': None})>
<Event(768-KeyDown {'unicode': '2', 'key': 50, 'mod': 0, 'scancode': 31, 'window': None})>
<Event(771-TextInput {'text': '2', 'window': None})>
<Event(769-KeyUp {'unicode': '2', 'key': 50, 'mod': 0, 'scancode': 31, 'window': None})>
<Event(768-KeyDown {'unicode': '3', 'key': 51, 'mod': 0, 'scancode': 32, 'window': None})>

Lo interesante de los eventos es que su control mediante código nos permiten desarrollar interacciones entre el usuario y el programa. Algunos ejemplos de formas de uso serán tratadas en posteriores entradas.

miércoles, 16 de abril de 2025

Gráficos. Python

PyGame. Objeto ventana


Todo en PyGame son clases, objetos, atributos, métodos... dado que en Python, pero sobre todo en PyGame el paradigma de programación dominante es el llamado Programación Orientada a Objetos (POO)... incluso cuando nosotros estemos trabajando desde la óptica de otro paradigma, como el de programación lineal. De ahí que hablemos del objeto ventana, por cierto, uno de los fundamentales (imprescindible, diríamos) de todo script PyGame. Así que está más que justificado iniciar por ventana este recorrido por los objetos de esta librería.


El programa más simple que podemos escribir usando PyGame debe contener necesariamente una ventana, aunque de momento no sirva para nada más que demostrar que el programa existe y funciona. Este sería un ejemplo de lo que acabo de decir:

import pygame
pygame.init()
pygame.display.set_mode((800,600))
pygame.time.delay(2000)
pygame.quit()

Este script únicamente muestra en nuestro monitor una pantalla de 800 x 600 pilxeles de color negro durante 2 segundos. Después se cierra. No es mucha cosa, pero es el principio necesario. Además nos muestra tres opciones de desarrollo: el tamaño de la pantalla, el color de fondo y el manejo del tiempo de visualización.
  • El tamaño de la pantalla depende de la tupla que recibe como parámetro el método (o función) set_mode() (recuerda usar doble paréntesis) del objeto display, así que lo podemos modificar para que se ajuste lo mejor posible a nuestro monitor, llegando incluso a utilizarlo a pantalla completa. Tema interesante sobre el que volveremos, por cierto.
  • Dado que se usa un color por defecto, el manejo de esta opción no queda expresado en este primer script,  pero enseguida comprobaremos la necesidad de presencia.
  • Finalmente, el control del tiempo de exposición de nuestra ventana mediante el método delay() del objeto time es una licencia que nos tomamos ahora para facilitar el visionado del funcionamiento del script, por lo que no será un método que veamos necesariamente en otros script, pero que tiene su interés, especialmente para un uso de PyGame un tanto diferente del habitual.
Con todo, incluso para nuestros sencillo fines, este script es excesivamente sencillo, así que vamos a trabajarlo un poco más... empezando por dar color a esa ventana, aunque sea color blanco...

import pygame
pygame.init()
ventana = pygame.display.set_mode((800,600))
ventana.fill((255,255,255))
pygame.display.update()
pygame.time.delay(2000)
pygame.quit()

Como puedes ver he necesitado dos líneas de código para animar un poco esa primera ventana:
  • Usando el método fill() que recibe como parámetro una tupla con tres valores numéricos (derivada del sistema de codificación del color en formato RGB)
Esa tupla la podemos sustituir por una constante

BLANCO = (255,255,255) -> ventana.fill(BLANCO)

  • Y el método update(), encargado de actualizar los valores de la pantalla.
La primera instrucción se posiciona en la sección 1 y la segunda en la sección 2.

Existe otro modo de tratar el trabajo con el color de la ventana que consiste en considerarlo como una superficie superpuesta a la propia ventana a modo de fondo o background. Esa es la propuesta de Fernando Sansberro y la que adopté en [el script] que utilicé como ejemplo de estructura de script. Reproduzco por motivos didácticos:

#Superficie del fondo de pantalla
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

La última de las instrucciones es la única realmente imprescindible y es la que ya conocemos por la anterior formulación. El resto nos lleva al tema del uso de una imagen como fondo de pantalla, cuestión esta que aun no está a nuestro alcance, aunque lo estará en breve. Ahora prefiero que nos centremos en la definición del tamaño de la ventana.

Mientras que estas instrucciones se ubican dentro de la sección 1, en la sección 2 deberemos actualizar la imagen de fondo de la pantalla (screen.blit(imgBackground, (0, 0))), además de redibujar ésta (pygame.display.flip())

Pero realmente no supone ninguna dificultad establecer las dimensiones de ventana que mejor se ajuste a nuestro monitor y al objetivo de nuestro script; es suficiente con establecerlo directamente como valores numéricos en la función set_move() o, en su defecto, indicarlo por medio de una variable...

size = (800,600)

 ventana = pygame.display.set_mode(size)

... o mediante dos constantes

ANCHO = 800

ALTO = 600

 ventana = pygame.display.set_mode((ANCHO,ALTO))

... pudiendo modificar esos valores numéricos sin necesidad de modificar la instrucción que establece la propia pantalla mediante set_mode(). Únicamente queda por plantear una situación especial que no se resuelve modificando esos valores: cuando deseamos trabajar a pantalla completa (fullscreen). En este caso necesitamos modificar la instrucción de base añadiendo un segundo parámetro a set_mode(): pygame.FULLSCREEN

V.g ventana = pygame.display.set_mode(size, pygame.FULLSCREEN)

Dos observaciones son necesarias en estos momentos:

  • Observación 1: aunque en los equipos modernos no es normal que falle la tarjeta gráfica al usar el modo fullscreen, si puede suceder en equipos antiguos, por lo que debemos saber que las resoluciones que aceptan ese modo de pantalla son las siguientes: 640 x 480, 800 x 600, 1024 x 768 y 1920 x 1080. Se recomienda usar cualquiera de los dos primeros como tamaños de ventana por ser las medidas de uso más frecuente.
  • Observación 2: El uso de la pantalla a tamaño completo tiene repercusiones sobre los objetos contenidos en ella y sobre la imagen de fondo, por lo que no te recomiendo que lo uses en estos momentos, ya que aun no nos corresponde entrar en estas cuestiones y dar solución a los problemas que puedan surgir. Por el momento es suficiente con que sepas que es posible trabajar con diferentes tamaños de ventana, realizar cambios de tamaño y trabajar a pantalla completa. En breve aprenderemos a sacar rendimiento de estas posibilidades.

domingo, 13 de abril de 2025

Gráficos. Python

PyGame. Tercera sección.


Esta entrada tiene poco que contar, pero es necesaria para completar el análisis de la estructura básica de un script pygame.


Sencilla, fácil de entender, pero imprescindible; la tercera y última sección de un script pygame se escribe fuera del game loop, y en último lugar, incluyendo cuando el script carece de game loop, situación extraordinaria, pero posible, como vimos en la [entrada anterior].

Esto es debido a que con la instrucción pygame.quit() o simplemente la función quit() (ya sabemos que eso depende del modo en que importemos pygame), lo que estamos haciendo es liberar la memoria de todos los recursos asociados al lenguaje Python que hayamos solicitado al sistema, incluyendo, evidentemente, la biblioteca PyGame.

Según nuestro script modelo, esta tercera sección se concreta como sigue:

#Sección 3: Cerrar y liberar recursos ---------------------------

# Cerrar Pygame y liberar los recursos que pidió el programa.
pygame.quit()

De este modo evitamos sobrecargar la memoria de nuestro ordenador. Con independencia de que estemos sobrados de recursos, es una buena práctica que además genera un efecto acorde con lo esperado en el funcionamiento de un script: su cierre.

Con esta entrada podemos dar por finalizada la explicación de la estructura básica de un script (en realidad de un programa-juego) creado con PyGame, pero nos quedan aun muchas cosas por aprender, incluyendo algunas que supondrán volver a hablar de alguna de estas tres secciones.

Gráficos. Python

PyGame. Segunda sección. Game loop.


Curiosamente el game loop, que es el corazón del script y el componente fundamental de su segunda sección, es posible que no esté presente, o no del modo en que se espera, en determinados usos de PyGame. Usos poco frecuentes y posiblemente no especialmente ajustados a las posibilidades de esta biblioteca, pero no por ello menos posibles.



La sección 2 se asocia normalmente al bucle infinito del juego (game loop) y es, a su vez, la parte más compleja del script PyGame, estando conformado, normalmente por las siguientes secciones:
  • Manejo de eventos
  • Actualización de pantalla
  • Dibujar nuevo contenido
El game loop se suele formular mediante el bucle while (while not salir:), ya que este bucle se ejecuta mientras se cumpla determinada condición, la cual suele establecerse a priori (salir = False). 

En este nuestro ejemplo se formula el game loop y su bucle while mediante una doble negación, lo cual no suele ser la norma, la cual simplifica esta formulación que suele hacerse en positivo (vg):
  • running = True
  • while running:
La primera parte del game loop es el manejo de los eventos que se producen en la pantalla, los cuales pueden ser objeto de un tratamiento muy simple o de mucha complejidad. En el script que nos sirve de referencia se manejan eventos del modo más sencillo posible, y está bien que así sea para empezar, pero en posteriores ejemplos veremos algunas de las múltiples posibilidades que presenta el manejo de eventos. De momento nos servirá saber que se requieren un segundo bucle (en esta caso un bucle for (for event in pygame.event.get():) que se complementa con estructuras condicionales (vg. if event.type == pygame.QUIT:), las cuales capturan los eventos y, en función de ellos, se toman decisiones (en este caso salir = True, que equivale a salir del game loop).

Además del acceso a los eventos de pantalla, el game loop también incluye otras dos partes, ambas fuera del bucle for de captura de eventos: la actualización de la pantalla (screen.blit(imgBackground, (0, 0))) y dibujar en la pantalla lo creado previamente (pygame.display.flip()). Estas instrucciones son obligadas y en ese mismo orden. En caso de ausencia o de inversión del orden se altera el correcto funcionamiento del script.

Curiosamente ambas afectan más al funcionamiento del script que el propio game loop. Lo digo en el sentido de que su ausencia invalida el script, pero no la ausencia del game loop, aunque ésta impide la creación de un juego como tal, pero no el uso de PyGame para otras utilidades. 

Para ejemplificar la posibilidad de crear un script PyGame sin game loop pondré un ejemplo muy sencillo aunque : la sucesión de pantallas de diferentes colores. Para ello repetiré una secuencia de cuatro instrucciones tres veces, mostrando así tres pantallas de tres colores diferentes. Y todo ello sin utilizar ni el bucle while (game loop) ni el bucle for (asociado en game loop a la captura de eventos. 

El script completo está accesible desde [este enlace], pero paso a explicar la composición de estas estructuras que, en esta ocasión se repiten tres veces.

imgBackground.fill((0, 0, 255))
screen.blit(imgBackground, (0, 0))
pygame.display.flip()
pygame.time.delay(2000)

La primera instrucción es, si recuerdas, la tercera del bloque de tres instrucciones situadas en la sección 1ª del script modelo dedicadas a establecer el fondo de pantalla. La segunda y tercera son las mismas que ubicamos dentro del game loop para actualizar la pantalla y la cuarta nos permite establecer un tiempo de espera que facilita apreciar el funcionamiento del script: en esta caso establecemos una demora de 2 segundos, usando para ello la función delay() asociada al objeto time de la biblioteca pygame.

Realmente este script no es más que un ejercicio que que demuestra que es posible trabajar con PyGame sin usar game loop, pero no tiene una utilidad inmediata. Para que sí la tenga necesitamos aprender aun unas cuantas cosas. Cuando lo hagamos y estemos en condiciones de demostrar lo que ahora adelanto, prometo que lo pondremos en práctica.

miércoles, 2 de abril de 2025

Gráficos. Python

PyGame. Presentaciones, demostraciones y juegos.


El motivo de incluir PyGame en este blog es facilitar un medio para el logro de los objetivos planteados en la sección Aprendizaje. Cierto que para ello ya disponemos del servicio Impress, de recursos OOo Basic (docap) e incluso, aunque con limitaciones, también de la biblioteca Python-pptx. Sin embargo PyGame no permite adentrarnos en un mundo, el de los videojuegos, con un gran potencial para el desarrollo de la intervención educativa  (incluyendo la llamada gamificación) y de los SEO; en este último caso como herramienta de evaluación.


Debo reconocer, no obstante, que si PyGame interesa como recurso es por las posibilidades de aprendizaje que genera, ya que también exige un proceso de aprendizaje no exento de complejidad. Por ello, lo que en este blog se trate sobre esta biblioteca será únicamente lo que responda a los objetivos que en él se plantea, motivo por el que señalo en el párrafo de inicio de esta entrada a los objetivos de la sección Aprendizaje.

Pero en la sección a la que pertenece esta entrada (y las que siguen sobre el mismo tema) (Herramientas) se plantearán los procedimientos básicos que se requiere saber para hacer uso de esta biblioteca, incluyendo los conocimientos necesarios que se requiere dominar sobre el lenguaje Python y sobre el paradigma de programación orientada a objetos, aunque ambos como extensión y/o derivación del aprendizaje del trabajo con PyGame.

Para poder iniciar este recorrido deberemos empezar por instalar la biblioteca, así que procederemos como sabemos y corresponde desde Símbolo del sistema escribiendo después del prompt pip install pygame; siempre en el supuesto de trabajar desde Windows.

Queda con esto situada la temática y el enfoque, incluyendo sus limitaciones. Para mayor conocimiento del tema iré añadiendo a esta entrada algunas referencias documentales. Para empezar...


jueves, 20 de marzo de 2025

MAV. Python


Python-pptx. Gráfico (3)




Gráfico estadístico

Tercer y último componente gráfico, el gráfico estadístico, al igual que la tabla, se puede presentar como imagen capturada creada con otro programa (una hoja de cálculo mismamente) o creada directamente. Esta es la opción que paso a explicar en esta última entrada sobre python-pptx.


Además, dada la diversidad de opciones disponibles, me limitaré a presentar tres de las opciones disponibles, quedando el resto a la decisión del usuario, que puede ampliar sus conocimientos sobre este particular desde este enlace.

Y por simplificar el contenido de la entrada omitiré la ya sabida (por ser la misma) explicación de la creación de la nueva diapositiva y todo lo que conlleva, para centrarme en lo que es específicamente crear el gráfico estadístico.

Este proceso implica añadir dos sentencias import al inicio del script...
  • from pptx.chart.data import CategoryChartData
  • from pptx.enum.chart import XL_CHART_TYPE
... cuyo significado resulta bastante explícito: la primera permite crear gráficos estadísticos y la segunda crear gráficos específicos según tipología.

Sobre esta base, en efecto, primero creamos el gráfico genérico (chart_data = CategoryChartData()), proceso que completamos asignando las categorías (chart_data.categories = ['Este', 'Oeste', 'Norte','Sur']) y las series de datos que va a tener nuestro gráfico (chart_data.add_series('Series  de datos', (0.40,0.35, 0.15, 0.10))), en este segundo caso mediante la función add_series() que requiere los siguientes parámetros: un título para la serie y la lista de datos de la serie (que debe ser acorde con el número de elementos de las categorías).

Después la añadimos el gráfico a la (teórica) colección de formas de la diapositiva mediante la función add.chart(). Esta función, cuya sintaxis completa incluye el identificador (variable) de la diapositiva y la referencia a la clase formas (Diapo6.shapes.add_chart()) requiere seis parámetros:
  • El primero, la clase de gráfico al que hace referencia la constante, en este caso, XL_CHART_TYPE.COLUMN_CLUSTERED, que hace referencia a un gráfico de barras.
  • Después cuatro variables numéricas, dos de posición y dos de dimensiones, que podemos introducir directamente o mediante referencia a variables declaradas previamente, como es el caso (x, y, cx, cy = Inches(2), Inches(2), Inches(6), Inches(4.5))
  • y finalmente la variable que remite al gráfico creado antes (en este caso, y como sabemos, chart_data)
La expresión final de esta instrucción es la siguiente: Diapo6.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data), aunque el cambio del tipo de gráfico podría hacer cambiar el primer parámetro (XL_CHART_TYPE.LINE para gráficos de línea o XL_CHART_TYPE.PIE para gráficos de tarta) o incluso la el conjunto del código explicado en esta entrada si así lo requiere el tipo de gráfico que deseamos emplear. No obstante, es posible que hacer gráficos más complejos mediante estos recursos no suponga una ventaja, siendo, en ese caso, más sencillo crear el gráfico mediante otro medio y simplemente cargarlo como imagen. Eso queda a la elección del usuario.

Documento. Accede desde este enlace al script con el que finaliza esta serie sobre automatización de presentaciones mediante python-pptx.

Gráficos. Python


Python-pptx. Gráfico
(2)





Tabla

Para las presentaciones que estamos pensando automatizar, las tablas son un componente gráfico interesante. Como gráfico podemos representarlas perfectamente mediante una captura de imagen, esto es, como una imagen simple, pero también es posible construirlas directamente basándonos en datos mediante python-pptx. Este será el tema de esta entrada.


Después de crear la nueva diapositiva (diapo5 = mi_presenta.slide_layouts[5]), de añadirla a la colección (diapo5 = mi_presenta.slides.add_slide(diapo5)) y de acceder a la colección de formas que contiene (formas = diapo5.shapes), esto por ser un modelo de diapositiva con título, y para poner título a la diapositiva (formas.title.text = 'Datos grupales básicos'), pasamos a trabajar con la tabla.

Aunque no es necesario, si resulta conveniente establecer a priori los valores de posicionamiento (x - y) y de  dimensiones de la tabla (cx - cy) (x, y, cx, cy = Inches(2), Inches(2), Inches(4), Inches(1.5)); después pasamos a crear la tabla propiamente dicha mediante la función add_table(), que consta de seis parámetros: dos de estructura de la tabla (filas-columnas), dos de posicionamiento y dos de dimensionado (tabla = formas.add_table(4, 3, x, y, cx, cy).table)

Tampoco es obligatorio, pero sí puede ser conveniente redimensionar las columnas para ajustarlas al contenido. Para ello utilizamos esta expresión ajusta a cada una de las columnas (aquí sólo reproduzco una: tabla.columns[0].width = Inches(2.5))

Ahora ya sólo nos queda escribir en las celdas su contenido: primero el nombre de las columnas (es este caso) (tabla.cell(0, 0).text = 'Estadístico') y después los valores (tabla.cell(1, 0).text = 'Media'). Recuerda que aquí únicamente presento aquí una muestra de cada una de estas instrucciones. Existen otras opciones de trabajo con tablas que puedes consultar en la web de la biblioteca, pero lo que se presenta en esta entrada (y en el script que la acompaña. Ver a continuación) tienes la información fundamental para trabajar con tablas sencillas, las que usarás con más frecuencia en tus presentaciones. 

Documento. En este acceso tienes el script que se explica en la entrada.


lunes, 17 de marzo de 2025

Gráficos. Python


Python-pptx. Índice.




Una vez que sabemos acceder a los objetos que componen una diapositiva, lo que nos ha servido para poner título a la presentación y añadir una breve explicación sobre el contenido, vamos a seguir aprendiendo a manejar otros componentes que normalmente forman parte de una presentación del tipo de las que nos interesa automatizar.


Para ello, siguiendo el listado de contenidos que expuse en la entrada precedente, vamos a tratar en ésta sobre el índice de la presentación. Este componente lo encontramos en el modelo 1 de diapositiva, el cual contiene un objeto título y un objeto de propósito general que nosotros, posteriormente utilizaremos para incluir nuestro índice. Para crear este modelo de diapositiva, primero la creamos del mismo modo que hicimos con la primera (diapo2 = mi_presenta.slide_layouts[1]), aunque especificando que será de tipo 1, y después a añadimos a la lista de objetos diapositivas del objeto presentación (diapo2 = mi_presenta.slides.add_slide(diapo2)). Como ves, se trata del mismo procedimiento que nos sirvió para crea la primera diapositiva y que nos servirá para crear las siguientes.

Una vez creada la diapositiva procedemos a poner el título, que será el mismo que pusimos en la primera diapositiva, aunque podría ser uno específico ("ÍNDICE", por ejemplo). En este caso el procedimiento que empleamos para poner el título en la diapositiva anterior lo vamos a desarrollar en dos fases, pero el resultado es el mismo, por lo que se trata simplemente de un procedimiento alternativo (bien podría ser como sigue: titulo2 = diapo2.shapes.title):
  • Primero accedemos a la clase formas de la clase diapositiva (formas = diapo2.shapes)
  • Y después a la forma title (título) presente en nuestra diapositiva en función del modelo (de diapositiva) que solicitamos crear en el paso anterior (titulo2 = formas.title)
  • Finalmente añadimos el texto (titulo2.text = "Presentación con python.")
Ahora estamos en disposición de entrar en materia, esto es, de escribir el índice que deseamos en la segunda forma, para lo que deberemos acceder a ella (esquema = formas.placeholders[1]) y después la conformamos como nos interesa (tesquema = esquema.text_frame), esto es, como un text_frame, ya que inicialmente se trata de un contenedor de tipo general (placeholders). Observa que hemos utilizado la variable formas que dotamos de contenido antes, dando ahora sentido al procedimiento explicado.

Aunque en nuestra presentación hemos optado por incluir contenido del nivel superior (tesquema.text = "Índice de contenidos."), podemos prescindir de ello, según el modo en que pensemos redactar el índice. Por ejemplo podemos hacer que el título principal de la diapositiva sea "ÍNDICE" y el índice propiamente dicho no tenga título, ocupando los epígrafes principales ese nivel. Te animo a que investigues esta opción.

Dejando pendiente esta cuestión, vamos a ver cómo incluimos los contenidos del esquema y cómo identificamos el nivel al que pertenece. Para ello tomaré como ejemplo el primer componente, ya que el resto se resuelve por repetición del procedimiento.
  1. Añadimos el parágrafo a la lista del conjunto de objetos parafraph (p1 = tesquema.add_paragraph())
  2. Dotamos de contenido textual a ese elemento (p1.text = "Título y subtítulo")
  3. Y finalmente indicamos el nivel al que pertenece (p1.level = 1), que en este caso es el primer nivel, pero que en otros, como el asignado a la variable p4a es el segundo (p4a.level = 2)
La repetición de este procedimiento nos permite crear, de forma sencilla, el índice de la presentación. Dado que se trata de una mera repetición de las mismas instrucciones, no es difícil simplificar el procedimiento mediante el uso de listas y bucles, pero de momento es incluso preferible que lo hagamos de forma repetitiva para asegurarnos el dominio de dicho procedimiento.

Documento. En este enlace puedes acceder al script que incluye el código explicado en esta entrada. Incluyo una modificación de la estructura del script para mejorar la diferenciación de sus partes.

miércoles, 21 de agosto de 2024

Evaluación. Ítem.

Ítem gráfico (b). Mapa interactivo.


Este tipo de ítem, basado en el uso de imágenes como [el anterior] está mucho menos representado en las pruebas de evaluación que aquel, aunque podemos considerarlo apropiado para el tratamiento de todas aquellas actividades que se basen en la localización de elementos en un "mapa" o gráfico complejo en el que se representan diferentes elementos.


La prueba CONCEBAS (Conceptos básicos) puede considerarse apropiada para aplicar este método de informatización del ítem, pero donde más aplicaciones puede tener es en la elaboración de materiales para la intervención: enseñanza y evaluación de vocabulario (en español o en lengua extranjera), identificación de elementos individuales en imágenes complejas, posicionamiento de elementos en un mapa geográfico...

Las bases técnicas de la elaboración de este tipo de ítem están expuestas [en esta entrada] en su parte final. Partiendo de lo visto en ella voy a aplicarlo a crear un ítem que puede servir para la evaluación o para la intervención; en realidad se trata de un ejercicio de vocabulario de la anatomía de la cara, basada en una lámina de Esther Moret García publicada en es.liveworksheets.com, sobre la cual se han construido otras aplicaciones, como el vocabulario de las partes de la cara en inglés.


En
 este caso trabajaremos la identificación del vocablo enunciado por el adulto sobre la imagen. Para ello sobrepondré una imagen transparente, asociando a ella la valoración (A-E /1-0) en función del acierto o fallo.

Como ya vimos [al tratar este procedimiento], el mayor trabajo está en organizar el material y dar el tratamiento adecuado a la imagen principal y a las imágenes que sirven de comando (1); los script y subrutinas no se diferencian del código creado para el trabajo con otros ítem basados en imágenes o gráficos, como podemos ver a continuación (2).

Script

Sub Boca

    Dim sOpcion As String

    sOpcion = "A"
    Resultado (sOpcion)

End Sub

Subrutina

Sub Resultado (Opcion As String)

Dim oHoja As Object, oCelda As Object

oHoja = ThisComponent.getSheets().getByName("Resultados")

oCelda = oHoja.getCellRangeByName( "B5")

oCelda.setString(Opcion)

oCelda = oHoja.getCellRangeByName( "C5")

If Opcion = "A" Then

oCelda.setValue(1)

Else

oCelda.setValue(0)

End If

End Sub

Documento. En [este documento] se desarrolla la propuesta que explico en la entrada.

NOTAS

(1) Eliminar la línea del contorno de la figura, dar el color a estas imágenes auxiliares que más se adecue a la principal, dar el grado de transparencia que cumpla el objetivo esperado... 
(2) Otra cuestión es el tratamiento del conjunto de ítem de la prueba o del ejercicio, pero en este caso nos limitaremos al tratamiento del ítem individual, por lo que los script creados son suficientes. LO que sí he añadido a la subrutina es la puntuación del ítem (sobre la celda C5), no sólo al registro de la respuesta. Con ello carece de sentido crear una función Calc que cumpla ese cometido.