miércoles, 26 de marzo de 2025

Python. Recursos.

Biblioteca openpyxl (1). Registro de datos.

Aunque es una forma un tanto grandilocuente de expresarlo, lo cierto es que en esta entrada aprenderemos a utilizar openpyxl para automatizar el registro de datos en una hoja de cálculo; el resultado es, valga la redundancia y el juego de palabras, la creación de un registro (individual) de datos. Aun no llegamos a la creación de una tabla de datos (y por tanto tampoco a crear una base da datos), pero damos un paso adelante en esta dirección.


Para crear un registro de datos basado en un libro Excel mediante un script Python, primeramente, llamar al módulo openpyxl de creación de la hoja de cálculo mediante la instrucción from openpyxl import Workbook. Hecho esto ya estamos en disposición de crear nuestra primera hoja de cálculo mediante la función (sin parámetro) Workbook(), que asociaremos a una variable para facilitar el trabajo que viene a continuación (Hoja = Workbook()). De este modo ya hemos creado una documento Excell (accesible también desde Calc), el cual contiene una hoja, por lo que ya podemos trabajar con ella, pero te aconsejo que lo siguiente que hagas sea guardar tu trabajo mediante la función save() que, esta sí, tiene como parámetro la dirección donde guardar el documento y el propio identificador de éste (nombre y extensión), todo ello asociado a la variable con la que se identifica el documento (hoja.save("Hoja1.xlsx") -> En este caso se entiende que el documento se guarda en el mismo directorio del script python). 

Aunque una única hoja puede ser suficiente para la mayoría de las tareas, habrá ocasiones en las que necesitemos disponer de más de una. Para ello necesitamos  crear más hojas mediante código, lo que es posible y sencillo mediante la función create_sheet() que recibe como parámetro el nombre que la hoja mostrará en el libro (vg. create_sheet("Hoja2")), aunque ese nombre no se debe confundir con el nombre de la variable con la que se accede a la hoja desde el script (vg. y para complicar un poco las cosas, hoja1 = hc_uno.create_sheet("Hoja2")). De este modo podremos crear tantas hojas como deseemos, bien de forma sucesiva, bien posicionándola mediante un segundo parámetro tipo integer que indica la posición (vg hoja0 = hc_uno.create_sheet("Hoja0",0) asociada a la variable hoja0 crea una hoja de nombre Hoja0 en la posición 0, esto es, en primera posición).

También podremos cambiar el nombre visible de las hojas mediante el atributo title (hoja5 = hc_uno.create_sheet("Hoja5",-1) -> hoja5.title ='Hoja3') -> Asociada a la variable hoja5 creamos una hoja en penúltima posición a la que damos por nombre Hoja5, pero después modificamos ese nombre por Hoja3, aunque en el script deberemos seguir refiriéndonos a la hoja por su variable (hoja5).

Esta diferencia es fundamental para posicionar datos en las celdas de las hojas, ya que debemos utilizar los nombres de las variables con las que éstas están referenciadas (vg. hoja5['B1'] = 'Estas en la Hoja 3') -> escribe en la celda B1 de la Hoja3 el string 'Estas en la Hoja 3' aunque para ello usamos como referencia la variable hoja5.

La anterior es la forma más sencilla y directa de escribir contenido en una celda, pero también podemos usar la función cell() asociada a la variable con la que identificamos la hoja. Esta función recibe tres parámetros: la fila, la columna y el dato (o variable) a escribir (hoja5.cell(row=2, column=2, value='Segunda forma'))

Y hablando de columnas (column) y filas (row), también podemos grabar colecciones de datos en una tabla mediante un ciclo for, acercándonos así al objetivo de crear una tabla (base) de datos.

Para ello primero establecemos una hoja como hoja activa, esto es, la hoja sobre la que copiaremos los datos (sheet = hc_uno.active) y forzamos que ésta sea la nombrada como Sheet en el libro (sheet = hc_uno['Sheet'])

... después creamos nuestra colección de datos (en esta ocasión de forma directa)...

datos = [('id','Nombre', 'Edad'),
         (0,'José',35),
         (1,'Lucas',27),
         (2,'Mario',31),
         (3,'Antonio',28),
         (4,'Sonia',24)
    ]

