Mostrando entradas con la etiqueta Procedimientos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Procedimientos. Mostrar todas las entradas

martes, 15 de julio de 2025

Textos. Procedimientos

Identificación de segmentos textuales


Después de seleccionar el texto a automatizar, algo que no debería resultar complicado ya que materia prima tenemos en abundancia, procedemos a identificar los diferentes segmentos y prepararlos para automatizar su conversión en elementos de la matriz-base.


Las apariencias engañan, y las palabras anteriores pueden encubrir más dificultad de la que se quiere informar. No lo digo por eso de elegir el documento-base, que tampoco es tan sencillo como lo pinto (algo de trabajo lleva quedarse con aquel ejemplar que más nos satisface); lo digo por el trabajo que supone eliminar del documento todo aquello que no es el núcleo de contenido textual o que no es recomendable abordar mediante este procedimientos de automatización (1), tarea esta que resulta imprescindible para entregar un documento que se pueda manejar mediante código.

Resuelta esta cuestión (que tampoco es insalvable), es posible realizar la revisión del contenido, entendiendo por tal la identificación de los diferentes segmentos, de los cuales identificaremos su fin mediante una marca formada por caracteres que sean reconocidos como tales por las funciones de cadena y que, a la vez, no sea posible que se encuentren como parte del propio texto, ya que, en ese caso, se producirían segmentaciones no deseadas.

Por partir de una referencia concreta que tiene la virtud de haber sido planteada desde otras perspectivas de trabajo y que, además presenta un cuerpo textual que no ofrece dificultad, pero que como documento no se puede afrontar únicamente desde esta opción de automatización, voy a plantear el trabajo sobre una sección del documento-soporte llamado Becas NEE (2).

Lo que del proceso anterior deriva del documento-base en un cuerpo textual es lo que se recoge [en esta entrada] y que queda aquí simplificado como sigue (3):

A efectos de participación en la convocatoria de ayudas para alumnado con necesidad específica de apoyo educativo del Ministerio de Educación Cultura y Deporte, para el curso académico 2020/2021D. Joaquín González López, orientador del EOE de Avilés emite el siguiente informe específico correspondiente al alumno Antonio Jiménez Montoya, escolarizado en el centro CP Piedras BlancasSegún consta en el Dictamen de escolarización fechado el 12/10/2019Antonio es un alumno con NEE derivadas de discapacidad auditiva que requiere apoyos de Audición y Lenguaje y Pedagogía Terapéutica. En este informe se especifica la asistencia educativa que requiere el alumno, así como las condiciones que debe reunir ésta para garantizar la debida atención de las necesidades educativas específicas que presenta.


