Aplicación de Datos

¡tú puedes!

Presentación por Gabriela "Gaba" Rodriguez / @gaba / Open News Fellow 2014

¿Qué es una aplicación de noticias?

¿Qué vamos a hacer?

Jugar con conjunto de datos desde http://espanaenllamas.es/

http://gabelula.github.io/espanaenllamas/build/

Pre-requisitos

Linea de Comandos

En Windows: prompt

En Linux y Mac: Console y Terminal

Editor de Texto

Un editor de texto plano. No sirve Word pues agrega formato y otras cosas al texto que no necesitamos. Recomendaciones: notepad, sublime, gedit

Python - version 2.7

En Windows https://www.python.org/download/windows

En Mac: ya está incluido

En Linux: apt-get install python

Pip

un manejador de packetes para python

En Windows: http://docs.python-guide.org/en/latest/starting/install/win/

En Mac: sudo easy_install pip

En Linux: apt-get install pip

¡Hola Flask!

un micro framework para crear aplicaciones web en python

Usar pip para instalar Flask

$ pip install Flask

Crear directorio en donde pondremos archivos con código de la aplicación

							
								$ mkdir mi-app
							
						

Adentro crear archivo llamado app.py, donde configuremos Flask y servira como backend de nuestro proyecto.

Abrir app.py en un editor

							
								from flask import Flask
								app = Flask(__name__)
							
						

Configurar para hacer la raíz de tu sitio

Usaremos un archivo llamado 'index.html' para colocar la información. Tenemos que especificarlo en app.py

							
								from flask import Flask
								from flask import render_template
								app = Flask(__name__)

								@app.route("/")
								def index():
								    return render_template('index.html')
							
						

Crear directorio "templates"

dentro del directorio de nuestro proyecto.

							
								$ mkdir templates
							
						

Crear "index.html"

dentro del directorio "templates" y colocarle cualquier texto.

							
								¡Hola Mundo!
							
						

Volver a editar app.py

y agregarle lo siguiente para poder levantar el servidor local de Flask

							
								from flask import Flask
								from flask import render_template
								app = Flask(__name__)

								@app.route("/")
								def index():
								    return render_template('index.html')

								if __name__ == '__main__':
								    app.run(
								        host="0.0.0.0",
								        port=8000,
								        use_reloader=True,
								        debug=True,
								    )
							
						

Correr app.py en la linea de comandos

Mirar el resultado en un navegador en http://localhost:8000

							
								$ python app.py
							
						

¡Hola HTML!

Comenzar nuevamente editando "index.html". Reemplazar el contenido por el esqueleto de un archivo HTML

<!doctype html> <html lang="es"> <head></head> <body> <h1>Incendios en España entre 2004 y 2014</h1> </body> </html>

En linea de comandos correr app.py

$ python app.py
y visitar http://localhost:8000 nuevamente

Crear directorio para guardar archivos estáticos

Aqui guardaremos el CSV con nuestros datos

							
								$ mkdir static
							
						

Guardar archivo CSV

descargarlo desde https://github.com/gabelula/espanaenllamas/ y guardarlo en directorio "static".

Abrir app.py en editor de texto

Usaremos libreria csv para acceder a nuestros datos

							
								import csv
								from flask import Flask
								from flask import render_template
								app = Flask(__name__)

								csv_path = './static/incendios.csv'
								csv_obj = csv.DictReader(open(csv_path, 'r'))
								csv_list = list(csv_obj)

								@app.route("/")
								def index():
								    return render_template('index.html')

								if __name__ == '__main__':
								    app.run(
								        host="0.0.0.0",
								        port=8000,
								        use_reloader=True,
								        debug=True,
								    )

							
						

Pasarle la lista de datos del csv a index.html

							
								import csv
								from flask import Flask
								from flask import render_template
								app = Flask(__name__)

								csv_path = './static/incendios.csv'
								csv_obj = csv.DictReader(open(csv_path, 'r'))
								csv_list = list(csv_obj)

								@app.route("/")
								def index():
								    return render_template('index.html',
								        object_list=csv_list,
								    )

								if __name__ == '__main__':
								    app.run(
								        host="0.0.0.0",
								        port=8000,
								        use_reloader=True,
								        debug=True,
								    )

							
						

Guardar app.py y editar index.html

Colocar la lista del csv en el index.html

<!doctype html> <html lang="es"> <head></head> <body> <h1>Incendios en España entre 2004 y 2014</h1> {{ object_list }} </body> </html>

En linea de comandos correr app.py

$ python app.py
y visitar http://localhost:8000 nuevamente

Vamos a darle formato a los datos en index.html

Estamos usando el lenguaje de templating jinja de Flask