... y después desarrollamos un ciclo for sobre el parámetro row 

for row in datos:
    sheet.append(row)

Documento. Aunque no sea gran cosa, te dejo acceso al script que contiene el código trabajado en esta entrada. Con el tiempo ampliaremos el código para darle forma y utilidad; de momento es más puro ejercicio para aprender a manejarnos con openpyxl.



martes, 25 de marzo de 2025

Textos. Python.

Biblioteca python-docx (4). Formatos


En esta entrada sobre el uso de funciones de formato en python-docx trataré una cuestión que se me antoja de suficiente interés como para no prescindir de ella en este breve recorrido por esta biblioteca: el sangrado del texto.


Este interés viene dado, como en los casos anteriores, por la frecuencia con se emplea en el trabajo con textos, especialmente el sangrado de la primera línea del párrafo. Por motivos de procedimiento dejaré esta cuestión para el final, ya que antes es conveniente explicar cómo se procede para sangrar el párrafo, algo que no es de uso frecuente, dicho sea de paso.

Suponiendo que sí lo sea, vamos a sangrar nuestro párrafo (no sólo la primera línea) por la izquierda (también podemos hacerlo por la derecha). Para ello, tras importar las funciones de trabajo con pulgadas (from docx.shared import Inches),  desarrollamos la siguiente secuencia:
  1. Escribimos el párrafo según el procedimiento común (parrafo1 = documento.add_paragraph(txt)), que en este caso emplea la variable txt como parámetro en lugar del texto del párrafo.
  2. Accedemos a la propiedad general de formato del párrafo (formateoIzq = parrafo1.paragraph_format) que referenciamos sobre la variable formateoIzq
  3. Y sobre esta variable accedemos a la propiedad left_indent a la que damos valor Inches(1.5) (en este caso) (formateoIzq.left_indent = Inches(1.5))
En realidad los pasos 2 y 3 son una forma de evitar la escritura de una instrucción larga, pero ésta es válida, y parrafo1.paragraph_format.left_indent = Inches(1.5) es equivalente a las dos anteriores.

Si quisiéramos que el sangrado fuera a la derecha, sería suficiente con sustituir la propiedad left_indent por right_indent. Así de sencillo.

De modo similar, si en lugar de sangrar todo el párrafo sólo quisiéramos sangrar la primera línea, recurriríamos a la propiedad first_line_indent como alternativa a cualquiera de las dos anteriores. Por aclararlo mejor: el tercer paso del proceso se concretaría como formateoL1.first_line_indent = Inches(1) (por claridad del código en el scritp, sustituyo la variable formateoIzq por formateoL1). El valor numérico pasado como parámetro a Inches() puede ser positivo (como en este caso) o negativo (vg. Inches(-1)), lo que modifica el aspecto del párrafo, pero no supone ninguna modificación de la lógica de script.

Documento. Este es el enlace al script explicado en esta entrada; y con esto doy por finalizada la serie de entradas dedicadas a la biblioteca python-docx. Aunque no pretendo haber agotado todo lo que hay que aprender sobre ella, sí creo haber tratado los temas de mayor interés práctico.

Textos. Python.

Biblioteca python-docx (3) Formatos


No soy yo muy partidario de dedicar tiempo a estas cuestiones, teniendo por delante tantas cosas aun por resolver, pero no queda otro remedio que incluir algunas cosas referidas al formato cuando se trata de generar documentos de forma automática. Por ello dedicaré esta entrada a estas cuestiones; las mínimas.


Por empezar por algún lado, y por eso de la frecuencia de uso (y la utilidad), se me ocurre que nos puede interesar aprender a formatear los párrafos centrándolos, justificándolos, o alineándolos a derecha o izquierda.

