from __future__ import print_function
from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets

"""
Explanation: <table width="100%" border="0">
  <tr>    
  <td><img src="./images/ing.png" alt="" align="left" /></td>
  <td><img src="./images/ucv.png" alt="" align="center" height="100" width="100" /></td>
  <td><img src="./images/mec.png" alt="" align="right"/></td>
  </tr>
</table>

<br>
<h1 style="text-align: center;"> Curso de Python para Ingenieros Mecánicos </h1>
<h3 style="text-align: center;"> Por: Eduardo Vieira</h3>
<br>
<br>
<h1 style="text-align: center;">  Uso de widgets interactivos en Jupyter </h1>
<br>
Después de haber aprendido a utilizar las bibliotecas de Python científico claves (NumPy, matplotlib y SymPy), con los módulos interactivos de IPython / Jupyter podemos obtener resultados interactivas de muy alta calidad y altamente personalizables.
La función interactive (IPython.html.widgets.interact) crea automáticamente y con un comando una interfaz gráfica de usuario (GUI) para la exploración de código y datos de forma interactiva. Es la forma más fácil de comenzar a utilizar los widgets de IPython.
_ Este notebook es una traducción parcial de un tutorial de Jupyter dado por sus desarroladores durante la Strata Silicon Valley 2015. Vamos a empezar por lo más sencillo._
En primer lugar, importamos los módulos que vamos a utilizar:
End of explanation
"""


def f(x):
    print(x)

"""
Explanation: Uso básico de interact
At the most basic level, interact autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use interact, you need to define a function that you want to explore. Here is a function that prints its only argument x.
A nivel más básico, interact genera controles automáticamente mediante una interfaz gráfica de usuario para los argumentos de una función que debe ser definida previamente. Así, interact llama a dicha función con los argumentos que se definieron para manipularlos con controles de forma interactiva.
Por tanto, para utilizar interact, es necesario definir la función en Python que desea explorar. Vamos a crear es una función que imprime su único argumento x:
End of explanation
"""


interact(f, x=10);

"""
Explanation: When you pass this function as the first argument to interact along with an integer keyword argument (x=10), a slider is generated and bound to the function.
Ahora utilizaremos esta función como primer argumento para interact junto con un argumento predifinido a un entero (x = 10), se autogenera un control deslizante (slider) y con que nos permite interactuar con esta función.
End of explanation
"""


interact(f, x=True);

"""
Explanation: Al mover el deslizador, se llama a la función y el valor actual de x se imprime.
Si hacemos pasar un True o False, interact generará una casilla de verificación:
End of explanation
"""


interact(f, x=u'¡Hola!');  

"""
Explanation: Si hacemos pasar una cadena de texto (string), interact generará un campo de texto:
End of explanation
"""


def h(p, q):
    print(p, q)

"""
Explanation: Fijando argumentos usando fixed
Hay momentos en los que es posible que vayamos a explorar una función utilizando interact, pero queramos fijar una o más de sus argumentos a valores específicos. Esto puede lograrse haciendo uso la función fixed.
End of explanation
"""


interact(h, p=5, q=fixed(20));

"""
Explanation: Cuando llamamos a interact, hacemos pasar fixed(20) para mantener q fijado al valor de 20.
End of explanation
"""


interact(f, x=widgets.IntSlider(min=-10,max=30,step=1,value=10));

"""
Explanation: Fijate que el deslizador solo responde a p y que el valor de q está fijado con el valor 20. 
Widget abbreviation
Cuando pasamos un entero como argumento (x=10) a interact, se genera un deslizador de valores enteros con el rango de $[-10,+3\times10]$. En este caso, 10 es una abreviación de un widget slider tipo:
python
IntSliderWidget(min=-10,max=30,step=1,value=10)
De hecho, podemos obtener el mismo resultado si pasamos este IntSliderWidget como el argumento de palabra clave para x:
End of explanation
"""


interact(f, x=(0,4));

