<jupyter_start><jupyter_text>Presentaciones y encuestas interactivas con jupyter notebooks y RISE pycon Colombia 2020 <NAME> 07 Febrero 2020 **Observaciones:*** sebastiandres en twitter y github.* Presentación en [github.com/sebastiandres/charlas](github.com/sebastiandres/charlas)* Opiniones y críticas a título personal. Hola. Mi nombre es <NAME>, y quiero compartir algunos experimentos que realicé para realizar encuestas en vivo mientras se presenta en jupyter notebook con la extensión RISE.  No es necesario que tomen apuntes, la presentación y todos los enlaces están en mi github: sebastiandres (el repo se llama charlas, es el primero).  Introducción¿Porqué esta presentación? ¿Se pueden hacer encuestas interactivas en presentaciones con jupyter notebooks? La necesidad nació hace algunos meses cuando la noche anterior a realizar una charla a unos estudiantes, quise realizar una encuesta en vivo, pero me di cuenta que no sabía como hacerlo sin salir de RISE y jupyter notebook. Mi talento googleador tampoco me ayudó, así que supongo que si alguien ya lo ha hecho, no lo ha documentado. Así que al menos esto sirve para auto-contestarme. Esto va para ti, Sebastian del lejano pasado.  Agenda0. Sobre hacer presentaciones con RISE.1. Solución 1: Quick & dirty.2. Solución 2: ¡Pero quiero los datos!3. Solución 3: No confío en nadie. La presentación está estructurada de lo más general a lo más específico, y de lo más mainstream a lo más geek/hipster. Así que un poco de paciencia si hay cosas que parecen muy evidentes.  0.1 Sobre hacer presentaciones con jupyter y RISE¿Consejos sobre hacer presentaciones en general? * Contenido pensado en tu audiencia. * Ensayar, ensayar, ensayar.* Incrementar el desafío. Relato: ¿Cómo hacer una buena presentación? Este es un tema en sí mismo. No soy para nada un experto, pero he aprendido algunas cosas.Relato: Aunque parezca un consejotrivial, hay 2 elementos a considerar: saber quién es la audiencia y preparar el contenido necesario. Y haber ensayado varias veces la presentación y ser familiar con el contenido es la mejor forma de que el relato sea fluido. Al final, toda habilidad es como un músculo. Cuando lo ejercitas, se vuelve más fuerte y resulta más fácil usarlo. Esta misma presentación ya la he ensayado unas 10 veces. Sí, toma tiempo.  0.2 Sobre hacer presentaciones con jupyter y RISESi forma parte importante de tu día a día, investiga y aprende a hacer mejores presentaciones. Libro que considero muy bueno: Confessions of a public speaker - <NAME>. Relato: Por supuesto, hay varios libros que se pueden leer al respecto. A mi me gustó este. Confessions of a public Speaker - <NAME>. Consejos prácticos y con un tono de humor.  0.3 Sobre hacer presentaciones con jupyter y RISE¿jupyter notebook? ¿RISE?  0.3 Sobre hacer presentaciones con jupyter y RISE¿Qué es la extensión RISE?Una celda de jupyter notebook se puede clasificar (adicionalmente al code/markdown) como:* *Slide*: Diapositiva normal.* *Fragment*: Fragmento de diapositiva.* *Sub-slide*: Opcional.* *Skip*: No mostrar.* *Notes*: Notas. Toda la info en https://rise.readthedocs.io/  0.3 Sobre hacer presentaciones con jupyter y RISE¿Qué es la extensión RISE?  Relato: Si les interesa pueden buscar un tutorial más completo sobre hacer presentaciones en RISE. Pero en resumen, es lo que muestra esta animación (gif). Basta marcar una celda de jupyter notebook con la propiedad “slide”, “sub-slide”, “fragment”, o “” para que esta adquiera la propiedad. Y luego se pone en modo presentación. ¡Voilá!  0.4 Sobre hacer presentaciones con jupyter y RISEOk, pero... ¿porqué? ¿Porqué? ¿PORQUÉ? * Tener una presentación autocontenida: los ejemplos (código) queda en jupyter notebook.* Corregir directamente cuando sea necesario.* Hacer participar a la audiencia.  0.4 Sobre hacer presentaciones con jupyter y RISESí, incluso ejecutar código en python<jupyter_code>x = 200
y = 200
x is y
a = 300
b = 300
a is b
def cheeseburger(n):
    return ["bread"] + ["meat", "cheese"]*n + ["bread"]