El código basado en la función Split() que se necesita para realizar la segmentación del texto (una cadena al fin y al cabo) ya ha sido explicada [en esta entradapero antes de crearlo deberemos plantear dos cuestiones: dónde ubicar el texto y cómo tratar determinadas partes del mismo.

La primera de estas cuestiones es de orden práctico y tiene que ver con el diseño del soporte, pero también con cómo conceptualizamos el procedimiento de automatización, entendiendo por esta segunda consideración la posibilidad de que nos lo planteemos como algo que corresponde desarrollar directamente al profesional, como parte de sus responsabilidades y en función de las competencias informáticas que ha adquirido.

Esto supone ir más allá de que un profesional especialmente y extraordinariamente competente cree un docap y lo ponga a disposición del resto de los compañeros para que ellos, meros usuarios, lo utilicen en su trabajo.

Cabe esta opción, evidentemente, pero el actual planteamiento también hace posible esta otra: cada uno de nosotros, yo mismo, como orientadores somas capaces de desarrollar procedimientos de automatización de cualquier documento profesional, vg. este documento concreto, para uso personal y/o del colectivo. Cierto que puedo cederlo a otro/s compañero/s, pero inicialmente está pensado en función de mis necesidades, por lo que está adaptado a mi (personalizado) (4). Para crearlo yo orientador hago uso de mis conocimientos de OOo Basic, lenguaje que utilizo tanto para crear y desarrollar el procedimiento como para manejarlo una vez creado. Uso OOo Basic y los servicios OpenOffice que necesito (en este caso Calc y Writter).

La consecuencia de todo ello es que opto por automatizar determinado documento (ahora el que he presentado antes) para lo que empiezo por trabajar sobre su contenido textual después de realizar una copia del mismo en Writer (primera fase del procedimiento). Una vez adaptado introduzco los marcadores de los segmentos (#), que sitúo al final de los mismos. 

La segunda parte de esta fase consiste en el traslado del texto creado a Calc, servicio sobre el que, por motivos de eficiencia, se desarrollaré las restantes partes del procedimiento, a excepción de la última, en la que, por motivos obvios (5), volveré a utilizar Writer.

En teoría, tras lo hecho y expuesto ya estamos en disposición de iniciar la segunda fase del procedimiento, pero antes de llevar la teoría a la práctica me debo plantear una cuestión importante, derivada de la distinción entre personalización (en función del profesional como usuario) y automatización. Me explico:

Ciertos segmentos del texto-base...

D. Joaquín González López, orientador del EOE de Avilés emite el siguiente informe específico correspondiente

... pueden ser personalizados, ya que se refieren al profesional que realiza el informe, que será siempre el mismo (6). Partimos de la anterior consideración, así como de valorar las repercusiones que tiene no personalizar el documento en lo que afecta al tratamiento de variables-input y de variables-condicionadas (7); añado también la conveniencia de aplicar el principio de simplicidad, que se concreta como transformación del componente más complejo al más simple, y que en este caso consiste en tratar esos segmentos como texto fijo. Por todo ello planteo que antes de abordar la segmentación conviene realizar la personalización del texto.

Este proceso consiste en sustituir el nombre y apellidos del OE del documento-base por el nuestro, así como el de mi SEO. En consecuencia, en función de mi género, modifico las variables gramaticalmente condicionadas, esto es, tratamiento de cortesía (D vs ) y denominación profesional (orientador vs orientadora). El resultado es que me ahorro tratar 5 variables y convierto una frase compleja en un único segmento textual calificado como texto fijo (tf) (8).

Tras lo anterior, aplicando el procedimiento de identificación y marcado de los segmentos textuales, obtengo el siguiente texto-base que queda recogido en el documento Writer auxiliar (AutoDocTxt.odt), cuyo contenido es el siguiente (9):

A efectos de participación en la convocatoria de ayudas para alumnado con necesidad específica de apoyo educativo del Ministerio de Educación Cultura y Deporte, para el curso académico#2020/2021#.##D. Joaquín González López, orientador del EOE de Avilés emite el siguiente informe específico correspondiente#al alumno#Antonio#Jiménez Micó#,#escolarizado#en el centro#CP Piedras Blancas.##Según consta en el Dictamen de escolarización fechado el#12/10/2019#,#Antonio#es un alumno#con NEE derivadas de#discapacidad auditiva#que requiere apoyos de#Audición y Lenguaje y Pedagogía Terapéutica.##En este informe se especifica la asistencia educativa que requiere#el alumno#, así como las condiciones que debe reunir ésta para garantizar la debida atención de las necesidades educativas específicas que presenta.

Ahora podemos trasladar manualmente (copiar y pegar) el texto-base a una hoja de cálculo sin más, pero también podemos hacerlo a un documento Calc previamente acondicionado (10), lo cual es, cuanto menos, aconsejable por el adelanto de trabajo que nos supone. También podemos crear un script que automatice el copia-pega, que podremos utilizar en posteriores ocasiones, con las debidas modificaciones. Ese script se podría implementar sobre el documento Writer o sobre Calc, opción que elijo en este caso (11). Este es el script (12):

Sub CopiarTexto

Dim sRuta As String
Dim mOpciones(0) As New "com.sun.star.beans.PropertyValue"
Dim oDoc As Object
Dim NombreDoc As String
 
NombreDoc = "AutoDocTxt"

'Acceder al documento. Sustituir la ruta por la propia.
sRuta = ConvertToUrl(Ruta_absoluta_del_documento & NombreDoc & ".odt")
oDoc = StarDesktop.loadComponentFromURL( sRuta, "_blank", 0, mOpciones() )

'Copiar el contenido del documento AutoDocTxt
dim document   as object
dim dispatcher as object

document   = ODoc.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())
dispatcher.executeDispatch(document, ".uno:EndOfDocumentSel", "", 0, Array())
dispatcher.executeDispatch(document, ".uno:Copy", "", 0, Array())

'Pegar el texto en Calc
dim documentCalc   as object
documentCalc   = ThisComponent.CurrentController.Frame
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "ToPoint"
args1(0).Value = "$A$1"
dispatcher.executeDispatch(documentCalc, ".uno:GoToCell", "", 0, args1())
dispatcher.executeDispatch(documentCalc, ".uno:Paste", "", 0, Array())

'Cerrar el documento Writer que contiene el texto
oDoc.close(True)
 
End Sub


NOTAS

(1) Esto puede suponer una dificultad de mayor calado de lo que ahora se puede considerar, ya que lo que aquí se presenta es una forma simplificada de desarrollar el procedimiento. Cuando nos enfrentemos a situaciones reales veremos cómo las abordamos. Adelantar ahora que una posible solución puede ser emplear procedimientos mixtos.... pero hay más opciones.
(2) Este documento consta originalmente en versión digitalizada sobre Word a modo de plantilla. Posteriormente reelaboré el anterior como plantilla LO-Writer, pero también desarrollé un docap basado en OOo Basic y en el uso de marcadores (modelo de automatización asimilable a la categoría carátula). [Este docap es accesible desde este enlace].
(3) Obsérvese que se presenta como bloque textual único y que se usa # como marcador de los segmentos textuales.
(4) Es perfectamente posible concretar este planteamiento también como resultado del trabajo en grupo, aunque cada uno de sus componentes deberá realizar su propia personalización.
(5) Trasladar a Writer el texto personalizado para obtener el documento final.
(6) Desde la perspectiva del profesional informáticamente competente que nos hemos planteado esto es siempre así; pero incluso en caso de que se de 4, o de que yo ceda mi trabajo a otro compañero, también es abordable como planteo ahora. Lógicamente cabe la posibilidad de desarrollarlo todo desde la perspectiva del docap tradicional y como resultado de la omisión de la diferenciación personalización-automatización, aunque tiene su coste en términos de complejidad del manejo del procedimiento mediante código.
(7) Recuerdo que con ellas me refiero a los segmentos textuales condicionados gramaticalmente, en este caso en función del género (masculino-femenino) del OE.
(8) Además del ahorro de programación que hemos observado, también está la simplificación del tratamiento de las variables-condicionadas que restan, ya que ahora sólo existe un elemento condicionante, la variable-input nombre del alumno. De no realizar la fase de personalización anterior, nos deberíamos plantear la existencia de dos condicionantes, con las consecuencias que esto tiene para el planteamiento del código de tratamiento de las variables-input y de las variables-condicionadas gramaticalmente.
(9) Se asume en este caso que coinciden los datos personalizables con los iniciales. Obsérvese que el marcador # se pega al final del segmento identificado, ocupando el espacio que existe entre esta posición y el inicio del segmento que sigue; esto es: sin espacio intermedio en ambos casos.
(10) Nombre del documento, nombre de la hoja receptora y ajuste de la celda a la que trasladaremos el texto. También podemos definir en ella un módulo para trabajar posteriormente desde el IDE.
(11) No es un script independiente del servicio, por lo que si optamos por implementarlo en Writer deberemos modificarlo. Yo prefiero hacerlo sobre Calc dado que ese documento deberá ser trabajado desde el IDE, con lo que esto implica; así nos ahorramos hacerlo desde dos de los documentos con los que trabajaremos. Esto conlleva desarrollar al completo el proceso indicado en (10).
(12) Obsérvese que es una combinación de macro y script. A parte de tratar la cuestión en una entrada específica, los comentarios que contiene hacen innecesario que dediquemos aquí tiempo a explicar su funcionamiento. Señalar, eso sí, que deberemos utilizarlo directamente desde el IDE o desde la funcionalidad Herramientas | Macros | Ejecutar macro 

martes, 22 de octubre de 2024

Procedimientos. Datos.

Funciones estadísticas Calc. Puntaciones normalizadas Z. 

Disponemos en Calc de una función que nos permite calcular las puntuaciones Z o puntuaciones normalizadas. Se trata de la función NORMALIZACION(). Dedicaremos esta entrada a explicar esta función y su significado en cuanto a proceso de normalización de las puntuaciones directas, entre otras razones, por el interés que tiene para el análisis de los resultados de las pruebas de evaluación.


El cálculo de las puntuaciones normalizadas (Z) asume que las puntuaciones directas (PD) de la muestra de datos (y más aun de la poblacional) presentan una distribución normal (curva en forma de campana, y más específicamente como campana de Gauss). Se basa en el conocimiento de la media (promedio) y de la desviación típica (Dt), estadísticos que se emplean para su cálculo...

... que se puede describir como cociente de la diferencia de la puntuación directa (PD) respecto a la media, dividido entre la desviación típica (Dt). El resultado puede interpretarse como el número de Dt en que se sitúa la PD. Calcular las p. Z es asignar los datos a una distribución de media 0 y Dt 1.

Este resultado se expresa en valores de signo - (cuando PD es inferior a la media) o de signo + (cuando la PD es superior a la media) que se encuentra acotado inferiormente por -3 y superiormente por +3 (1), siendo excepcionales (atípicos) los valores que se sitúan por debajo o por encima de estos límite. Una p. Z -2 indica que la PD se encuentra situada a 2 Dt por debajo de la media y una p. Z +1 indica que la PD se encuentra situada a 1 Dt por encima de la media.

Las puntuaciones Z permiten comparar las posiciones relativas de dos datos respecto al conjunto de las observaciones, eliminando los efectos de la ubicación y de la escala en que se presenta la PD de dichos datos; además permite identificar los posibles valores atípicos y, en términos de comparación de muestras, facilita las comparaciones entre conjuntos de datos con diferentes métricas.

El cálculo de las puntuaciones normalizadas (Z) se puede realizar en Calc haciendo uso de la función NORMALIZACION(), que requiere tres parámetros: el datos a normalizar (x), el valor de la media (promedio) y el valor de la desviación estándar (Dt).

Para cubrir el conjunto de datos de una muestra deberemos anclar las referencia a Promedio (PROMEDIO()) y a Dt (DESVEST()) y arrastrar el cursor hasta finalizar el recorrido por la columna o fila que contenga los datos de las PD.

En OOo Basic no contamos con una función Built-In para realizar el cálculo de este estadístico, pero aquí te muestro [una creada] por mí, siguiendo la lógica de la función NORMALIZACION() pero aplicada automáticamente a un conjunto de datos, lo que supone una ventaja sobre la función Calc.

NOTA

(1) Dentro de este intervalo (-3/+3) se encuentra el 99,7% de las observaciones en la población. Dentro del intervalo central (Md+/- 1 Dt) se encuentran situadas el 68,2% de las observaciones de la población.

sábado, 19 de octubre de 2024

Procedimientos. Datos.

Funciones estadísticas Calc. Medidas de tendencia central.

Dentro de las funciones Calc, ocupan un lugar importante para el trabajo de los SEO las funciones estadísticas. Vamos a ocuparnos en esta entrada de las funciones que nos permiten calcular las medidas de tendencia central.


Dentro de la llamada estadística descriptiva, las medidas de tendencia central ocupan un lugar destacado, ya que son las que nos permiten resumir en un único valor todo el conjunto de valores de la muestra. Esto implica que dicho valor representa el centro respecto al cual se encuentra el conjunto de datos.

Las medidas de tendencia central más utilizadas son la moda, la mediana y la media o promedio. Para su cálculo disponemos en Calc de varias funciones, de las que trataremos en esta entrada (1).

Empezando por la moda (el valor o los valores que más se repiten en una muestra), en Calc contamos con dos funciones: MODA.UNO() y MODA.VARIOS(). La primera encuentra en la muestra y devuelve el primer valor que más se repite; esto no garantiza que no existan otros valores con la misma (máxima) frecuencia muestral, por lo que es conveniente aplicar de forma complementaria la segunda función (MODA.VARIOS()), ya que nos permite observar si la muestra o conjunto de datos es, cuanto menos, bimodal (dos modas). MODA.VARIOS() encuentra y devuelve los dos valores con mayor frecuencia en la muestra o conjunto de datos. Esto no garantiza que no haya un tercer valor con también el máximo de frecuencia, pero es suficiente para confirmar que sólo existe una moda (devolverá el mismo valor dos veces) o que la muestra es, cuanto menos, bimodal.

La función que nos permite calcular el valor de la mediana es MEDIANA(), que devuelve el valor que ocupa la posición central en la muestra, por lo que divide ésta en dos partes iguales (50%). Es importante comprender que la función MEDIANA() de Calc da cómo resultado un dato o valor que se sitúa en esa posición, y suele ocurrir que este valor se repita dentro de la muestra o que no se encuentre realmente representado en ella. 

En el segundo caso es posible que MEDIANA() dé como resultado un valor con decimales (50,5, por ejemplo), que resulta de dividir entre dos los dos valores que dividen la muestra en partes iguales (50 y 51, por ejemplo), dado que el valor (número de observaciones de la muestra, para muestras no agrupadas) es par (2). 

En ambos caso (valor repetido y valor inexistente) debemos interpretar que lo que nos devuelve MEDIANA() no es el valor en sí, sino la posición: cuando el valor se repite lo que quiere decir es que el valor x-mediana ocupa la posición que divide la  muestra en dos partes iguales (50%) (3); cuando nos devuelve un valor con decimales, lo que quiere decir es que la posición que divide la muestra en dos partes iguales se sitúa en la posición intermedia de dos valores presentes en la muestra, por lo que utiliza ambos (a+b/2) para obtener la posición mediana.

Mientras que la moda parte del análisis de frecuencias y la mediana de los valores posicionales, la media aritmética o promedio resulta, como sabemos, del sumatorio de los valores de y (los datos muestrales observados) dividido entre el valor n (número de observaciones).

Aunque Calc cuenta con varias funciones (4), la que aquí nos interesa por similitud funcional con las anteriores medidas y por frecuencia de uso, es la que se denomina PROMEDIO(), que devuelve un valor numérico, frecuentemente con parte decimal, resultante de la aplicación de la fórmula anterior.

Debemos tener en cuenta que el valor devuelto por PROMEDIO() es sensible a distorsiones derivadas de valores extremos (muy bajos o muy altos), por lo que no siempre es una medida central que resuma adecuadamente los valores muestrales. Tampoco lo es cuando la variabilidad de los datos es muy elevada, pero de eso hablaremos en otra entrada (5).


NOTAS

(1) De las funciones Calc, no de las medidas propiamente dichas, ya que no es este el objetivo de este Blog. Para una revisión de los conceptos y cálculos estadísticos de estas medidas hay abundante información en la red, además de amplia bibliografía. Sólo a título de muestra, [ver aquí] para una exposición de las medidas de tendencia central y de dispersión.
(2) Si es impar nos devolverá un valor numérico entero (sin parte decimal).
(3) Muy probablemente ese valor que se repite también ocupará otras posiciones, inferiores a 50% y superiores, pero uno de sus representantes muestrales siempre se situará en esa posición central. Una forma de comprobarlo es ordenar la lista de datos y generar una columna precedente en la que escribiremos el orden sucesivo de posiciones, aplicando también la función MEDIANA() a esta columna. Buscaremos el valor resultante con el dato que corresponda en la columna de valores reales, que deberá coincidir con el calculado por MEDIANA() sobre dicha columna de datos.
(4) Concretamente MEDIA.ACOTADA()MEDIA.ARMO()MEDIA.GEOM()
(5) Al contrario de lo que sucede con las funciones Calc de medida del tiempo, con contamos en OOo Basic con funciones Built-In equivalentes a estas funciones, por lo que deberemos crearlas o trabajar directamente con las funciones Calc siguiendo el procedimiento que mostramos en [esta entrada].

martes, 13 de agosto de 2024

Procedimientos. Datos.

Calc. Funciones de fecha y hora.

Dentro de las funciones propias de Calc, las de fecha y hora tienen un interés especial para el trabajo del OE, ya que permiten registrar datos temporales y realizar cálculos en ellos, siendo éstos fundamentales para el registro de las actuaciones y para el trabajo en los procesos de evaluación.


Empezaremos por la función AHORA() que tomaremos como referencia para otras funciones. AHORA() devuelve la fecha y la hora actual del sistema expresada según el idioma de configuración del programa. En mi caso, los valores devueltos se expresan como dd/mm/aaaa hh:mm. Una característica de esta función es que el resultado que devuelve se actualiza automáticamente en el momento en que se emplea.

Sobre esta función o directamente sobre un valor que expresa la fecha o la hora es posible aplicar funciones que calculan cada uno de sus componentes: AÑO(), MES(), DIA(), HORA(), MINUTO() y SEGUNDO() (1).

Todas estas funciones Calc tiene su equivalente en funciones OOo Basic, siendo la única diferencia el que se expresan en inglés, así AHORA() se expresa en OOo Basic como Now(). El resto de las funciones de fecha y hora también pueden toma como valor de referencia la función Now: Second(Now) (2). Estas son las equivalencias entre las funciones Calc y las funciones integradas (Built-In) en OOo Basic (3):
  • AHORA() - Now()
  • AÑO() - Year()
  • MES() - Month()
  • DIA() - Day()
  • HORA()Hour()
  • MINUTO() - Minute()
  • SEGUNDO() - Second()

NOTAS

(1) En el caso de aplicar cualquiera de estas funciones sobre AHORA(), la expresión será (por ejemplo) como sigue: MES(AHORA()). Aunque AHORA() no contemple necesariamente a la expresión del valor de los segundos (depende de cómo se haya configurado la expresión del valor), éste está presente implícitamente, por lo es posible conocer este valor mediante la función SEGUNDO().
(2) AHORA() - Now() es una función sin argumentos, por lo que se puede expresar con o sin paréntesis (AHORA() = AHORA).
(3) Como se puede ver, se trata de una mera traducción de términos. Las funciones Calc se expresan en español por ser éste (en mi caso) el idioma elegido en la instalación de LibreOffice. Sobre las funciones Built-In OOo Basic puedes ver [esta entrada] y las que siguen en la sección Funciones.

lunes, 15 de julio de 2024

Procedimientos. Macros.

Vincular macros o script a un objeto (2)


Además de un comando o a una hoja, también podemos asignar una macro/script a un objeto figura o imagen. Aunque aquí nos basemos en Calc, esa posibilidad activar un script no se limita a este servicio, ya que es posible insertar una forma o una imagen en cualquiera de los servicios LibreOffice.




Después de implementar una forma (Insertar | Forma) y/o una imagen (Insertar | Imagen) en la hoja, hacemos clic derecho sobre ella para seleccionara. Automáticamente se despliega un menú de opciones, dentro de las cuales tenemos la opción Asignar macro.


Haciendo en ella accedemos a un submenú donde se diferencia una ventana superior donde se identifica la única opción de evento disponible (Botón del ratón presionado). En la ventana inferior se encuentran los subdirectorios que contienen las distintas ubicaciones de macros posibles (Macro de). Deberemos hacer clic en aquella que contenga la macro que deseamos asociar a la forma/imagen y seleccionarla en Macros existentes.


Una vez seleccionada la macro/script deberemos hacer clic en el comando Asignar (lateral derecho de la ventana) y después en Aceptar (marco inferior). Estas dos acciones son necesarias para que se realice correctamente la asignación de la macro/script al objeto forma/imagen.


El documento Calc que ejemplifica este proceso consta de dos hojas: en la primera he implementado una figura y en la segunda una imagen. Los script (podemos decir, de ida y vuelta) permiten acceder uno a Hoja2 y otro a Hoja1. De este modo, al hacer clic en el cuadrado azul (Hoja1) nos desplazamos a Hoja2 (previamente se muestra esta hoja y después se oculta Hoja1). El proceso que desarrolla el script asociado a la imagen situada en Hoja2 realiza el proceso contrario.

Documento. En [este libro Calc] puedes encontrar ejemplificado el proceso descrito en la entrada, incluyendo los dos script que se activan desde los objetos gráficos insertados en sus dos hojas.





Procedimientos. Macros.

Vincular macros o script a un objeto (1)


Una vez que hemos creado una macro o un script, necesitamos hacer que funciones. La primera alternativa consiste en utilizar las opciones de la interface del servicio (Herramientas | Macros | Ejecutar macro), solución simple y funcional pero poco atractiva a día de hoy. La segunda consiste en asignar la macro/script a un comando de formulario (botón), que es la forma que más se asemeja al modo standard de trabajar con las interfaces visuales. Pero aun hay otras opciones.


Una
forma un tanto especial y específico de las hojas de cálculo, consiste en asociar el script a la propia hoja. Para ello nos posicionamos en el navegador inferior de Calc y hacemos clic derecho sobre el nombre de una de las pestañas, la que representa la hoja a la que queremos asignar el script. 


Se visualiza la ventana emergente con el menú que vemos en la imagen superior y seleccionamos la opción Eventos de hoja. Haciendo clic en ella, accedemos a una ventana de selección de opciones de vinculación (eventos) (1)


Seleccionamos uno de estos eventos y  hacemos clic en Macros. A continuación podremos seleccionar la macro/script que nos interesa vincular a la página, seleccionarla y hacemos clic en Aceptar.


 
Nos devuelve a la ventana anterior (ahora con la macro seleccionada identificada en la columna Acción asignada) y volvemos a hacer clic en Aceptar.

De este modo la macro/script queda vinculada a la página en función del evento que hayamos escogido.

En el ejemplo que desarrollo como concreción del proceso anterior, he elegido el evento Activar documento y la macro Main. Esto implica que cuando Hoja1 sea la hoja activa se pondrán en marcha las instrucciones que contiene este script.

Sub Main

Dim oHoja As Object

oHoja = ThisComponent.getSheets.getByIndex(1)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(0)
oHoja.isVisible = False
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(2)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(1)
oHoja.isVisible = False
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(3)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(2)
oHoja.isVisible = False

End Sub

En resumen, se visibiliza (mostrar) una hoja, se espera 500 msg y se oculta la hoja precedente (2), con lo que la hoja visible pasa a ser también la hoja activa (3).

Documento. Este [libro Calc] contiene el código anterior asociado a Hoja1. Al abrir este documento, nos encontramos posicionados en Hoja4. Si nos desplazamos "manualmente" a Hoja1 se desarrollará el proceso esperado (4). 

NOTAS

(1) Si comparas los eventos posibles con los que se despliegan cuando trabajamos con el control de formulario Botón (Comando), verás que los eventos de hoja son mucho más limitados.
(2) Esto es así por trabajar con el índice de las hojas, lo que facilita la secuencia Mostrar-Ocultar.
(3) Este script contiene la instrucción Wait cuyo uso merece más atención de la que se le presta aquí. Será necesario analizarla específicamente en una entrada específica.
(4) Dado que se ocultan todas las hojas (menos Hoja4), para volver al estado inicial deberemos mostrar todas las hojas (Hoja | Mostar la hoja, seleccionamos todas las que se nos muestran y clic en Aceptar), pero mantendremos Hoja4 como hoja activa. Si guardamos el documento posicionándonos en Hoja1, de modo que al volver a activarlo estemos posicionados en ella, no se activará el script.

viernes, 12 de julio de 2024

Procedimientos. Datos.

Calc. Uso de funciones dentro de los script.

Sabemos que Calc cuenta con un número elevado de funciones que podemos utilizar en este servicio para trabajar con datos, numéricos o alfanuméricos. Podemos reemplazar estas funciones mediante código OOo Basic, pero también tenemos la posibilidad de incluirlas en nuestros script, aprovechando así toda su potencia y ahorrándonos trabajo (1). 


Encontré el código que explicaré en esta entrada buscando precisamente cómo aprovechar las funciones Calc  en el código OOo Basic y, por lo que parece, no fui el único que se planteó una pregunta parecida (2). Cierto que no me ayudó a resolver el problema que tenía planteado, pero me ha parecido una solución muy interesante y de mucha utilidad, así que la comparto (3).

La base fundamental de este procedimiento consiste en hacer referencia en los script a las funciones Calc, pero no es la denominación con que se nos presentan en el servicio en su Asistente de funciones, sino en inglés; detalle éste importante para que funciones el código (4).

Se plantean dos opciones básicas: la que incorpora la función Calc en el script y la que lo hace mediante una función OOo Basic. Esta diferencia conlleva mucho más, como podremos ver más adelante, pero como primer criterio de diferenciación es relevante para que nos vayamos poniendo en situación.

Estas dos formas de trabajo se ejemplifican en los siguientes script. En el primero llamamos a una función para que "escriba" su resultado en una celda y después accedemos al contenido de esa celda para aprovechar el resultado de la función.

Sub PruebaFuncionCalc1a

Dim oHoja As Object
Dim dResulta As Double

oHoja = ThisComponent.CurrentController.ActiveSheet
oHoja.getCellRangeByName("B12").Formula = "=SUM(A1:A12)"

dResulta = oHoja.getCellRangeByName("B12").Value

MsgBox dResulta

End Sub

Tras declarar dos variables (oHoja dResulta) y acceder al objeto Hoja (oHoja = ThisComponent.CurrentController.ActiveSheet), implementamos la fórmula (=SUM(A1:A12)) en la celda B12. Para ello añadimos al identificador de la celda el identificador Formula (oHoja.getCellRangeByName("B12").Formula = "=SUM(A1:A12)")

Una vez que la fórmula actúa y entrega su resultado en la celda establecida, accedemos a dicho resultado asignándolo a la variable dResulta (dResulta = oHoja.getCellRangeByName("B12").Value) (5). En este caso, lo que hacemos con el valor obtenido es mostrarlo mediante MsgBox (MsgBox dResulta), pero podríamos utilizarlo de cualquier otra forma, dependiendo del algoritmo de nuestro script.

El segundo modo de trabajo implica el uso de una función (FuncionCalc()) que es llamada desde un script (PruebaFuncionCalc2). Empecemos explicando el script:

Sub PruebaFuncionCalc2

Dim oHoja As Object
Dim dSuma As Double
oHoja = ThisComponent.getSheets().getByName("Hoja1")
dSuma = FuncionCalc( "SUM", Array(oHoja.getCellRangeByName("A1:A12")) )
MsgBox dSuma
 
End Sub

Tras declarar las dos variables necesarias (oHoja y dSuma) y acceder al objeto Hoja (oHoja = ThisComponent.getSheets().getByName("Hoja1")) recurrimos a la función (FuncionCalc()), asignando el dato que devuelve ésta a la variable dSuma. Dado que se trata de una función, cuenta (en este caso) con dos parámetros, que son los que pasamos por valor en la formulación de la llamada a la función (FuncionCalc( "SUM", Array(oHoja.getCellRangeByName("A1:A12")) )):

  • El primero es el nombre de la función Calc (en inglés) ("SUM")
  • Y el segundo, mucho más complejo, es la matriz de datos formada por el contenido del conjunto de celdas A1:A12, esto es: los datos que requiere la función Calc (Array(oHoja.getCellRangeByName("A1:A12"))) (6)

Después utilizamos el resultado devuelto por la función para mostrarlo en pantalla mediante MsgBox (MsgBox dSuma) (7)

 Veamos a continuación el código de la función FuncionCalc():

Function FuncionCalc( Nombre As String, Datos() )

Dim oSFA As Object

oSFA = createUnoService( "com.sun.star.sheet.FunctionAccess" )

FuncionCalc = oSFA.callFunction( Nombre, Datos() )

End Function

Observa que la función tiene dos parámetros, uno de tipo texto y otro una matriz (Nombre As String, Datos()): son los mismos a los que damos valor desde el script (( "SUM", Array(oHoja.getCellRangeByName("A1:A12")))).

Además, la función cuenta con una variable de tipo objeto (oSFA) a la que se asigna el objeto UnoService de acceso a las funciones de Calc FunctionAccess. (createUnoService( "com.sun.star.sheet.FunctionAccess")) Esta asignación se basa en la estructura típica de acceso a las funciones nucleares de la suite LibreOffice, que, como sabes, está escrita en parte en Java, esto es: en un lenguaje orientado a objetos (POO)

Siguiendo la sintaxis de las funciones, asignamos al identificador de la actual el resultado de aplicar la función nombrada a la matriz de datos; como recordarás, ambos han sido pasados por valor desde el scriot (FuncionCalc = oSFA.callFunction(Nombre, Datos())). De este modo la función devuelve al script, el resultado de dicha función. (8)

Dado que sólo he sabido manejar adecuadamente el primer modo de trabajo (ver nota 8), me limitaré a exponer cómo transformarlo para trabajar con otras funciones. Llamo a estos script PruebaFuncionCalc1bPruebaFuncionCalc1c respectivamente. En el primero empleo una función Calc que actúa sobre un dato unitario (la función RAIZ()) y en el segundo trabajo con una función que trabaja con datos alfanuméricos, posicionados en una colección del celdas (no una matriz) (la función CONCATENAR()) (9).

Empecemos por el primer script y la función RAIZ()

Sub PruebaFuncionCalc1b

Dim oHoja As Object
Dim sResulta As Double

oHoja = ThisComponent.CurrentController.ActiveSheet
oHoja.getCellRangeByName("B15").Formula = "=SQRT(A15)"

dResulta = oHoja.getCellRangeByName("B15").Value

MsgBox dResulta

End Sub

 Como ves hay poco que añadir a lo visto en la explicación del script de base (PruebaFuncionCalc1a): únicamente sustituimos la expresión de la función anterior (SUM()) por la actual (SQRT()) (en inglés), con lo que no tienes mayor dificultad que recurrir al Asistente para funciones de Calc y traducir el nombre de la función al inglés. Los cambios de parámetros van incluidos en el procedimiento: para SUM() era necesaria una matriz de datos ("=SUM(A1:A12)") y para SQRT() únicamente una referencia a celda ("=SQRT(A15)")

El script PruebaFuncionCalc1c muestra la validez universal del procedimiento de sustitución que te acabo de explicar:

Sub PruebaFuncionCalc1c

Dim oHoja As Object
Dim sResulta As String

oHoja = ThisComponent.CurrentController.ActiveSheet
oHoja.getCellRangeByName("B20").Formula = "=CONCATENATE(A20;A21;A22)"

dResulta = oHoja.getCellRangeByName("B20").String

MsgBox dResulta

End Sub

De nuevo, es suficiente con escribir la sintaxis de la función Calc en la posición adecuada dentro del script para obtener el resultado deseado. 

Pero aun hay más: podemos combinar varias funciones dentro de la misma expresión, del mismo modo que es posible construir una combinación de funciones Calc. El script PruebaFuncionCalc1d es una prueba de ello.

Sub PruebaFuncionCalc1d

Dim oHoja As Object
Dim dResulta As Double

oHoja = ThisComponent.CurrentController.ActiveSheet

oHoja.getCellRangeByName("B13").Formula = "=SQRT(SUM(A1:A12))"

dResulta = oHoja.getCellRangeByName("B13").Value

MsgBox dResulta

End Sub

Aquí combinamos las funciones SQRT() y SUM() para obtener una función combinada en la que sobre la suma resultante de la matriz de datos A1:A12 solicitamos el cálculo de su raíz cuadrada ("=SQRT(SUM(A1:A12))"). El resultado se escribe en la celda B13. Como puedes comprobar, la sintaxis de la instrucción únicamente varía en la forma en que se llaman a ambas funciones, que es la misma que escribimos sobre la Línea de entrada de fórmulas de Calc.

Por tanto resulta evidente la ventaja de este modo de implementar funciones Calc en los script OOo Basic: es suficiente con escribir la fórmula según su sintaxis Calc, sustituyendo el nombre de la función por su equivalente en inglés. Es además importante establecer correctamente la referencia a los datos con los que trabajarán dichas funciones.

Documentos.

Pongo a tu disposición dos documento. El primero [FormulCalc.ods] es el documento Calc en el que puedes encontrar los ejemplos explicados en la entrada. El segundo [WIKI de OpenOffice] el enlace a la web donde encontrarás el listado de funciones Calc en inglés y en español.

NOTAS

(1) En algunas ocasiones esto puede ser así, pero en otras es preferible generar procedimiento propios, basados en OOo Basic, ya que son mucho más potentes y flexibles. No obstante, no es de despreciar lo que el uso de las funciones Calc nos puede ayudar a resolver problemas (especialmente de cálculos complejos) para los que no dispongamos de solución en un momento concreto. Toda ayuda es bienvenida.

(2) El material procede en primera instancia de la Web OpenOffice (en español), aunque los autores reconocen el mérito a Mauricio Baeza, del que son deudores. Y yo de ambos.

(3) A lo que aportan los autores anteriores añado de mi parte mi explicación del funcionamiento del código. Esta explicación no está disponible al menos en la primera de las referencias.

(4) Una contribución que añado para facilitarte el trabajo: el listado de funciones Calc en inglés y en español, cortesía de la WIKI de OpenOffice.

(5) Utilizamos .Value por tratarse de un resultado numérico. En caso de emplear una fórmula que devuelva un contenido alfanumérico emplearíamos .String

(6) Si tienes curiosidad, puedes comprobarlo escribiendo esa misma función en la Línea de entrada (de fórmulas) de Calc.

(7) Observa que, a diferencia del modo anterior, ahora no escribimos el resultado de la función en ninguna celda; no como paso previo para acceder a su resultado. Podríamos hacerlo, pero sería ya una decisión a posteriori, equivalente a mostrarlo por pantalla, que es la solución por la que optamos en este caso. 

(8) En principio podríamos sustituir la función SUM() por cualquiera otra que utilice como datos una matriz similar a la que emplea ésta, pero no resulta tan sencillo trabajar con funciones que actúan sobre otro tipo de estructuras. Al menos yo no he sabido hacerlo. Supongo que habrá forma de hacerlo y cuando lo averigüe lo expondré. 

(9) Te sugiero que, antes de seguir, refresques tu memoria haciendo uso de ambas funciones desde Calc. Así te resultarán familiares y comprenderás mejor los script en los que se incluyen.