Para ello lo primero que tenemos que hacer es añadir el acceso a un conjunto de funciones mediante la instrucción pertinente (from docx.enum.text import WD_ALIGN_PARAGRAPH)  y tomaré un texto suficientemente largo para que se puedan observar los diferentes ajustes. Este texto queda asociado a la función add_paragraph() como parámetro (parrafo1 = documento.add_paragraph(texto1)) y se escribe en el texto sin formato de ningún tipo; pero si a continuación añadimos la instrucción parrafo1.alignment = WD_ALIGN_PARAGRAPH.RIGHT, el párrafo pasa a estar alineado a la derecha, así que sólo tenemos que sustituir la palabra RIGHT por sus alternativas (.LEFT - .RIGHT - .CENTER - .JUSTIFY) , para que se justifique de acuerdo a lo ellas.

Esta es, posiblemente, la forma más sencilla de trabajar con formatos en python-docx, ya que otras opciones de formateo del texto exigen mayor complejidad en su codificación. Por ejemplo, algo tan sencillo como escribir en negrita , cursiva o subrayado requieren otro tipo de estrategias basadas en el uso de la función add_run()Supongamos, por ejemplo, que queremos destacar una palabra dentro de un párrafo escribiéndola en negrita. El procedimiento sería el siguiente:
  • Primero escribimos el texto que precede a la palabra a resaltar como párrafo sin formato (parrafo=documento.add_paragraph('En este segundo párrafo vamos a poner palabras en '))
  • Y después, para escribir la palabra (o las palabras) en negrita asociamos a la variable parrafo la función ad_run() incluyendo como parámetro dicha palabra, seguida del atributo booleano .bold con su valor en True (parrafo.add_run('negrita').bold = True). Para cursiva (.italic = True) y para subrayado (.inderline = True), actuaríamos igual; incluso para añadir más texto sin ninguno de estos tres formatos deberemos emplear la función add_run() asociada a la variable parrafo (v.g. parrafo.add_run(' y palabras en '))
Un ejemplo de complejidad de formateo que yo considero extremo en cuanto a complejidad (por comparación con lo simple que resulta "manualmente") es definir el tamaño y el tipo de fuente, siendo como es una funcionalidad que podemos considerar básica en el uso de un procesador de texto. En este caso...
  • Primero debemos importar un conjunto de funciones específicas .docx (from docx.enum.style import WD_STYLE_TYPE) requiriendo haber importado previamente el manejo de valores de tamaño de fuente (from docx.shared import Pt)
  • Después debemos asociar a una variable (v.g. styles) el manejo de las funciones de estilo asociadas al documento que referenciamos mediante la variable documento a la que previamente se asoció el objeto creado con la función Document() (styles = documento.styles)
  • Sobre la variable styles llamamos a la función add_style() que recibe dos parámetros: el primero un string con la denominación que vamos a emplear (vg. 'Calibri_12') y un segundo parámetro con referencia al atributo WD_STYLE_TYPE.CHARACTER (todo ello queda asociado a la variable -vg- charstyle -> charstyle = styles.add_style('Calibri_12', WD_STYLE_TYPE.CHARACTER))
  • Después accedemos al objeto charstyle.font, que a su vez asignamos a la variable obj_font
  • Y sobre ella al atributo tamaño (obj_font.size = Pt(12)) y nombre de la fuente (obj_font.name = 'Calibri')
Una vez que ya tenemos creado este conjunto de características puedes usarlo para añadirlo como segundo parámetro de la función add_run() asociada a la variable parrafoX para que el texto que se escriba quede formateado según la fuente y el tamaño que definiste antes. Esto se realiza en dos pasos:
  • Se asocia el añadido de la párrafo al documento a una variable (parrafo1 = documento.add_paragraph())
  • Y sobre ella se aplica la función add-run() con dos parámetros: el texto a escribir y el atributo style al que se asigna el identificador del formato que se estableció según el procedimiento anterior (parrafo1.add_run(texto1, style = 'Calibri_12'))
Este procedimiento es especialmente interesante cuando se va a trabajar con varios estilos de letra (fuente y tamaño), aunque se puede simplificar cuando el modo de proceder va a ser más sencillo, accediendo al atributo fuente del objeto run (run = parrafo1.runs[0] -> font = run.font -> font.name = 'Calibri' + font.size = Pt(12)). Todo este código queda en el script que acompaña esta entrada comentado para que no interfiera en el funcionamiento del algoritmo de base.