cheeseburger(3)<jupyter_output><empty_output><jupyter_text>0.5 Sobre hacer presentaciones con jupyter y RISE¿Que he aprendido? * Usa "Ctrl +" y "Ctrl -" para controlar aspecto. * Entrega parte del control de contenido al público. Usa un teclado+mouse inalámbrico. * Plantea desafíos de código incompleto pero entrega propuestas de solución. * `git` es tu amigo. * Improvisa. Nunca será como planificaste. Relato: ¿Qué cosas he aprendido en estos años haciendo presentaciones con RISE? (0) Más que jugar con los fonts, regular con Ctrl+ y Ctr- como se ve en pantalla.(1) No tener temor en pedir ideas a la audiencia sobre que valores probar o alternativas de código a implementar. (2) Usar un teclado y mouse inalámbrico, para clases de computación.(3) Poner soluciones pre-definidas a los problemas, en lugar de escribirlos en directo (por tiempo).(4) Saber que textos mostrar y cuales ocultar.(5) Usar un repo para volver a versiones anteriores.Usar un diagrama de celdas y mostrar lo que hace “con algunas cajitas”.  0.6 Descripción del Problema **¿Qué queremos?** Realizar encuesta interactiva sin salir del modo presentación (en RISE). **¿Porqué?** Hacer encuestas para obtener retroalimentación de la audiencia cuando importa, sin cambiar pantalla o sistema. Relato: Bueno, llevamos 5 minutos y todavía no hablamos siquiera del problema ¡ni código!. ¿Qué es lo que intentamos resolver? Cuando uno realiza presentación a una audiencia desafiante - estudiantes de primer año de universidad, que no resisten 45 minutos sin mirar su celular - resulta interesante proporcionar un medio para obtener retroalimentación de manera sencilla y directa. Pero ¿Podemos hacer eso en presentaciones con jupyter notebook?   1.7 Descripción del Problema **¿Se puede?** Sí, y de varias maneras distintas. **¿Cómo?** IFrames. Relato: Pensaba que era algo muy dificil. Pero finalmente encontré varias formas distintas.  0.9 Descripción del ProblemaNuestro héroe se llama IFrame.<jupyter_code>from IPython.display import IFrame
IFrame("https://es.wikipedia.org/wiki/Iframe", width=1000, height=500) #https://es.wikipedia.org/wiki/Iframe<jupyter_output><empty_output><jupyter_text>Otros:* https://www.pycon.co/* https://rise.readthedocs.io/ Relato: Las funciones HTML y Iframe son nuestras héroes. Todo esfuerzo de lo que haremos recae en sus hombros. Diferencias de html y iframe. DEFINICION DE IFRAME. Mostrar   0.10 Descripción del ProblemaMás ejemplos ...<jupyter_code>from IPython.display import IFrame
IFrame("https://www.python.org/", width=800, height=300)<jupyter_output><empty_output><jupyter_text>No siempre funciona:* https://www.python.org/* google, facebook, twitter, ... En general a los sitios (sobre todo los que requieren autentificación y desean hacer tracking de usuarios) bloquean los IFrames.  0.11 Descripción del Problema: EXTRAMás ejemplos ...¡IFrame nos permite incluso embeber un jupyter notebook dentro de otro!<jupyter_code>from IPython.display import IFrame
link="http://localhost:8888/notebooks/2020_02_XX_pycon_rise_and_poll/2020_pycon_RISE_and_poll.ipynb"
#IFrame(link, width=800, height=300) #google, facebook, twitter<jupyter_output><empty_output><jupyter_text>Relato: Un aprendizaje interesante que pueden llevarse hoy, es que existen sitios que no permiten ser embebidos en un iframe. Por ejemplo, si tratamos de hacer un iframe de google, nos da el siguiente error. ¿Porqué? Porque XYZ.Sin embargo, podemos usar un acortador de dirección para evitar ese problema. Por ejemplo, el mismo acordador de dirección de google nos permite bypasear su propia seguridad. Hermoso.  1.1 Problema: Realizar encuestas interactivas.**Solucion nivel 1:**KISS: Keep IT Simple, Stupid. Podemos usar IFrame con los servicios de alguna compañía especializada en encuestas interactivas:* Polleverywhere* Mentimeter* Muchos, muchos otros... Relato: Solución nivel 1. Meme de “cerebro”. Hay un principio elemental en programación: KISS. Keep it Simple, Stupid. No hay para que reinventar la rueda cuando podemos aprovechar lo que otras personas ya han hecho.Relato: Hay varias empresas que proporcionan servicios para realizar encuestas en vivo, que funciona a través de páginas web. Algunas de las empresas que pueden revisar para esto son: Mentimeter, Survey, Polleverywhere, por ejemplo. Spoiler Alert: Son todas bastante parecidas.  1.2 Solución nivel 1: EncuestaProbemos este método con una encuesta simple:<jupyter_code>from IPython.display import IFrame
IFrame("https://pollev.com/sebastianflo711", width=800, height=600)<jupyter_output><empty_output><jupyter_text>Relato: Hagamos un primer experimento. Yo ya cree una encuesta que deberán responder. ¿Listos? En sus celulares, busquen la página web que se encuentra en pantalla y voten. Mostrar con un iframe y leer.  1.3 Solución nivel 1: Link encuesta:  https://pollev.com/sebastianflo711 **¿Qué debe cumplir un sitio de encuestas interactivas?*** Encuesta acccesible por url pública, incrustable por iframe.* Gráfico dinámico accesible por url pública, incrustable por iframe. Relato: ¿Qué necesitamos de esta encuesta? Que tenga las siguientes características:Encuesta accesible con una url pública, para poder compartir el enlace durante la presentación.Gráficos disponibles a partir de una url pública o privada, para incrustarla el grafico en la ppt.  1.3 Solución nivel 1:Veamos los resultados de la encuesta anterior.<jupyter_code>from IPython.display import IFrame
IFrame("https://www.polleverywhere.com/multiple_choice_polls/7Xwy472JbCrk3fITm12XM", width=800, height=600)
# Observación: ¡requiere estar autentificado como dueño de la encuesta!<jupyter_output><empty_output><jupyter_text>Relato: Mientras ustedes votan, podemos ya comenzar a ver los resultados. Ejecutar el iframe varias veces.  1.4 Solución nivel 1:  Resumen¿Cómo se debe usar? 1. Seleccionar algún proveedor.1. Crear y configurar la encuesta previamente.1. Obtener el enlace de las preguntas, e incrustarla con un iframe.1. Obtener el gráfico de las respuestas, e incrustarla con un iframe.1. Probar que funcione correctamente. Borrar respuestas de prueba.  Relato: En general, la versión “gratis” permite hacer preguntas y ver los resultados, pero requiere haberla preparado antes para tener el enlace, y no permite descargar los resultados para explorarlos más “cientificamente”. Es necesario haber creado la presentación de antemano y es más difícil cambiarla a último momento. Dependiendo de la empresa, funciona más o menos fácil y “auto-refresh”.  1.5 Pausa¿Que viene antes, el huevo o la gallina?<jupyter_code># Solución al problema
# python3 permite usar unicode
sorted(['\N{EGG}', '\N{CHICKEN}'])<jupyter_output><empty_output><jupyter_text>2.1 Problema: Realizar encuestas interactivas.**Solución Nivel 2**Una segunda opción que requiere un poco más de configuración pero entrega más control, es usar un servicio de encuestas tradicional: * Microsoft Forms* Google Forms* Survey Monkey* Typeform* Muchas otras...Se diferencia que nosotros podemos hacer los gráficos porque podemos descargar los datos. Relato: El siguiente nivel es enviar una encuesta de un servicio más estándar, como Google Survey, Microsoft Forms, Survey Monkey o Typeform.  2.2 Solución Nivel 2: Encuesta + DatosProbemos este método con otra encuesta simple:<jupyter_code>long_url = "https://forms.office.com/Pages/ResponsePage.aspx?id=zu7OdUTRPU-clJ5rQCX8_4qs5cX1Y7dFhVdiCz848sBUNFU3UzU3OTNHVDhWNURSMEs2WDBUMDdCTi4u"
short_url = "https://bit.ly/2uYDdhm"
iframe_options = {"width":800, "height":600}
IFrame(short_url, **iframe_options)<jupyter_output><empty_output><jupyter_text>Notas: Por ejemplo, accedan a la encuesta que se encuentra en la siguiente dirección:   2.3 Solución Nivel 2:  Link encuesta:  https://bit.ly/2uYDdhm ¿Qué debe cumplir un sitio de encuestas nivel 2?* Encuesta accesible al público mediante un enlace abierto. Puede que no sea incrustable con un iframe.* Opcionalmente, que cuente con gráficos en línea.* Datos disponibles y puedan descargarse.* Crear una función (en Python) para descargar e interpretar los datos.* Probar que la encuesta funcione. Borrar las respuestas de prueba. Notas: ¿Que fue lo que hicimos acá? Veamos un poco más de detalle. La página web que accesaron tuvo que ser creada antes, y el link para compartir incrustado en la presentación. La tabla con los resultados se interpreta con alguna función apropiada, por ejemplo, en este caso, usé pandas y matplotlib porque porqué no.  2.4 Solución Nivel 2: Respuestas<jupyter_code>long_url = "https://forms.office.com/Pages/AnalysisPage.aspx?id=zu7OdUTRPU-clJ5rQCX8_4qs5cX1Y7dFhVdiCz848sBUNFU3UzU3OTNHVDhWNURSMEs2WDBUMDdCTi4u&AnalyzerToken=<KEY>"
short_url = "https://bit.ly/37We2dE"
iframe_options = {"width":800, "height":600}
IFrame(short_url, **iframe_options)<jupyter_output><empty_output><jupyter_text>2.4 Solución Nivel 2: Respuestas  (versión 2)* Descargamos la planilla de datos con el resultado desde algún [enlace](https://uplanner-my.sharepoint.com/:x:/r/personal/sebastian_flores_u-planner_com/_layouts/15/Doc.aspx?sourcedoc=%7B7D9BF52E-2931-4702-86ED-00792E617ECF%7D&file=2020_02_09_encuesta2_pycon.xlsx&action=default&mobileredirect=true)<jupyter_code># Alternative to ls data/*.xlsx
import glob
glob.glob("data/*.xlsx")
import pandas as pd
df_dict = pd.read_excel("data/2020_02_08_encuesta2_pycon.xlsx", sheet_name=None)
df_dict.keys()
df = df_dict["Form1"]
question = df.columns[-1]
print(question)
df.head()<jupyter_output><empty_output><jupyter_text>La tabla con los resultados se interpreta con alguna función apropiada, por ejemplo, en este caso, usé pandas y matplotlib porque porqué no.  2.5 Solución Nivel 2: Respuestas<jupyter_code>question_df = df[question]
answer_counts = question_df.value_counts()
answer_counts
from matplotlib import pyplot as plt
answer_counts.plot.barh(figsize=(16,6))
plt.show()<jupyter_output><empty_output><jupyter_text>2.6 Solución Nivel 2: RespuestasHagamos un gráfico un poco mejor.<jupyter_code>from matplotlib import pyplot as plt
answer_counts.plot.barh(figsize=(16,6), fontsize=16, alpha=0.60)
plt.suptitle(question, fontsize=16)
plt.xlabel("Número de respuestas", fontsize=16)
plt.ylabel("");<jupyter_output><empty_output><jupyter_text>2.7 Solución nivel 2: Resumen1. Elegir algún proveedor.1. Crear la encuesta.1. Obtener la url pública de las preguntas, e incrustarla en un iframe.1. Obtener la url de los datos de las respuestas.1. Usar una api o descargar los datos.1. Graficar desde python para interpretar los datos. Leer.  2.1 Problema: Realizar encuestas interactivas.**Solución Nivel 3**La solución más compleja es por supuesto hacer el sistema completo: * **Base de datos**: donde almacenar la encuesta y las respuestas. * **Frontend**: para realizar la encuesta (mostrar preguntas, recolectar respuestas, mostrar gráficos).* **Backend**: interactuar con la base de datos.  En este caso: mysql, flask, flask-mysql y pandas, con algo de html y css, y una librería de javascript para graficar. Notas: Por supuesto, la versión que nos da más control de todo es hacerlo a lo macgiver. Par los millenials de la sala, macgiver es un programa de televisión donde el protagonista podía hacer una bomba con un moco. En fin, la idea es hacer todo desde cero: la página web con su base de datos y gráficos.  Solución Nivel 3¿Porqué alguien voluntariamente se sometería a este tormento? **Filosofía xkcd**: ¿Porqué hacer algo simple cuando podrías hacer algo extremadamente complejo *de la manera más simple posible*, aprendiendo mucho en el camino?   Solución Nivel 3¿xkcd en python?<jupyter_code>import antigravity<jupyter_output><empty_output><jupyter_text>Solución Nivel 3<jupyter_code>from IPython.display import IFrame
IFrame("http://localhost:5000/", width=1200, height=800)<jupyter_output><empty_output><jupyter_text>Notas: Sí, es bastante trabajo. Este es un diagrama reducido de cómo funcionaría.  Solución Nivel 3El código de polite se encuentra en https://github.com/sebastiandres/surveys_with_flask_and_xkcd_charts. Hace uso de muchos recursos públicamente disponibles (además de mysql y  python+librerías):* Font xkcd.ttf de ipython, https://github.com/ipython/xkcd-font* Librería xkcd_chart en javascript: https://timqian.com/chart.xkcd/* Una cantidad vergonzosamente grande de búsquedas en internet y stackoverflow.  Notas: Pero tiene la ventaja que es posible dejarlo tal y cual lo queremos. Por ejemplo, si quiero cambiar la pregunta y sus opciones durante la presentación. Para lograr esto le di la funcionalidad de que genere automáticamente una encuesta a partir de un texto con formato markdown.  Solución Nivel 3Una de las cosas que más me llamó la atención fue cómo hacer una función que pudiese transformar un texto markdown en la serie de preguntas y opciones de respuesta. Requería definir convenciones:* La pregunta es todo lo que va antes de `:`* Las preguntas de respuesta única se definen por `*` * Las preguntas de respuesta única se definen por `^`Otra opción podría haber sido `-` y `+`. Es una mala opción usar `o` y `m`.   Solución Nivel 3<jupyter_code>def markdown_parser(my_text):
    if my_text.count(":")!=1:
        print("Cannot parse, there's an error in the format")
        return {"is_format_ok":False, "markdown_str":my_text}
    single_option = 0
    multiple_option = 0
    if ("* " in my_text):
        single_option = 1
        split_char = "*"
    if ("^ " in my_text):
        multiple_option = 1
        split_char = "^"
    # If both False or both True, simultaneoulsy, there's an error
    if single_option==multiple_option:
        print("Cannot parse, there's an error in the format")
        return {"is_format_ok":False, "markdown_str":my_text}
    question_str, answer_str = my_text.split(":")
    question = question_str.strip()
    answer_list = [_.strip() for _ in answer_str.split(split_char)[1:6]] # Skip the empty string, reach to the fifth existing one
    answer_list = answer_list + ["" for _ in range(5-len(answer_list))] # Fill with empty ones if needed
    question_type = single_option*"radio"+multiple_option*"checkbox" # This is the html convention
    # Create the dict
    md_dict = {}
    md_dict["is_format_ok"] = True
    md_dict["markdown_str"] = my_text
    md_dict["type_str"] = question_type
     md_dict["question_str"] = question
    md_dict["option_1_str"] = answer_list[0]
    md_dict["option_2_str"] = answer_list[1]
    md_dict["option_3_str"] = answer_list[2]
    md_dict["option_4_str"] = answer_list[3]
    md_dict["option_5_str"] = answer_list[4]
    return md_dict<jupyter_output><empty_output><jupyter_text>Solución Nivel 3<jupyter_code>markdown_parser("Q: ^ A * B * C * D * E * F * G ")
markdown_parser("""Q: ^ A ^ B ^ C ^ D ^ E ^ F ^ G ^ H""")<jupyter_output><empty_output><jupyter_text>Solución Nivel 3Hagamos la prueba:<jupyter_code>from IPython.display import IFrame
IFrame("http://localhost:5000/survey", width=1000, height=1000)<jupyter_output><empty_output><jupyter_text>Solución Nivel 3Veamos los resultados:<jupyter_code>from IPython.display import IFrame
IFrame("http://localhost:5000/bar_chart", width=1000, height=1000)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07620788717680857, 'fraction_numerical': 0.01854270044398015, 'mean_word_length': 5.325074331020812, 'pattern_counts': {'":': 10, '<': 78, '<?xml version=': 0, '>': 78, 'https://': 19, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '632402', 'license': 'MIT', 'n_tokens_mistral': 6756, 'n_tokens_neox': 6412, 'n_words': 2319, 'path': '2020_02_08_pycon_rise_and_poll/2020_pycon_RISE_and_poll.ipynb', 'repo_name': 'sebastiandres/charlas', 'size': '19204'}