Widget interactivos

Daniel Domene ( CAChemE) - CC By 4.0

Un Widget interactivo es una herramienta que proporcionan muchos softwares de programación y que tiene como finalidad facilitar la observación de resultados. Uno de los más destacados y sencillos de implementar son los de tipo slider, como por ejemplo:

Interesante, ¿no?

Pues este ejemplo está hecho con código que aparece al final de este Notebook ;)

¿Por qué widgets?

Imaginemos que necesitamos que un cierto proceso viene definido por una función cualquiera, y que esta función depende de uno o más parámetros. En muchos casos estaremos interesados en ver qué ocurre con la función si modificamos esos parámetros, algo que en muchas ocasiones no es trivial.

Lo más común es representar la función e ir variando en nuestro código los valores de los parámetros para observar que ocurre, pero esta puede llegar a ser una tarea muy tediosa y aburrida, y generalmente se tienen que repetir las representaciones para llegar a establecer conclusiones. En este sentido, todo sería más fácil si introdujeramos widget que permitiria, tan solo moviendo una barrita, variar el valor de los parámetros y observar las variaciones de manera simultánea.

Si opinas lo mismo estás en el lugar adecuado, pues vamos a enseñar cómo se hace y aplicarlo a algún ejemplo como el de arriba.

Comenzamos...

En primer lugar tenemos que cargar las bibliotecas que vamos a necesitar:


In [1]:
%matplotlib inline 

import numpy as np 
import matplotlib.pyplot as plt 
from IPython.html.widgets import interact

¿Qué acabamos de hacer aquí arriba? Primero, hemos configurado las gráficas para que aparezcan dentro de este Notebook. Con los dos comandos siguientes hemos importado la bibliotecas NumPy y Matplotlib. Finalmente importamos también la biblioteca que nos permitirá utilizar los widgets interactivos.

Vamos a ver en qué consiste el widget que vamos a implementar con el comando interact. Primero, creamos una función muy sencilla que imprime la variable de entrada por pantalla:


In [2]:
# En Python los comentarios se escriben con una almohadilla

def funcion_prueba(x):
    print(x)

Ahora sólo tenemos hacer uso de interact para que nos cree un slider y así poder cambiar el valor de x con el ratón con el intervalo que especifiquemos.


In [3]:
interact(funcion_prueba, x=(1,10,1))


5
Out[3]:
<function __main__.funcion_prueba>

Nota: Para poder ver los sliders debes de ejecutar este notebook en tu ordenador o en la nube. Si es la primera vez que utilizas Python, dale un vistazo a nuestro curso online grautito.

Con este ejemplo sencillo queda más claro cómo se ha de implementar el comando interact. En primer lugar se ha de definir una función, que podrá tener diferentes parámetros, en este caso 'x', y se establece lo que la función tiene que hacer, en este caso solo mostrar el valor de la variable. Cuando llamamos al comando interact le indicamos que función queremos que haga referencia y le damos el rango de valores que pueden adoptar los parámetros, en este caso, x varía de 1 a 10 de uno en uno dependiendo dónde coloquemos la barrita.

Ejemplos interactivos

Generalmente, cuando se está realizando algún tipo de trabajo científico lo que más interesa es observar los datos, y la mejor manera es en gráficas. Si implementamos este tipo de widgets a nuestras representaciones, la dotaremos de una vistosidad y versatilidad como nunca. Vamos con unos ejemplos.

Isoterma de adsorción ( Wikipedia)

Una isoterma de adsorción (también llamada isoterma de sorción) describe el equilibrio de la adsorción de un material en una superficie (de modo más general sobre una superficie límite) a temperatura constante. Representa la cantidad de material unido a la superficie [...] como una función del material presente en la fase gas o en la disolución. Las isotermas de adsorción se usan con frecuencia como modelos experimentales,1 que no hacen afirmaciones sobre los mecanismos subyacentes y las variables medidas. Se obtienen a partir de datos de medida por medio de análisis de regresión.

Isoterma de Langmuir

Esta Isoterma tiene como parámetros:

  • $\theta_a$: Como la fracción de huecos ocupada por A.
  • K: Como el coeficiente de reacción
  • Pa: Como la presión parcial del componete A.

Presenta la siguiente forma:

$$ \theta_a = \frac{Kp_a}{(1+Kp_a)} $$

Vamos a implementar la ecuación anterior dentro de una función que llamaremos Isoterma_1, y tan solo variaremos el el coeficiente de reacción para estudiar su influencia en la adsorción.


In [11]:
def Isoterma_1(K):

    #Hacemos un vector para la presión parcial de A. Este rango corresponde con el eje de adcisas. 
    Pa = np.linspace(0,1,1000)
    #Definimos la ecuación de la Isoterma.
    Theta_a = (K*Pa) / (1 + K*Pa)           
    #Escribimos los comandos necesarios para represetar los resultados. 
    #Con este primer comando delimitamos el tamaño de la figura. 
    fig = plt.figure(figsize=(10, 8))
    #Representa el vector de theta frente al de presiones parciales. 
    plt.plot(Pa,Theta_a) 
    #Establece los límites de la figura. 
    plt.ylim([0,1])
    plt.xlim([0,0.1])
    #Coloca el título de los ejes y a la figura. 
    plt.ylabel('theta')
    plt.xlabel(u'Presión parcial de A')
    plt.title(u'REPRESENTACIÓN DE LA ISOTERMA DE LANGMUIR')
    
    # Cambiamos el estilo por defecto (opcional)
    plt.style.use('ggplot')

In [12]:
interact(Isoterma_1, K = (0,150,0.5))


