6 agosto, 2026

GENERAR ESPIRAL DE BURBUJAS Y PALABRAS CON AZURE FUNCTIONS EN POWER APPS

Hola a todos,

Este post va a ser similar al post que había escrito hace un par de semanas sobre cómo construir una nube de palabras utilizando Python, Azure, VSC, Power Automate y Power Apps.

Os remito al post de referencia: https://excelsignum.com/2025/11/02/generar-nube-de-palabras-con-azure-functions-en-power-apps/

En este caso, lo que tenemos es una serie de palabras que hemos pedido a los empleados de una empresa, que indiquen 10 palabras que definan de alguna forma lo que sienten cuando se encuentran en nuestra empresa.

Estos datos que muestro aquí en Excel están en una lista de SharePoint, y lo que buscamos es generar algo diferente a una nube de palabras, por ejemplo, una espiral de burbujas, que muestre en el centro las que se repiten con mayor frecuencia y con burbujas más grandes y el resto que vaya decreciendo.

Para ello vamos a utilizar Azure Functions y después de generar nuestra función en VSC con Python: miFuncionDatosBurbuja

Os dejo aquí la función que tenéis que pegar en vuestro archivo init.py

import logging
import azure.functions as func
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import io
import base64

# -------------------------------
# STOPWORDS — AÑADE LAS QUE QUIERAS
# -------------------------------
STOPWORDS_ES = set([
    "un", "una", "unas", "unos", "uno", "sobre", "todo", "también", "tras",
    "otro", "algún", "alguno", "alguna", "algunos", "algunas", "ser", "es",
    "soy", "eres", "somos", "sois", "estoy", "esta", "estamos", "estais",
    "estan", "como", "en", "para", "porque", "estado", "estaba", "ante",
    "antes", "siendo", "ambos", "pero", "por", "poder", "puede", "podria",
    "pueden", "puedo", "mientras", "con", "muy", "más", "ya", "del", "los",
    "las", "lo", "de", "la", "el", "y", "o", "u", "que", "qué", "a", "al"
])

# --------------------------------
# FUNCIÓN PRINCIPAL DE AZURE
# --------------------------------
def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info("Generando gráfico de burbujas en espiral")

    try:
        data = req.get_json()
        texto = data.get("texto", "")

        # --------------------------------
        # LIMPIEZA DE TEXTO
        # --------------------------------
        palabras = []
        for palabra in texto.replace(",", " ").split():
            palabra = palabra.strip().lower()
            if palabra and palabra not in STOPWORDS_ES:
                palabras.append(palabra)

        # Conteo
        from collections import Counter
        conteo = Counter(palabras)

        labels = list(conteo.keys())
        counts = list(conteo.values())
        N = len(labels)

        # --------------------------------
        # ESPIRAL COMPACTA TIPO FIBONACCI
        # --------------------------------
        a = 0.25     # separación compacta
        b = 0.35     # crecimiento suave

        theta = np.linspace(0, 4 * np.pi, N)
        r = a + b * theta

        x = r * np.cos(theta)
        y = r * np.sin(theta)

        sizes = [600 + c * 650 for c in counts]

        # --------------------------------
        # GRÁFICO
        # --------------------------------
        fig, ax = plt.subplots(figsize=(14, 10))
        colors = plt.cm.Pastel1(np.linspace(0, 1, N))

        ax.scatter(x, y, s=sizes, c=colors, alpha=0.45)

        # -------------------------------
        # TEXTO CENTRADO SOBRE BURBUJAS
        # -------------------------------
        for i, palabra in enumerate(labels):
            ax.text(
                x[i], y[i], palabra,
                fontsize=14,
                ha="center", va="center",
                fontweight="bold"
            )

        # --------------------------------
        # QUITAR EJES Y CENTRAR VISUAL
        # --------------------------------
        ax.axis("off")
        ax.set_xlim(min(x)-2, max(x)+2)
        ax.set_ylim(min(y)-2, max(y)+2)

        # --------------------------------
        # EXPORTAR A BASE64
        # --------------------------------
        buf = io.BytesIO()
        plt.savefig(buf, format="png", bbox_inches="tight", dpi=150)
        buf.seek(0)

        img_base64 = base64.b64encode(buf.read()).decode("utf-8")

        return func.HttpResponse(
            body=f'{{"imagen": "{img_base64}"}}',
            mimetype="application/json"
        )

    except Exception as e:
        logging.error(f"Error: {str(e)}")
        return func.HttpResponse(
            body=f"Error procesando datos: {str(e)}",
            status_code=500
        )

Luego la desplegáis para poder obtener la URI y generar nuestro Automate.

En seleccionar lo obtendréis con el contenido dinámico, pero en Redactar debéis utilizar una expresión:

join(split(join(body('Seleccionar'), ','), ','), ' ')


Y seguimos:

El Cuerpo del HTTP que se pega directamente (no expresión):

{
"texto": "@{outputs('Redactar')}"
}


Y la respuesta como expresión

body('HTTP')?['imagen']


Y con esto, si pulsamos veremos esto en el control de imagen de nuestra App:

Comparte este post

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies