RISE = Reveal.js IPython Slide Extension
Es una extensión a los jupyter notebooks que permite transformarlos en una presentación interactiva.
Con herramientas de markdown, html y latex: $ e^{i \pi} + 1 = 0 $
y python:
print("Hola \U0001F30E")
Hola 🌎
Simplificar la generación de material.
Simplificar la distribución del material.
Puedes mezclar contenido usando las celdas de markdown y código, según necesites:
Como regla general, si se muestra correctamente en el notebook, se verá bien en la diapositiva.
¡Sé creativo! La gracia es precisamente que todo puede ser interactivo.
Incluir gifs animados es igual de fácil que incluir imágenes, y suele ayudar a tener apoyos visuales atractivos.
Para mostrar gráficos resulta práctico que no se genere una ventana adicional, sino que se agreguen a la celda de resultados. Esta es una práctica común en jupyter notebook/lab, pero es más importante aún al pensar en las diapositivas.
%matplotlib inline
from matplotlib import pyplot as plt
import numpy as np
with plt.xkcd():
fig = plt.figure(figsize=(14,6))
x = np.linspace(-5,5,num=100)
y = np.abs(np.abs(np.sin(2*x)/x))
plt.plot(x,y)
from IPython.display import Audio, Image, display
a = Audio("http://www.w3schools.com/html/horse.ogg")
i = Image(filename="images/Python.png", width=100)
display(a,i)
from IPython.display import Javascript
Javascript('alert("¡¡Tenemos javascript!!");')
%matplotlib inline
import ipywidgets as widgets
import numpy as np
import matplotlib.pyplot as plt
@widgets.interact(grado=(0, 9), N_puntos=(5,35))
def mi_plot(grado=3, N_puntos=5):
x = np.linspace(-10, 10, N_puntos)
y = x**grado
plt.figure(figsize=(12,8))
plt.plot(x, y, 'ro-')
plt.grid(True)
plt.show()
Si tienes una librería (en local, en línea o en pypi) puedes usar la presentación para mostrar como se usa... ¡en vivo!
Por ejemplo, un proyecto llamado pypsdier para la simulación de ecuaciones de reacción-difusión de catalizadores inmobilizados
!pip install git+https://github.com/sebastiandres/pypsdier.git --upgrade
WARNING: Ignoring invalid distribution -rnado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ornado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution - (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cikit-learn (/miniconda3/lib/python3.7/site-packages) Collecting git+https://github.com/sebastiandres/pypsdier.git Cloning https://github.com/sebastiandres/pypsdier.git to /private/var/folders/68/v1ds0ld152q_wk4sbcns3ckw0000gn/T/pip-req-build-594v9sm6 Running command git clone -q https://github.com/sebastiandres/pypsdier.git /private/var/folders/68/v1ds0ld152q_wk4sbcns3ckw0000gn/T/pip-req-build-594v9sm6 WARNING: Ignoring invalid distribution -rnado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ornado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution - (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cikit-learn (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -rnado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ornado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution - (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cikit-learn (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -rnado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -ornado (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution - (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cipy (/miniconda3/lib/python3.7/site-packages) WARNING: Ignoring invalid distribution -cikit-learn (/miniconda3/lib/python3.7/site-packages) WARNING: You are using pip version 21.1.1; however, version 21.2.4 is available. You should consider upgrading via the '/miniconda3/bin/python -m pip install --upgrade pip' command.
import pypsdier
SIM = pypsdier.SimulationInterface()
SIM.status()
System configuration: environment: python python version: 3.7.4 GenericSimulationLibrary version: 1.1.1 numpy version: 1.19.5 scipy version: 1.6.3 xlwt version: 1.3.0 matplotlib version: 3.3.3 dill version: 0.3.2 Inputs: No inputs Plot Options: No plot_options Simulations: ODE: no PDE: no
SIM.load("data/pypsdier_example.rde")
SIM.status()
Loaded a simulation from /Users/sebastiandres/Projects/charlas-y-eventos/talk_2021_08_pylatam/data/pypsdier_example.rde System configuration: environment: google_colab python version: 3.6.9 GenericSimulationLibrary version: 1.1.0 numpy version: 1.18.5 scipy version: 1.4.1 xlwt version: 1.3.0 matplotlib version: 3.2.2 dill version: 0.3.2 Inputs: SimulationTime: 120.0 SavingTimeStep: 1.0 CatalystVolume: 0.5 BulkVolume: 100.0 Names: ('Substrat',) InitialConcentrations: (1.3,) EffectiveDiffusionCoefficients: (5.3e-10,) CatalystParticleRadius: [4e-05, 6e-05, 8e-05] CatalystParticleRadiusFrequency: [0.3, 0.5, 0.2] ReactionFunction: <function MichaelisMenten at 0x13daeeb90> ReactionParameters: (41, 0.13) CatalystEnzymeConcentration: 0.35 Plot Options: title: Simulación de Michaelis Menten para la PyconAr label_x: Tiempo de reacción [s] label_y: Concentración [mM] ode_kwargs: {'label': 'ode', 'color': 'black', 'marker': '', 'markersize': 6, 'linestyle': 'dashed', 'linewidth': 2} pde_kwargs: {'label': 'pde', 'color': 'black', 'marker': '', 'markersize': 6, 'linestyle': 'solid', 'linewidth': 2} data_kwargs: {'label': 'exp', 'color': 'red', 'marker': 's', 'markersize': 6, 'linestyle': 'none', 'linewidth': 2} data_x: [0.0, 30, 60, 90, 120] data_y: [1.3, 0.65, 0.25, 0.1, 0.0] Simulations: ODE: yes PDE: yes
SIM.plot()
Al empaquetar tu código con clases, asegúrate de incluir una función _repr_html_
para poder interactuar nativamente con jupyter notebook (y RISE):
class Alerta(object):
def __init__(self, text):
self.text = "\U000026A0 - " + text.upper()
def _repr_html_(self):
return "<h1 style='color:white;background:red;padding:30px'>" + self.text + "</h1>"
Alerta("Comenzar a hablar de RISE")
Paso 1:
La instalación de la extensión RISE es extremadamente fácil:
pip install rise
o
conda install -c conda-forge rise
Eso hará que se agregue el botón de iniciar presentación (destacado en rojo).
Paso 2:
En el menú de jupyter notebook, es necesario seleccionar View/Cell Toolbar/Slideshow
para que permita configurar el tipo de celda para diapositiva.
Existen varios tipos de celda con distintas funcionalidades:
-
: valor por defecto. La celda se muestra con la slide anterior.Slide
: inicia una nueva diapositiva (dirección horizontal).Sub-slide
: iniciar una nueva sub-diapositiva (dirección vertical).Fragment
: se concatena a la celda anterior, pero no se muestra inmediatamente. Skip
: no se muestra la celda en las diapositivas.Notes
: No se muestra en las diapositivas, sólo se muestra en las notas para el presentador.Al hacer click en el botón "Iniciar presentación", la presentación se iniciará en la celda que esté activa.
Espacio
(o la flecha derecha).Shift Espacio
(o la flecha izquierda).Page Up
.Page Down
.¡O simplemente usar el mouse!
Existen 2 direcciones: slides (izquierda a derecha) y subslides (arriba a abajo).
Personalmente no uso subslides porque no logro recordar un orden que no sea lineal, y termino saltándome las subslides sin querer.
Existen múltiples funcionalides accesibles con el teclado durante la presentación, pero las principales a recordar son:
,
: ocultar los botones.w
: Mostrar orden de diapositivas.?
: ver todos los atajos de teclado.Un problema común es que al conectar el computador a otra pantalla o datashow, no se alcanza a ver en la diapositiva todo el código, texto o imagen.
Ctrl +
y Ctrl -
permiten regular el tamaño (⌘+
y ⌘-
en Mac), de la misma manera que regulas el tamaño de una página web.
Puedes abrir las notas del presentador presionando t
.
Para poder usar las notas del presentador necesitas tener al menos 2 pantallas.
Existen 3 formas de presentar con jupyter notebook + RISE:
Para cada celda (markdown o código) que tengas en el jupyter notebook, indica que tipo de diapositiva deberá usar.
Usar principalmente:
Slide
: inicia una nueva diapositiva (dirección horizontal).-
: Se concantena a la interior inmediatamente.Fragment
: se concatena a la celda anterior, pero con una animación (no inmediata).Evitar:
Skip
: no se muestra la celda en las diapositivas.Notes
: No se muestra en las diapositivas, sólo se muestra en las notas para el presentador.Sub-slide
: iniciar una nueva sub-diapositiva (dirección vertical).Si ya tienes una presentación pptx, puedes convertirla con una herramienta en línea. No es perfecta, pero te ahorrará un buen tiempo de copiar y pegar texto.
https://share.streamlit.io/sebastiandres/streamlit_ppt2rise/main
El funcionamiento es el siguiente. Supongamos que tienes una presentación que necesitas convertir: simple.pptx
simple.pptx
Primero que nada, en el sitio debes cargar la presentación, esperar que se convierta y descargar el notebook + RISE equivalente:
Después de descargar y descomprimir, al lanzar el notebook en jupyter la presentación debería comenzar de inmediato:
Todas las configuraciones de RISE se realizan editando la metadata del notebook.
Para ello, tienes que ir a Edit/Edit notebook metadata
y agregar la(s) opcion(es) deseadas.
La metadata es un diccionario json con las distintas opciones de todo el notebook. Por defecto, no trae ninguna opción cargada de RISE. Por eso, tenemos que agregar las opciones que se quieren configurar:
"rise": {
"opcion_1": valor_opcion_1,
...
"opcion_n": valor_opcion_n,
}
`
Observación importante:
Cada vez que editas la metadata, es necesario cerrar (apagar) el notebook y volver a abrirlo para que se recarguen las opciones.
El tema de la presentación controla el aspecto general de la presentación.
En la metadata del notebook se agrega la opción de "theme" con el nombre del tema deseado:
"rise": {"theme": "sky"}
`
Existen 11 opciones, que se heredan de la librería revealjs:
La imagen fue compilada por el siguiente blog.
El tipo de transición entre slides se define de manera similar. En la metadata del notebook se agrega la opción de "transition" con el nombre de la transición deseada:
"rise": {"transition": "zoom"}
Las opciones, heredadas de las transiciones existentes en la librería revealjs, son:
Los tipos de transiciones se muestran en esta animación:
Simplemente, usar:
"rise": {
"backimage": "mybackimage.png",
}
}
Esta opción es útil si quieres un fondo personalizado, como a veces se exige en algunos congresos. Como es habitual al manejar imágenes, conviene usar archivos png con fondo transparente para que se integre bien con el theme elegido.
Simplemente, usar:
"rise": {
"header": "<h1>Hola</h1>",
"footer": "<h3>Mundo</h3>"
}
}
Puedes usar <br>
y
para introducir saltos de línea y espacios en blanco, respectivamente.
En la metadata del notebook se agrega la opción de "autolaunch" con valor true
(todo en minúsculas, ¡es verdadero de javascript, no de Python!):
"rise": {"autolaunch": true}
`
Al publicar tu jupyter notebook con mybinder.org, se mostrará en modo presentación automáticamente.
Es posible activar una pizarra (chalkboard) para realizar anotaciones durante la presentación.
Para eso, en Edit/Edit Notebook Metadata, es necesario agregar el siguiente texto a la metadata del jupyter notebook:
{
...
"rise": {"enable_chalkboard": true}
}
Durante la presentación se puede utilizar la pizarra haciendo click en los íconos, que permiten dibujar en una pizarra o sobre las diapositivas.
Es posible cambiar de color de lapiz presionando s
y q
. Se puede borrar la pizarra con -
.
Las anotaciones se preservan incluso al cerrar el modo presentación. Sin embargo, no se guardan al cerrar el notebook.
Tantas opciones pueden ser sobrecogedoras y difíciles de recordar. Como no se puede tener comentarios en un json, resulta práctico tener guardadas todas las opciones y simplemente agregar un _
antes de las opciones que no se desean usar.
"rise": {
"autolaunch": true,
"enable_chalkboard": true
"theme": "black",
"transition": "zoom",
"_header": "<h1>PRESENTATION NAME // EVENTs</h1>",
"_footer": "<h3>NAME, DATE</h3>",
"_backimage": "path/to/mybackimage.png",
"_theme_options": [ "black", "white", "league", "beige",
"sky", "night", "serif"],
"_transition_options": ["none", "fade", "slide", "convex", "concave", "zoom"],
}
No trabajes en local: usa git + repositorio en línea: github, bitbucket, gitlab u otros.
Incluye:
requirements.txt
: librerías que se requieren en el notebook.En github, al activar "Gitub Pages" las páginas html de tu repo pueden consultarse y navegarse.
El archivo de nombre_repo/ruta_carpetas/nombre_archivo.html
se visualizará en https://nombre_usuario.github.io/nombre_repo/ruta_carpetas/nombre_archivo.html
.
Binder es un servicio que permite lanzar un jupyter notebook en el navegador y en la nube, sin consumir recursos de tu computador y de manera completamente gratuita.
Resulta práctico para que otras personas pueden ver la presentación de manera interactiva sin tener que instalar nada en su computador, ¡incluso desde un smartphone o tablet!
Para usar mybinder, debes tener tu repositorio en github.
En Binder puedes introducir los distintos parámetros:
requirements.txt
La siguiente página mostrará tu notebook:
https://mybinder.org/v2/gh/nombre_usuario/nombre_repositorio/nombre_rama?filepath=ruta_carpetas/nombre_archivo.ipynb
Incluirá la extensión RISE si la colocaste en los requirements.txt
.
En el terminal:
jupyter nbconvert --to slides ruta_carpeta/nombre_archivo.ipynb
Se generará un archivo html estático de tu presentación, con el nombre ruta_carpeta/nombre_archivo.slides.html
Se requieren 3 pasos:
Genera las diapositivas en html, usando nbconvert, para que queden "activas":
jupyter nbconvert --to slides ruta_carpeta/nombre_archivo.ipynb --post serve
Se abrirá una página web en el navegador, en la dirección http://127.0.0.1:8000/nombre_archivo.slides.html#/
Edita la ruta, para que sea http://127.0.0.1:8000/nombre_archivo.slides.html?print-pdf
.
Finalmente, guarda la página web como pdf.
Incluye un archivo html con todas las opciones, y deja que el usuario elija:
Para mostrar columnas mezclando texto e imagenes, simplemente usamos un poco de html:
<div>
<div style="display: inline-block; width: 40%;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div style="display: inline-block; vertical-align: text-bottom; width: 40%;">
<img src="images/2columns.gif" alt="LoreIpsum">
</div>
</div>
Consejo: keep it simple.
Gastar 1 hora en una diapositiva que mostrarás 1 minuto puede ser una mala inversión.
Reveal.js soporta animaciones bastante complejas.
Creo que es mejor mantener simple, pero siempre puedes buscar en https://revealjs.com/
Usando el código
<p class="fragment">Fade in</p>
<p class="fragment fade-out">Fade out</p>
<p class="fragment highlight-red">Highlight red</p>
<p class="fragment fade-in-then-out">Fade in, then out</p>
<p class="fragment fade-up">Slide up while fading in</p>
Obtenemos:
Fade in
Fade out
Highlight red
Fade in, then out
Slide up while fading in
Usando el código
<p class="fragment" data-fragment-index="3">Appears last</p>
<p class="fragment" data-fragment-index="1">Appears first</p>
<p class="fragment" data-fragment-index="2">Appears second</p>
Obtenemos:
Appears last
Appears first
Appears second
A veces quieres ejecutar una celda pero no mostrar largas filas de código.
Hay 2 formas de hacerlo:
Opción Simple:
Podemos definir la función en un archivo, y luego importarla y ejecutarla:
from mi_carpeta import mi_script
mi_script.mi_grafico(order=1, figsize=(12,8))
Si queremos mostrar la función, usamos un poco de bash:
!ls ./mi_carpeta
__init__.py __pycache__ mi_script.py
!cat mi_carpeta/mi_script.py
# Tomado y adaptado desde: # https://matplotlib.org/stable/gallery/lines_bars_and_markers/fill.html import numpy as np import matplotlib.pyplot as plt def koch_snowflake(order, scale=10): """ Return two lists x, y of point coordinates of the Koch snowflake. Parameters ---------- order : int The recursion depth. scale : float The extent of the snowflake (edge length of the base triangle). """ def _koch_snowflake_complex(order): if order == 0: # initial triangle angles = np.array([0, 120, 240]) + 90 return scale / np.sqrt(3) * np.exp(np.deg2rad(angles) * 1j) else: ZR = 0.5 - 0.5j * np.sqrt(3) / 3 p1 = _koch_snowflake_complex(order - 1) # start points p2 = np.roll(p1, shift=-1) # end points dp = p2 - p1 # connection vectors new_points = np.empty(len(p1) * 4, dtype=np.complex128) new_points[::4] = p1 new_points[1::4] = p1 + dp / 3 new_points[2::4] = p1 + dp * ZR new_points[3::4] = p1 + dp / 3 * 2 return new_points points = _koch_snowflake_complex(order) x, y = points.real, points.imag return x, y def mi_grafico(order=5, figsize=(12,8)): """ Plots the koch snowflake. Parameters ---------- order : int The recursion depth. scale : float The extent of the snowflake (edge length of the base triangle). """ x, y = koch_snowflake(order=order) plt.figure(figsize=figsize) plt.axis('equal') plt.fill(x, y) plt.show()
Opción Técnica:
Usando una función específica para ocultar código, creada con una mezcla de html y javascript.
def toggle_cell_code(button_id):
"""
Adds a button to toggle (show/hide) the code cell but not the output.
Parameters
----------
button_id : str
An identifier for cells that will hide/show when button is pressed.
"""
from IPython.display import display_html
my_html = '''
<button type="button" id="%s" onclick="code_toggle('%s')">Código</button>
<script>
function code_toggle(my_id) {
// get the parent element for the cell code and output
var p = $("#"+my_id);
if (p.length==0) return;
while (!p.hasClass("cell")) {
p = p.parent();
if (p.prop("tagName") =="body") return;
}
// get the cell code and toggle its value
var cell_code = p.find(".input");
cell_code.toggle();
}
</script>
''' %(button_id, button_id)
return display_html(my_html, raw=True)
Y así se ve en el código:
# Botón para esconder el código
toggle_cell_code("un_string_unico_y_reconocible")
# Código para graficar
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2 # 0 to 15 point radii
plt.figure(figsize=(20,14))
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()
Para incluir actividades interactivas, como las que se pueden hacer con https://www.mentimeter.com/, https://kahoot.com/ o https://quizizz.com/ (entre otros), es posible tomar varios caminos:
Simple: Colocar un código QR para que la audiencia acceda desde sus smartphones. Luego simplemente te cambias a la página correspondiente para mirar los resultados y compartirlos en pantalla.
Técnica: Incrustar la página web de la actividad mediante IFrames
. Desaconsejado, porque cada hay más restricciones a IFrames.
from IPython.display import IFrame
IFrame("https://www.pylatam.org/", width=1200, height=600)
from IPython.display import IFrame
IFrame("https://www.google.com", width=1200, height=600)
¡No desaproveches la oportunidad de aprender de tu audiencia! Termina con una encuesta.