<!doctype html> <html lang="es"> <head></head> <body> <h1>Incendios en España entre 2004 y 2014</h1> <table border=1 cellpadding=7> <tr> <th>Comunidad</th> </tr> {% for obj in object_list %} <tr> <td>{{ obj['COMUNIDAD'].decode('UTF-8') }}</td> </tr> {% endfor %} </table> </body> </html>

Refrescar el navegador con nuestra aplicación

<table border=1 cellpadding=7> <tr> <th>Identificador</th> <th>Superficie Forestal Quemada</th> <th>Fecha</th> <th>Muertos</th> <th>Heridos</th> <th>Comunidad</th> <th>Provincia</th> <th>Comarca</th> <th>Causa</th> <th>Perdidas</th> </tr> {% for obj in object_list %} <tr> <td>{{ obj['IDPIF'] }}</td> <td>{{ obj['SUPQUEMADA'] }}</td> <td>{{ obj['FECHA'] }}</td> <td>{{ obj['MUERTOS'] }}</td> <td>{{ obj['HERIDOS'] }}</td> <td>{{ obj['COMUNIDAD'].decode('UTF-8') }}</td> <td>{{ obj['PROVINCIA'].decode('UTF-8') }}</td> <td>{{ obj['COMARCA'].decode('UTF-8') }}</td> <td>{{ obj['CAUSA'].decode('UTF-8') }}</td> <td>{{ obj['PERDIDAS'] }}</td> </tr> {% endfor %} </table>

Refrescar el navegador para nuestra app

http://localhost:8000

Ahora página de detalles por incendio

Agregamos una nueva ruta en archivo "app.py"

							
								import csv
								from flask import Flask
								from flask import render_template
								app = Flask(__name__)

								...

								@app.route("/")
								def index():
								    return render_template('index.html',
								                           object_list=csv_list
								                          )

								@app.route('//')
								def detail(number):
								    return render_template('detail.html')

								if __name__ == '__main__':
								  ...

							
						

Agreguemos el template "detail.html"

							
								# Macs y Linux:
								$ touch templates/detail.html
							
						
							
								# Windows:
								$ start notepad++ templates/detail.html
							
						

Editamos el archivo detail.html

Agregar algo simple. Y levantamos la página en el navegador con cualquier número. http://localhost:8000/2004210126/

							
								¡Hola España!
							
						

Buscamos el incendio

Conectamos el número en la URL con el número identificador real del incendio en el CSV.

Editamos app.py y convertimos la lista que tenemos en algo donde el incendio sea fácilmente buscable por identificador

							
								csv_path = './static/incendios.csv'
								csv_obj = csv.DictReader(open(csv_path, 'r'))
								csv_list = list(csv_obj)

								csv_dict = dict([[o['IDPIF'], o] for o in csv_list])
							
						

Editamos la función detail en app.py

para que conecte el número en la URL con el registro correspondiente.


								@app.route('//')

								def detail(number):
								    return render_template('detail.html',
								        object=csv_dict[number],
								    )
						

Volver a editar detail.html

para agregarle datos desde nuestro CSV

<!doctype html> <html lang="es"> <head> <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8"> </head> <body> <h1>{{ object['COMUNIDAD'].decode('UTF-8') }}</h1> </body> </html>

Reiniciar el servidor y refrescar el navegador del incendio

http://localhost:8000/2004210126/

							
								$ python app.py
							
						

Editar "index.html" para enlazar la página del incendio

En la tag table reemplazar la fila de

<td>{{ obj['IDPIF'] }}</td> por

<td><a href="{{ obj['IDPIF'] }}/">{{ obj['IDPIF'] }}</a></td>

Reiniciar el servidor de pruebas y refrescar el navegador

http://localhost:8000

							
								$ python app.py
							
						

Agregar el resto de los campos del incendio

en detail.html

<body> <h1>Incendio de {{ object['COMUNIDAD'].decode('UTF-8') }}</h1> <p>En la comunidad {{ object['COMUNIDAD'].decode('UTF-8') }}, provincia {{ object['PROVINCIA'].decode('UTF-8') }}, comarca {{ object['COMARCA'].decode('UTF-8') }}, municipio {{ object['MUNICIPIO'].decode('UTF-8') }} se quemó una superficie forestal de {{ object['SUPQUEMADA'] }}. Hubieron {{ object['MUERTOS'] }} muertos y {{ object['HERIDOS'] }} heridos. Se detectó en la fecha {{ object['FECHA'] }}. Se pudo controlar en {{ object['TIME_CTRL'] }} minutos y extinguir en {{ object['TIME_EXT'] }} minutos. La causa del incendio fue {{ object['CAUSA'].decode('UTF-8') }}. En la extinción del incendio participaron {{ object['PERSONAL'] }} personas, {{ object['PESADOS'] }} vehiculos pesados y {{ object['AEREOS'] }} medios aereos.</p> </body>

¡Hola Javascript!

Ahora vamos a colocar un mapa con los incendios usando una libreria de Javascript llamada Leaflet. Primero hay que importarla en el archivo "index.html"

<head> <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8"> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" /> <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js?2"></script> </head>

Crear un elemento HTML para el mapa

							
								  ... inicio del body ...

									
... aca esta la table ...

Y usar Leaflet para centrarlo en España

<script type="text/javascript"> var map = L.map('map').setView([40.2085,-3.713], 14); var mapquestLayer = new L.TileLayer( 'http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', { maxZoom: 18, attribution: 'Data, imagery and map information provided by <a href="http://open.mapquest.co.uk" target="_blank">MapQuest</a>, <a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors.', subdomains: ['otile1','otile2','otile3','otile4'] }); map.addLayer(mapquestLayer); </script> </body>

Inicializamos el mapa con las coordenadas de España y nivel de zoom

							
								
							
						

Agregamos la capa de tiles desde mapquest, que utiliza open street map.

Se le pasa la URL para las imagenes de tiles, el nivel máximo de zoom (18) y el texto sobre de donde vienen los mapas.

							
								
							
						

Le agregamos el layer al elemento del mapa

							
								
							
						

Transformar los datos del CSV que tenemos a GeoJSON

GeoJSON es un formato para guardar estructuras de datos geograficos junto a información no geografica

							
  
							
						

Agregar una ventanita popup que muestre información sobre el incendio

Sustituir

							
								var dataLayer = L.geoJson(data);
							
						

por

							
					      var dataLayer = L.geoJson(data, {
					          onEachFeature: function(feature, layer) {
					              layer.bindPopup(feature.properties.causa);
					          }
					      });
							
						

Y ahora envolver la superficie por un link al incendio

Sustituir lo anterior por

							
								            var dataLayer = L.geoJson(data, {
                onEachFeature: function(feature, layer) {
                    layer.bindPopup(
                        '' +
                            feature.properties.causa +
                        ''
                    );
                }
            });
							
						

Hacemos lo mismo en "detail.html"

agregamos un mapa del incendio.

							
	
...

¡Hola Internet!

Ahora publicaremos nuestra aplicación de datos en Internet. Vamos a usar Frozen Flask para generar archivos estaticos desde nuestra app.

Frozen Flask

una libreria de Python que crea una página estatica por cada página que hicimos.

Usar pip para instalar Frozen Flask

							
								$ pip install Frozen-Flask
							
						

Crear un archivo freeze.py

en el mismo directorio que app.py

							
		from flask_frozen import Freezer
		from app import app
		freezer = Freezer(app)

		if __name__ == '__main__':
		    freezer.freeze()
							
						

Correrlo desde linea de comandos

Se creará un directorio build con un monton de archivos estaticos.

							
								$ python freeze.py
							
						

Usar el navegador

para abrir uno de los archivos generados en build. Lo único que paso a estaticos fueron las páginas de "index.html". Tenemos que editar freeze.py para incluir "detail.html"

							
								from flask_frozen import Freezer
								from app import app, csv_list
								freezer = Freezer(app)

								@freezer.register_generator
								def detail():
								    for row in csv_list:
								        yield {'number': row['IDPIF']}

								if __name__ == '__main__':
								    freezer.freeze()
							
						

Correrlo desde linea de comandos

Ahora se generan muchos más archivos en build.

							
								$ python freeze.py
							
						

¡Hola GIT!

GitHub Pages hostea páginas estaticas de forma gratuita

  • En Windows: http://windows.github.com
  • En Mac: http://mac.github.com
  • En Linux: apt-get install git

Inicializemos GIT localmente

En linea de comandos

							
								$ git init
								$ git add .
								$ git commit -m "Agregamos todo el proyecto a GIT"
							
						

Creamos cuenta en GitHub

Ir a http://github.com y crear cuenta.

Creamos repositorio en GitHub

Y lo agregamos a nuestro GIT local. Las instrucciones aparecen en la misma pagina web de github.com donde crearon el repositorio.

							
								$ git remote add origin http://github.com/.../.../
							
						

Finalmente publiquemos la app en github-pages

Para esto sólo tenemos que crear un branch gh-pages en nuestro repositorio.

	
	$ git checkout -b gh-pages # Crear el nuevo ramal
	$ git push origin gh-pages # Publicar desde nuevo ramal a GitHub
	
						

Luego de unos minutos tu app estara publicada en

http://tunombredeusuario.github.io/tuapp/build/index.html

Tutoriales y Referencias en linea

  1. Git y GitHub Pro GIT.
  2. Esta presentación en mi primera aplicación de datos
  3. La inspiración para este taller viene del mismo dado por Ben Welsh durante NICAR 2014.
  4. Tutorial de Flask (en ingles)
  5. Documentación sobre Python y Pip
  6. Leaflet
  7. Como hostear paginas en Github Pages

¡Gracias!

@gaba

gaba@datauy.org