"""
Explanation: Este ejemplo aclara como interactuar con con procesos mediante sus argumentos clave:

Si el argumento clave es Widget con un atributo tipo value, se utiliza el widget tipo slider. Cualquier widget con un atributo que resulte en un valor numérico se puede utilizar, incluso los personalizados.
De lo contrario, el valor se trata como una widget abbreviation que se convierte en un widget antes de su uso.

La siguiente tabla ofrece una visión general de los diferentes widget abbreviation:
<table class="table table-condensed table-bordered">
  <tr><td><strong>Keyword argument</strong></td><td><strong>Widget</strong></td></tr>  
  <tr><td>`True` or `False`</td><td>CheckboxWidget</td></tr>  
  <tr><td>`'Hola'`</td><td>TextareaWidget</td></tr>
  <tr><td>`value` or `(min,max)` or `(min,max,step)` if integers are passed</td><td>IntSliderWidget</td></tr>
  <tr><td>`value` or `(min,max)` or `(min,max,step)` if floats are passed</td><td>FloatSliderWidget</td></tr>
  <tr><td>`('naranja','manzana')` or `{'uno':1,'dos':2}`</td><td>Dropdown</td></tr>
</table>

Hemos visto arriba cómo funcionan los widgets checkbox y de área de texto. Veamos, más detalles sobre las diferentes abreviaturas para deslizadores y menús desplegables.
Si se pasa un tupla con dos enteros (min, max) un deslizador con valores también enteros se crea utilizando los mismos como máximo y mínimo. En este caso, se utiliza el tamaño de paso predeterminado de 1.
End of explanation
"""


interact(f, x=(0,8,2));

"""
Explanation: Si se pasa un tupla con tres enteros (min,max,step), lo que hacemos es determinar también el tamaño de paso:
End of explanation
"""


interact(f, x=(0.0,10.0));

"""
Explanation: Para que el widget devuelva valores en coma flotante, debemos pasar una tupla con valores en coma flotante. En el siguiente ejemplo, el mínimo es  0.0, el máximo es 10.0 y el intervalo es de 0.1 (por defecto).
End of explanation
"""


interact(f, x=(0.0,10.0,0.01));

"""
Explanation: De  nuevo, el  tamaño del intervalo se puede determinar haciendo uso de un tercer elemento en la tupla:
End of explanation
"""


def h(x=5.5):
    print(x)
    
interact(h, x=(0.0,20.0,0.5));

"""
Explanation: Para ambos sliders de enteros  y flotantes, se puede escoger el valor inicial del widget pasando un argumento de palabra clave por defecto a la función Python subyacente. Aquí establecemos el valor inicial de un slider con valores en coma flotante a 5.5.
End of explanation
"""


interact(f, x=['manzanas','naranjas']);

"""
Explanation: También podemos crear menús desplegables haciendo pasar una tupla de cadenas de texto (strings). En este caso, las cadenas de texto son utilizados como los nombres de la interfaz de usuario del menú desplegable y pasan a la función Python subyacente.
End of explanation
"""


interact(f, x={'uno': 10, 'dos': 20});

"""
Explanation: Si quieres un menú desplegable que pasa valores que no son cadenas de texto a la función de Python, se puede pasar un diccionario. Las palabras claves del diccionario se utilizan para los nombres de la interfaz de usuario del menú desplegable y los valores son los argumentos que se pasan a la función Python subyacente. Se puede entender mejor viendo este ejemplo:
End of explanation
"""


from __future__ import print_function
from IPython.html.widgets import interact, interactive, fixed

import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

# Vamos a cambiar el estilo por defecto (opcional)
plt.style.use('ggplot')

# Creamos un array con valores de x
x = np.linspace(0, 3*np.pi, 500)
y = np.sin(x**2)

plt.plot(x, y)
plt.title(u'Un gráfico simple');

"""
Explanation: Widgets  interactivos y Matplotlib
Como ya sabes, IPython de maravilla con Matplotlib. Veamos cómo podemos combinar los widgets interactivos con esta bibliote gráfica.
Repaso: creando un gráfico
A modo de repaso, veamos cómo creabamos un gráfico simple. Primero debemos de cargar las bibliotecas:
End of explanation
"""


def dibuja_ondas(frequencia1, frequencia2):
    x = np.linspace(0, 3*np.pi, 500)
    y = np.sin(x*frequencia1) + np.sin(x*frequencia2)
    plt.plot(x,y)
    
    plt.title(u'¡Mira mamá, gráficos interactivos!')
    
interact( dibuja_ondas, frequencia1=20., frequencia2=21.)

"""
Explanation: Haciendo un gráfico interactivo
En el siguiente ejemplo, una función que representa gráficamente la suma de dos ondas sinusoidales la combinamos con interact.
End of explanation
"""


# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = './css/aeropython.css'
HTML(open(css_file, "r").read())

"""
Explanation: Referencias

Ejemplos de IPython
End of explanation
"""