DocumentoNo sé si larga, pero algo liosa sí que ha sido esta entrada, así que va siendo hora de finalizarla con la ya esperable referencia al script asociado.
 

domingo, 23 de marzo de 2025

Textos. Python.

Biblioteca python-docx (2) Tablas y gráficos


Aclarar antes de nada que estoy empleando el término gráfico como sinónimo de imagen, con independencia de que esta imagen represente un paisaje, una persona o un gráfico de barrar. Dicho esto, en esta entrada trataré sobre estos potenciales componentes de un documento de texto por ser elementos que se pueden necesitar para la elaboración de los documentos que solemos crear como SEO. La finalidad de tratar estos temas es, como en otras ocasiones, proveer de recursos para la intervención profesional de los SEO; muy lejos de la de hacer a un OE experto en el manejo de Python-docx.


Desde esta orientación eminentemente práctica, empecemos por aprender a incluir gráficos (imágenes) en nuestro documento. Para ello, y dando por resueltos los procesos previos de creación del documento y la inclusión de los contenidos ya conocidos por la entrada anterior,  para incluir una imagen en un texto es suficiente con hacer uso de la función add_picture(), que precisa obligatoriamente un único parámetro; un string con la dirección de la imagen, incluyendo nombre y extensión, si bien cuando la imagen está en el mismo directorio que el script, es suficiente con el nombre y extensión.

Es posible pasar otros dos parámetros o sólo uno de ellos, con la indicación dimensional (height y/o width) y el o los valores necesarios para dimensionar la imagen en pulgadas (v.g. width=Inches(1.25)). Así es en nuestro este caso (documento.add_picture('Aprendizaje.jpg', width=Inches(1.25))) y por ese motivo necesitamos indicar al inicio del script que también precisamos importar el manejo de Inches (from docx.shared import Inches)

Sigamos ahora con las tareas necesarias para implementar una tabla en el documento, empezando por los datos que ésta va a contener, los cuales son tratados en nuestro documento de ejemplo como registros de una base de datos, motivo por el que creamos una tupla de tuplas que contiene tantos registros como deseemos y cada uno de ellos tantos elementos como columnas va a tener nuestra tabla.

registros = (('3', 'Entrevistas', 101),('4', 'Reuniones', 42),('5','Evaluaciones', 36))

No es precisamente la forma más sencilla de trabajar (y crear) una tabla, pero así aprendemos cómo podemos manejar el acceso a sus celdas para introducir los datos que deseamos contengan.

Pero crear la tabla es en realidad mucho más sencillo, siendo suficiente con emplear la función add_table(), que requiere dos parámetros integer: las columnas y las filas (tabla = documento.add_table(rows=1, cols=3))

Las complicaciones empiezan cuando decidimos que nuestra tabla tiene que tener un encabezado que clarifique su lectura. En ese caso (que es opcional, recuerdo) se requiere crear una variable (encabezado) que referencie la siguiente expresión (encabezado = tabla.rows[0].cells). Gracias a ella podemos acceder a las celdas (.cells) primera fila (rows[0].cells) de la tabla creada (tabla.rows[0].cells). Sobre esta variable iremos identificando cada una de las celdas del encabezado e incluyendo en ellas el texto del mismo (vg encabezado[0].text = 'Identificador')

Para incluir ahora el contenido de nuestros registros en la tabla, en este caso (y es un buen ejemplo de cómo podemos actuar) utilizamos un bucle for de cierta complejidad en cuanto a formulación, pero sumamente funcional (for id, cont, num in registros:). Básicamente lo que hace este bucle es recorrer nuestra base de datos (registros), elemento por elemento (id, cont, num in registros:) para posicionarlos según los criterios establecidos (vg, primero (primera celda de la fila) ... row_cells[0].text = id, después...) según la estructura a la que anteriormente se ha accedido, asociándola a la variable row_cells gracias a la función add_row() (row_cells = tabla.add_row().cells). 

Obsérvese que esta instrucción (row_cells = tabla.add_row().cells) es muy similar, pero en realidad muy diferente de la que nos sirvió para crear el encabezado (encabezado = tabla.rows[0].cells), por lo que no deben confundirse.