Out[12]:
<function __main__.Isoterma_1>

Pero, si es una isoterma, ¿dónde aparece la temperatura? El coeficiente de reacción depende de otros factores que no considera directamente la expresión implementada. Este coeficiente se rige por la ecuación de Arrenious: $$\ K = k_0e^{\frac{-E_a}{RT}} $$

¡Implementémoslo!


In [6]:
def Isoterma_1(T,Ea):

    #Hacemos un vector para la presión parcial de A. Este rango corresponde con el eje de adcisas. 
    Pa = np.linspace(0,1,1000)
    #Coeficiente R
    R = 8.314 
    #Coeficiente preexponencial
    ko = 10**(-8) 
    #Definimos K
    K = ko*np.exp(-(Ea*1000)/(R*T))
    #Definimos la ecuación de la Isoterma.
    Theta_a = (K*Pa) / (1 + K*Pa)           
    #Escribimos los comandos necesarios para represetar los resultados. 
    #Con este primer comando delimitamos el tamaño de la figura. 
    fig = plt.figure(figsize=(10, 8))
    #Representa el vector de theta frente al de presiones parciales. 
    plt.plot(Pa,Theta_a) 
    #Establece los límites de la figura. 
    plt.ylim([0,1.5])
    plt.xlim([0,0.1])
    
    #Coloca el título de los ejes y a la figura. 
    plt.ylabel('theta')
    plt.xlabel(u'Presión parcial de A')
    plt.title(u'REPRESENTACIÓN DE LA ISOTERMA DE LANGMUIR')
    
    # Cambiamos el estilo por defecto (opcional)
    plt.style.use('ggplot')
    
interact(Isoterma_1, T = (0,500,0.5), Ea = (-100,0,0.5) )


Out[6]:
<function __main__.Isoterma_1>

Isoterma para adsorción de dos componentes

Puede darse el caso que necesitemos variar más de dos parámetros, en ese caso simplemente tenemos que ir añadiendolos al código. Vamos a ver otro tipo de isoterma, cuando la adsorción se da para dos componentes.

$$ \theta_a = \frac{K_ap_a}{(1 + K_ap_a + K_bp_b)} $$


In [15]:
def Isoterma_2(T,Ea_a,Ea_b):

    #Coeficiente R (gases ideales) 
    R = 8.314
    #Coeficiente prexponencial
    ko = 10**(-8) 
    #Definimos el coeficiente para el componente A
    Ka = ko*np.exp(-(Ea_a*1000)/(R*T))
    #Definimos el coeficiente para el componente B 
    Kb = ko*np.exp(-(Ea_b*1000)/(R*T))
    #Vectores de presiones parciales y presión total
    Pa = np.linspace(0,.25,1000)
    Pb = np.linspace(0,.25,1000)
    P = Pa + Pb
    
    #Función para representar la adsorción de A 
    Ocupacion_a = (Ka*Pa) / (1 + Ka*Pa + Kb*Pb )
    #Función para representar la adsorción de B
    Ocupacion_b = (Kb*Pb) / (1 + Ka*Pa + Kb*Pb )
    
    
    plt.figure(figsize=(10, 6))
    
    plt.plot(P,Ocupacion_a, label='A component')
    plt.plot(P,Ocupacion_b, label='B component')
    
    plt.ylim([0,1])
    plt.xlim([0,0.1])
    
    plt.ylabel(r'$\theta$ / fractional-occupancy')
    plt.xlabel(u'$ p_A $ / Partial pressure ')
    plt.title(u'Langmuir adsorption model for two components')
    plt.legend()
    
    # Cambiamos el estilo por defecto (opcional)
    plt.style.use('ggplot')

In [16]:
interact(Isoterma_2, T = (0.5,500,0.5), Ea_a = (-100,0,0.5), Ea_b = (-100,0,0.5) )


Out[16]:
<function __main__.Isoterma_2>

Adsorción disociativa

Con este ejemplo se ve cómo de útil puede ser este tipo de widgets, ya que permite comparar funciones y ver de qué manera afectan los factores a las mismas.

$$ \theta_a = \frac{(Kp_a)^{1/2}}{(1+(Kp_a)^{1/2})} $$

In [9]:
def Isoterma_3(K_1 , K_2 , K_3):

    #Coeficiente R (gases ideales) en kJ/molK
    R = 8.31*(10**(-3))

    #Coeficiente de equilibrio de adsorción de A
    #K_a = k_0*np.exp(E_a/(R*T))
    #K_1 = 100
    #K_2 = 10
    #K_3 = 1
    
    #Hacemos un vector para la presión de A 
    P = np.linspace(0,1,1000)

    Ocupacion_1 = ((K_1*P)**(0.5)) / (1 + ((K_1*P)**(0.5)))
    Ocupacion_2 = ((K_2*P)**(0.5)) / (1 + ((K_2*P)**(0.5)))
    Ocupacion_3 = (K_3*P) / (1 + K_3*P)
    
    fig = plt.figure(figsize=(10, 6))
    plt.plot(P,Ocupacion_1)
    plt.plot(P,Ocupacion_2)
    plt.plot(P,Ocupacion_3)
    plt.ylim([0,1])
    plt.xlim([0,0.1])
    
    plt.ylabel(r'$\theta$ / fractional-occupancy')
    plt.xlabel(u'$ p_A $ / Partial pressure $')
    
    # Cambiamos el estilo por defecto (opcional)
    plt.style.use('ggplot')
    
interact(Isoterma_3, K_1 = (0,150,0.5) , K_2 = (0,150,0.5), K_3 = (0,150,0.5))