Pascal’s Triangle – Alteryx Python SDK

La versión en español está aquí

After a couple of posts (I & II) getting my feet wet with the Python SDK module for Alteryx I finally get to build a tool that actually uses some code:

The Pascal's Triangle generator

Following the original recipe, I duplicated a sample folder, renamed the files, removed most of the superfluous code, added the pieces I needed and, finally, connected my code with the AyxPlugin.

All so that I can generate my own Pascal’s Triangles with a single tool.

The main difference with the previous tool is that the code references two python libraries that are not part of the miniconda distribution that comes with Alteryx:

On hindsight, this is an overkill and I could/should have just written a self-contained implementation. BUT I did want to play with importing packages and virtual environments so…
The installer is available here.  Install it by double clicking on it, it will appear in the “Laboratory” tools. Unzip the .yxi to explore the files.

I first wrote a working example using Jupyter:

import scipy.special
import pandas as pd
    def Pascal(value):
        '''Returns the Pascal Triangle up to the Row defined in the value'''

        df = pd.DataFrame(0, index= range(value+1), columns = range((value+1)*2))                                 
        #instantiate the df, will need double
        # the number of columns as they don't stack

        for index in df.index:
            diff = len(df) - (index+1) #calculate the step to add to the stair
            for column in df.columns:
                try:
                    df.iloc[index,(column*2 + diff)] = int(scipy.special.binom(index, column))
                except: pass
        df.replace(to_replace=0,value='',inplace=True)# remove zeros
        return df
Then I migrated that code into the PascalTriangleEngine.py
  1. Import libraries:
  2. import AlteryxPythonSDK as Sdk
    import xml.etree.ElementTree as Et
    import scipy.special
    import pandas as pd
    
  3. Bring Pascal Function:
  4.     def Pascal(self, value):
            '''Returns the Pascal Triangle up to the Row defined in the value'''
            # Instantiate the df will need double the number of 
            # columns as they don't stack
            
            df = pd.DataFrame(0, index= range(value+1), columns = range((value+1)*2-1)) 
            for index in df.index:
                diff = len(df) - (index+1) #calculate the step to add to the stair
                for column in df.columns:
                    try:
                        df.iloc[index,(column*2 + diff)] = int(scipy.special.binom(index, column))
                    except: pass
            df.replace(to_replace=0,value='',inplace=True)# remove zeros
            return df
    
    
  5. Update pi_push_all_records:
  6.     def pi_push_all_records(self, n_record_limit: int) -> bool:
    
            self.dataframe = self.Pascal(self.n_rows)
            record_info_out = self.build_record_info_out()  # Building out the outgoing record layout.
            self.output_anchor.init(record_info_out)  # Lets the downstream tools know of the outgoing record metadata.
            record_creator = record_info_out.construct_record_creator()  # Creating a new record_creator for the new data.
            
            for row in self.dataframe.index:
                t=0
                for column in self.dataframe.columns:
                    record_info_out[t].set_from_string(record_creator,str(self.dataframe.loc[row,column]))
                    t+=1
            
                out_record = record_creator.finalize_record()
                self.output_anchor.push_record(out_record, False)  # False: completed connections will automatically close.
                record_creator.reset()  # Resets the variable length data to 0 bytes (default) to prevent unexpected results.
    
            self.alteryx_engine.output_message(self.n_tool_id, Sdk.EngineMessageType.info, self.xmsg(
            str(self.n_rows)+' records were processed.'))
            self.output_anchor.close()  # Close outgoing connections.
            return True
    
Finally, I made sure to follow the steps detailed in the official documentation to obtain the installer and proper dependencies:
  1. Create a virtual environment.
  2. C:\Program Files\Alteryx\bin\Miniconda3>python -m venv
    C:\TempFolderWhereIamDevelopingTheTool
  3. Install packages in the virtual environment.
  4. cd C:\TempFolderWhereIamDevelopingTheTool\Scripts
    pip install pandas
    pip install scipy
  5. Create the requirements.txt file using pip freeze.
  6. cd C:\TempFolderWhereIamDevelopingTheTool\Scripts
    pip
    freeze > ..\requirements.txt
    
  7. Create the installer .yxi as described in previous posts.
Voilà. Tool ready (here).

Please, leave any comments below or reach me at 

Un poco más de Python SDK

Después de un par de ensayos (I & II) familiarizándome con el
módulo de Python SDK de Alteryx, por fin me pongo manos a la obra para desarrollar una herramienta que necesite “algo de código”.

El Generador de Triángulos de Pascal

Siguiendo el paso a paso original, dupliqué una de las carpetas con ejemplos de muestra de Github, renombré los archivos, eliminé la mayor parte del código que era innecesaria para mis intenciones, añadí el pequeño fragmento que he desarrollado para obtener los triángulos y, la parte sin duda más complicada, conecté el código con el AyxPlugin de Alteryx.