Este uso del bucle for puede que nos resulte un poco complicado en estos momentos (aun estamos empezando a programar en Python), así que necesitamos conocer otra forma de utilizar una tabla, como, por ejemplo, para una función muy común en la composición de un texto: posicionar texto (una serie de párrafos) de forma tabular. Para estos casos podemos trabajar con un código más sencillo. Veamos:
  • Creamos la tabla igual que antes (tabla2 = documento.add_table(rows = 2, cols = 2))
  • Accedemos a la primera fila (celdas0 = tabla2.rows[0].cells), como ves con el mismo procedimiento que antes usamos para crear el encabezado
  • Y posicionamos el contenido textual en las celdas de esa fila (v.g. celdas0[0].text = "Primera")
Deberemos repetir el procedimiento para cada una de las filas (celdas1 = tabla2.rows[1].cells) y sus respectivas celdas (celdas1[0].text = "Segunda"), ya que por algo es un procedimiento manual. Pero estoy seguro que dentro de poco sabremos implementar un bucle para agilizar el procedimiento, no tan elegante y complejo como el presentado antes, pero suficiente para nuestros fines.

Documento. Desde este enlace puedes ver (y descargar) el script que contiene el código de esta entrada.

Textos. Python.


Biblioteca python-docx (1) 





Elementos comunes


Gracias a esta biblioteca podemos automatizar desde Python la creación de documentos, lo que no es equivalente a automatizar esos mismos documentos en lo que se refiere a su contenido. Esta diferencia es importante, sobre todo para no generar falsas expectativas. A pesar de esta limitación, no deja de ser un paso importante, aunque deberá complementarse con otros procedimientos para alcanzar el objetivo de la automatización documental.


Lo que se pretende explicar en estas entrada (esta es la primera) se limita a los procedimientos más básicos, sin menoscabo de que posteriormente retomemos estas cuestiones para avanzar en su desarrollo. En lo que a esta entrada toca, el contenido se limitará a la creación del archivo y la escritura de título y contenido textual, incluyendo los listados.