Todo con el único objetivo de tener mir propio generador de Triángulos de Pascal en una única herramienta de Alteryx.

La principal diferencia con los ejemplos que he venido haciendo radica en el requerimiento de dos bibliotecas adicionales que no son parte de la distribución de miniconda que viene con Alteryx:

Viéndolo con un poco más de calma y perspectiva, en realidad esto ha sido como matar moscas a cañonazos y lo que podría (o debería) haber hecho es un desarrollo independiente que no precisase instalar ~200MB adicionales :-S Peeero, al fin y al cabo, lo que quería era practicar, precisamente, importar bibliotecas  y trabajar en entornos virtuales  así que, sin más dilación…

El instalador se encuentra disponible aquí.  Para instalarlo, basta con hacer clic doble sobre él y se instalará por defecto en la sección de  “Laboratory” . El .yxi se puede descomprimir (como archivo zip) para explorar los distintos ficheros.

Empecé este proceso escribiendo una versión funcional en Jupyter:

import scipy.special
import pandas as pd
    def Pascal(value):
        '''Returns the Pascal Triangle up to the Row defined in the value'''

        df = pd.DataFrame(0, index= range(value+1), columns = range((value+1)*2))                                 
        #instantiate the df, will need double
        # the number of columns as they don't stack

        for index in df.index:
            diff = len(df) - (index+1) #calculate the step to add to the stair
            for column in df.columns:
                try:
                    df.iloc[index,(column*2 + diff)] = int(scipy.special.binom(index, column))
                except: pass
        df.replace(to_replace=0,value='',inplace=True)# remove zeros
        return df
El siguiente paso fue migrar ese código al PascalTriangleEngine.py
  1. Importar los módulos necesarios:
  2. import AlteryxPythonSDK as Sdk
    import xml.etree.ElementTree as Et
    import scipy.special
    import pandas as pd
    
  3. Incorporar la función “Pascal”:
  4. def Pascal(self, value):
    '''Returns the Pascal Triangle up to the Row defined in the value'''
    # Instantiate the df will need double the number of
    # columns as they don't stack
    
    df = pd.DataFrame(0, index= range(value+1), columns = range((value+1)*2-1))
    for index in df.index:
    diff = len(df) - (index+1) #calculate the step to add to the stair
    for column in df.columns:
    try:
    df.iloc[index,(column*2 + diff)] = int(scipy.special.binom(index, column))
    except: pass
    df.replace(to_replace=0,value='',inplace=True)# remove zeros
    return df
    
    
  5. Actualizar pi_push_all_records:
  6. def pi_push_all_records(self, n_record_limit: int) -> bool:
    
    self.dataframe = self.Pascal(self.n_rows)
    record_info_out = self.build_record_info_out() # Building out the outgoing record layout.
    self.output_anchor.init(record_info_out) # Lets the downstream tools know of the outgoing record metadata.
    record_creator = record_info_out.construct_record_creator() # Creating a new record_creator for the new data.
    
    for row in self.dataframe.index:
    t=0
    for column in self.dataframe.columns:
    record_info_out[t].set_from_string(record_creator,str(self.dataframe.loc[row,column]))
    t+=1
    
    out_record = record_creator.finalize_record()
    self.output_anchor.push_record(out_record, False) # False: completed connections will automatically close.
    record_creator.reset() # Resets the variable length data to 0 bytes (default) to prevent unexpected results.
    
    self.alteryx_engine.output_message(self.n_tool_id, Sdk.EngineMessageType.info, self.xmsg(
    str(self.n_rows)+' records were processed.'))
    self.output_anchor.close() # Close outgoing connections.
    return True
    
Por último, siguiendo al detalle las instrucciones en la  documentación oficial (esta vez sí ¡instrucciones!) para obtener el instalador y las dependencias necesarias:
  1. Crear un entorno virtual en la carpeta de desarrollo.
  2. C:\Program Files\Alteryx\bin\Miniconda3>python -m venv
    C:\TempFolderWhereIamDevelopingTheTool
  3. Instalar los módulos necesarios en el entorno virtual.
  4. cd C:\TempFolderWhereIamDevelopingTheTool\Scripts
    pip install pandas
    pip install scipy
  5. Crear el archivo de requerimientos requirements.txt usando pip freeze.
  6. cd C:\TempFolderWhereIamDevelopingTheTool\Scripts
    pip
    freeze > ..\requirements.txt
    
  7. Crear el instalador .yxi siguiendo el mismo proceso que en ocasiones anteriores (pero, eso sí, incluyendo el archivo de requirements creado).

Y con esto ya está listo el nuevo generador de triángulos de Pascal para Alteryx…

Muchas gracias por llegar hasta aquí. Deja un comentario más abajo o contacta aquí –>