Ya sabemos por una [entrada anterior], para trabajar con python-docx necesitamos haber instalado previamente esta biblioteca, cosa que hacemos desde Símbolo del sistema mediante pip install python-docx. Después, para incorporar las funciones a los script deberemos utilizar instrucciones, especialmente la siguiente, que permite crear documentos de texto (Word - Writerfrom docx import Document. No es la única necesaria, pero para los objetivos de esta entrada sí.

Empezamos por crear (documento = Document()) y guardar (documento.save('documento.docx')) el documento. La primera al inicio del script y la segunda al final.

Lo propio de un documento es que tenga título, así que utilizaremos la siguiente expresión basada en la función add_heading(), que requiere dos parámetros, el primero es la expresión textual del título (se puede sustituir por una variable string) y el segundo es una variable numérica (level = 0) que representa el nivel del título y que puede expresarse directamente como número (documento.add_heading('TÍTULO del documento', level = 0)documento.add_heading('TÍTULO del documento', 0) son equivalente)

La escritura de texto (mediante párrafos) es sumamente simple gracias a la función add_paragraph() cuando dicho gráfico no presenta ningún tipo de característica de formato. El parámetro de dicha función es el texto a introducir, o en su caso, la variable que lo referencia (parrafo1 = documento.add_paragraph('Párrafo simple...). Se puede implementar directamente, sin ser referenciado previamente a una variable, como es este caso).

Aunque no es caso, dado el escaso contenido actual de nuestro documento, podríamos necesitar, en un momento dado, provocar un salto de página. Para ello disponemos de la función add_page_break(), que carece de parámetros, y que va asociada, al igual que las anteriores al objeto document() creado previamente (documento.add_page_break()).

Antes de finalizar esta entrada, veremos cómo construir un listado, lo que en realidad consiste en implementar un segundo parámetro a la función add_paragraph() vista antes; se trata del parámetro style, variable string que tiene asociado la denominación del elemento gráfico del listado (documento.add_paragraph('Primer elemento de la lista', style='List Bullet')) (style='List Number' como alternativa).

Documento. [Este enlace] te da acceso al script explicado en esta entrada.

sábado, 22 de marzo de 2025

Python. Recursos.

Biblioteca OpenPyXL

Esta biblioteca es a las hojas de cálculo (Excell - Calc) lo que python-docx es a los documentos de texto. Con esto queda dicho lo fundamental que vamos a tratar en esta entrada, aunque sea necesario dar algún que otro detalle más. A ello vamos.



Y eso más que vamos a decir empieza por indicar que necesitamos instalar la biblioteca desde Símbolo del sistema mediante la instrucción pip install openpyxl. Posteriormente podremos consultar su documentación en esta página., aunque también podemos basarnos en otras más sencillas para una introducción a lo fundamental de su manejo. Esta página podría servir para tal fin.

Para trabajar con los módulos que componen la biblioteca openpyxl podemos utilizar esta instrucción (import openpyxl) que importa el módulo al completo, o utilizar este otro tipo de instrucciones (from openpyxl import workbook) que nos permite trabajar con funciones y atributos específicos, como en este caso, que permite ejecutar las principales y básicas instrucciones para automatizar el trabajo con hojas de cálculo.

Al tratarse del trabajo con hojas de cálculo, debemos tener en cuenta que nos interesa tanto crear y trasladar datos a la hoja de cálculo (input) como acceder a los datos grabados en una hoja de cálculo, dado que ésta cumple funciones de base de datos. Esto, trasladado al estudio del código básico que desarrollaremos en las entradas que siguen (empezando por ésta), implica centrar la atención en los dos procedimientos básicos: crear una hoja de cálculo como fuente de datos y acceder a los datos contenidos en esa base de datos. Parece novedoso (y lo es por comparación con python-docx y python-pptx), pero en realidad no es nada que no hayamos hecho ya trabajando con OOo Basic.


Textos. Python.


Biblioteca python-docx





Cuando lo que se necesita es automatizar la creación de un documento MS-Word (lo que también equivale a decir accesible desde LO-Writer), python-docx es una opción excelente: gratuita, de fácil acceso, sencilla de manejar y muy funcional.


Ya explicaré con más detalle por qué y cómo usar (a nivel básico) esta biblioteca, así que aquí sólo quiero adelantar lo elemental y necesario, que es lo que sigue.

La biblioteca python-docx no viene instalada por defecto (ya se sabe que la versión básica de Python es muy ligera y simple), así que necesitaremos instalarla desde Símbolo del sistema mediante la instrucción pip install python-docx

Para usarla en los script deberemos llamar específicamente a aquellos módulos que pensemos utilizar, siendo el más básico (e imprescindible) form docx import Document que nos permite crear un documento ejecutar sobre él las principales acciones, incluyendo la de guardarlo. Otro módulo de interés y uso frecuente es el que nos permite trabajar con formatos (from docx.enum.text import WD_PARAGRAPH_ALIGMENT).

Para finalizar esta breve introducción, de forma complementaria a lo que se explica en Documentos, te sugiero la atenta lectura de la documentación oficial de la biblioteca. Te dejo algunos enlaces de interés:

Textos. Python

Ofimática con Python


Dentro de las muchas utilidades que nos ofrece Python, las más próximas a los objetivos nucleares de este blog son las que tienen que ver con la ofimática. Aunque existen diferentes enfoques, mi opción actual tiene que ver con la creación automatizada de los principales documentos ofimáticos en términos de uso por parte de los SEO: documentos de texto, hojas de cálculo y presentaciones.



Aunque LibreOffice (LO) presenta la opción de crear y trabajar con script Python "internos", esto es, script con igual funcionalidad que los creados en OOo Basic, hasta donde yo sé, Python no cuenta con bibliotecas que permitan crear documentos LO "externamente", esto es, sin que sea necesario trabajar desde un servicio de la suite. Microsoft Office (MSA) sí, lo que constituye una ventaja a su favor. No obstante es factible crear documentos MSA y seguir trabajando con la suite LO, ya que ésta accede sin dificultad a los documentos creados para la primera.

Dentro de los productos ofimáticos, los de mayor uso (y funcionalidad) para los SEO son los documentos de texto, seguidos a mucha distancia y escasa entre ellos, por las hojas de cálculo y las presentaciones (tipo Power Point). Python cuenta con bibliotecas específicamente desarrolladas para automatizar la creación de estos documentos en soporte MSA.

Podemos automatizar la creación de documentos de texto (Word - Writer) mediante las utilidades que ofrece la biblioteca python-docx, crear hojas de cálculo (Excell - Calc) mediante openpyxl y generar automáticamente presentaciones mediante python-pptx (Power Point - Impress)
 

jueves, 20 de marzo de 2025

mav. Python


Biblioteca python-pptx




Esta biblioteca forma parte de un conjunto de recursos Python pensados para facilitar el trabajo con la suite ofimática MSO; concretamente con python-pptx podemos automatizar la creación de presentaciones Power Point.


Dada la versatilidad y compatibilidad de LibreOffice, es posible trabajar desde esta suite con cualquier documento creado para MSO, por lo que resulta que el uso de python-pptx también es compatible con la gestión de las presentaciones mediante LO-Impress.  Dicho esto para tranquilidad de los amantes del software libre, vamos a tratar en esta entrada sobre python-pptx como biblioteca.

Lo primero que deberemos hacer es importarla desde Símbolo de sistema mediante la instrucción pip install python-pptx; esto es necesario por no ser esta un biblioteca standard de Python.

Además tiene la peculiaridad de que, normalmente, y al contrario que en otras librerías, los script Python que hacen uso de ella no la llaman mediante la instrucción genérica (import python-pptx), aunque también puede hacerse así, sino mediante la llamada a cada una de sus funcionalidades específicas. Por ejemplo, para todo lo referentes (y nuclear) a la creación de una presentación se llama a las funciones Presentation() (from pptx import Presentation) y para trabajar con instrucciones que requieren dimensionar las formas que contienen las diapositivas (cosa que se hace en pulgadas), se llama a Inches (from pptx.util import Inches)

Por otro lado, al menos la creación de un modelo básico de presentación resulta ser bastante sencillo, lo que permite automatizar la creación de presentaciones Power Point de estas características, que se ajustan perfectamente a lo que necesitamos como alternativa a la creación de informes escritos para la presentación a colectivos de los resultados de evaluación grupal (también podría ser individual, pero generalmente es innecesario y no sustituye a la creación del informe sobre documento) o del análisis de datos. Evidentemente nada impide utilizar este recurso también para crear presentaciones específicamente informativas sobre un determinado tema, pero es este caso, si la presentación es larga y compleja, posiblemente automatizarla requiere adentrarse en el conocimiento de esta interesante biblioteca y sus múltiples opciones.

Para facilitarte esta tarea te dejo aquí enlaces a su fuente fundamental de información y a tres páginas con contenidos relevantes para la automatización de presentaciones:

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.


martes, 18 de marzo de 2025

MAV. Python


Python-pptx. Gráfico (1)






Imagen


Tras los textos, las imágenes son el componente más frecuente en una presentación informativa. Se trata generalmente de gráficos estáticos que simplemente son añadidos a la diapositiva por su función informativa y/o estética.


Los gráficos, y más en las presentaciones que aquí pretendemos automatizar, pueden reducirse en cuanto a tipología a imágenes externas que se incluyen en la presentación, pero también pueden especiales, como las tablas de datos y los gráficos estadísticos. En esta entrada trataré sobre el caso genérico, que podría ser suficiente para la mayoría de los casos, ya que tablas y gráficos se pueden convertir fácilmente en imágenes mediante el simple uso de la función captura de pantalla.

La inclusión de imágenes externas en una presentación es un proceso muy sencillo. Empieza accediendo a la imagen, bien mediante una dirección absoluta (img_path = 'D:/Aprendizaje.jpg' en el supuesto de la que imagen esté en el directorio raíz de la unidad D), bien relativa (img_path = 'Aprendizaje.jpg' cuando la imagen está en el mismo directorio que el script Python) y finaliza incluyendo la imagen en la diapositiva (pic = slide.shapes.add_picture(img_path, left, top)) mediante la función add_picture() que recibe tres parámetros:
  • el directorio donde se encuentra la imagen (variable asociada img_path)
  • y los posicionamientos cartesianos left y top bien como variables previamente asignadas (left = top = Inches(1)o bien mediante valores numéricos directos.
Recuerda que, al igual que con el text box, ese posicionamiento puede dar lugar a algunos problemas que habrá que solucionar probando los valores que mejor se ajusten a nuestras necesidades.

Entre ambos momentos, como es de esperar, está la creación de la diapositiva (también de tipo vacío, valor 6) (diapo4 = mi_presenta.slide_layouts[6])  y su añadido a la colección de diapositivas de la presentación (slide = mi_presenta.slides.add_slide(diapo4)).

Documento. Accede desde este enlace al nuevo script. También debes descargar esta imagen.


MAV. Python


Python-pptx (3)



Texto

Una vez creado el índice, entramos en la parte de la creación de la presentación en la que vamos dotando a ésta de contenido, y como ya dijimos, el contenido se va a concretar bien como contenido textual, bien como contenido gráfico. Vamos a tratar en esta entrada sobre cómo crear diapositivas con contenido textual.


Antes de empezar, deberemos importar dos utilidades de la biblioteca para que el script pueda acceder a las funciones necesarias (from pptx.util import Inches, Pt). Hecho esto, tenemos que crear una nueva diapositiva, que en este caso se ajusta al formato 6 (diapositiva vacía) (diapo3 =mi_presenta.slide_layouts[6]) y añadirla a la lista de diapositivas de la presentación (diapo3 = mi_presenta.slides.add_slide(diapo3)).

Viene a continuación un proceso no exento de cierta complicación: el dimensionado de lo que será el objeto text box (caja de texto), lo cual se realiza mediante una función (add_textbox()) que requiere cuatro parámetros numéricos, dos de posicionamiento (izquierda -left- y arriba -top- respecto a la diapositiva) y dos de dimensión (ancho -width- y alto -height- de la forma) todas ellas expresadas en pulgadas (1 pulgada = 2,54 cm), lo que hace que sea conveniente declarar previamente cuatro variables a las que asignar los valores respectivos (vg width = height = Inches(8)). Dado que ajuste del text box a la diapositiva es una cuestión de gustos, vas a tener que probar valores hasta que encuentres el que mejor se ajuste a tus necesidades, tarea esta que te puede llevar tiempo. Una vez que lo consigas puedes añadir la forma text box a la diapositiva (txBox = diapo3.shapes.add_textbox(left, top, width, height)) y definir la variable que te va  a permitir acceder a ella para escribir el contenido que desees (tf = txBox.text_frame)

Aunque no es prescriptivo, igual que te aconsejo trabajar con valores numéricos asociados a variables, también te aconsejo que utilices variables string para contener los textos que desees escribir; esto te facilitará la tarea siguiente (vg. titulo = "Los cuentos y los niños").

Y llega la hora de escribir el contenido en nuestro text box. Empezaremos por ponerle un título (tf.text = titulo), que no deja se ser un texto especial (por cómo es tratado y por la función que tiene) y paso seguido escribiremos el contenido, esto es, el párrafo o los párrafos que contendrá nuestro text box. Este proceso tiene dos fases:
  • Añadimos el párrafo al text box (p0 = tf.add_paragraph())
  • Y le damos contenido (p1.text = parrafo1)
  • Después podemos añadir formato al texto (p1.font.size = Pt(10)), aunque no siempre es necesario ni funciona como sería de esperar (eso también).
Cuando el texto (los párrafos) tiene una longitud que se ajusta al tamaño del text box y a la diapositiva como lienzo, no hace falta más ajustes; pero cuando la extensión del párrafo supera esas dimensiones se produce un efecto de desbordamiento que altera la visualización del contenido. En este caso es necesario llamar a una función que reajusta el texto al ancho del text box, generando automáticamente las líneas de texto necesarias, lo que evita que parte del texto que oculto. Esto es lo que hace la última línea de instrucciones de esta sección del script: tf.fit_text().

Documento: En este enlace puedes acceder al script que incluye el código explicado en esta entrada.