Quantcast
Channel: Python Hispano
Viewing all 180 articles
Browse latest View live

Pybonacci: Optimización en Python: CVXOpt

$
0
0

¿Qué es CVXOpt?

CVXOpt es un paquete gratuito que se emplea para la optimización convexa y que está basado en el lenguaje de programación de Python. Su principal propósito es conseguir el desarrollo de software para aplicaciones de optimización convexa mediante la construcción de una librería estándar extensa de Python y empleando las fortalezas de Python como lenguaje de programación de alto nivel.

CVXOpt fue desarrollado inicialmente por Martin Andersen, Joachim Dahl y Lieven Vandenberghe para emplearlo en su propio trabajo, haciéndolo disponible para otras personas.

¿Qué es la optimización convexa?

La optimización convexa es un tipo de programación matemática (programación convexa) en la que se estudia el caso en el que la función objetivo es convexa – minimización – y en la que el conjunto de restricciones del problema es convexa. Este tipo de optimización incluye la programación lineal (el conjunto de las ecuaciones del problema es lineal)

Matemáticamente, el problema se formula de la siguiente manera:

ec

Explicando de una manera más sencilla las ecuaciones anteriores: se tiene una función objetivo que se pretende minimizar (o maximizar, aunque este hecho es una trivialidad, ya que únicamente afecta al cambio de signo de la función objetivo) Dicha función objetivo está sujeta a una serie de restricciones convexas, que pueden ser de desigualdad o igualdad, y que determinan una región factible del problema. Todos los puntos del interior de dicha región constituyen soluciones del problema, pero en optimización se busca el mejor de todos ellos.

En la siguiente figura, se aprecia un ejemplo de lo anterior: los puntos verdes son puntos no factibles, ya que están fuera de la región factible y no cumplen las restricciones del problema. Los puntos amarillos constituyen un conjunto de soluciones del problema que cumplen las restricciones, pero que no son el punto óptimo. En cambio, el punto rojo sí que es el óptimo ya que es el mejor posible en el sentido de la función objetivo, indicado por la flecha negra.

grafo

¿Cómo se instala CVXOpt?

Para instalar CVXOpt se puede acudir a la página web de los desarrolladores del paquete: http://cvxopt.org/install/index.html donde se puede descargar gratuitamente y donde nos indican cómo realizar la instalación del mismo.

Trabajando con CVXOpt

CVXOpt es un paquete de optimización que emplea notación matricial para resolver problemas de optimización. Incluye tanto matrices densas como matrices dispersas (matrices con muchos términos nulos o ceros)

  • Las matrices densas se llaman mediante la función matrix. Los argumentos especifican los valores de los coeficientes, las dimensiones y el tipo de la matriz, siguiendo la siguiente nomenclatura:

cvxopt.matrix(x[,size[,tc]])

  1. size es un tuple (objeto que contiene otros objetos) con las dimensiones de la matriz y, por tanto, tiene longitud dos. El número de filas y/o columnas no puede ser cero.
  2. tc es el tipo de código. Los posibles valores son ‘i’, ‘d’, y ‘z’ para matrices enteras (integer), reales (double) y complejas, respectivamente.
  3. x puede ser un número, una secuencia de números, una matriz densa o dispersa, un vector Numpy de una o dos dimensiones o una lista de matrices y números.

Para mostrar la notación empleada, se muestra el siguiente ejemplo:

>>> from cvxopt import matrix
>>> A = matrix(1, (1,4))
>>> print(A)
[ 1 1 1 1]
>>> A = matrix(1.0, (1,4))
>>> print(A)
[ 1.00e+00 1.00e+00 1.00e+00 1.00e+00]
>>> A = matrix(1+1j)
>>> print(A)
[ 1.00e+00+j1.00e+00]
>>> print(matrix([[1., 2.], [3., 4.], [5., 6.]]))
[ 1.00e+00 3.00e+00 5.00e+00]
[ 2.00e+00 4.00e+00 6.00e+00]
>>> A1 = matrix([1, 2], (2,1))
>>> B1 = matrix([6, 7, 8, 9, 10, 11], (2,3))
>>> B2 = matrix([12, 13, 14, 15, 16, 17], (2,3))
>>> B3 = matrix([18, 19, 20], (1,3))
>>> C = matrix([[A1, 3.0, 4.0, 5.0], [B1, B2, B3]])
>>> print(C)
[ 1.00e+00 6.00e+00 8.00e+00 1.00e+01]
[ 2.00e+00 7.00e+00 9.00e+00 1.10e+01]
[ 3.00e+00 1.20e+01 1.40e+01 1.60e+01]
[ 4.00e+00 1.30e+01 1.50e+01 1.70e+01]
[ 5.00e+00 1.80e+01 1.90e+01 2.00e+01]

  • Las matrices dispersas se llaman mediante el comando spmatrix. Las matrices dispersas se suelen definir mediante tripletes en los que se indica el valor numérico, la posición en la fila y la posición en la columna. A modo de ejemplo, el valor 5 que se encuentra en la primera fila y en la segunda columna se nota como (5, 0, 1) Nótese que la primera fila o columna se indica mediante un cero.

matriz
La llamada al comando spmatrix se hace de la siguiente forma:

cvxcopt.spmatrix(x,I,J[,size[,tc]])

  1. I y J son secuencias de números enteros o matrices enteras que contienen los índices de las filas y las columnas de las entradas no cero. La longitud de I y J debe ser igual.
  2. size es un tuple de enteros no negativos con filas y columnas de las dimensiones de la matriz. Este argumento es únicamente necesario cuando se crea una matriz con una fila o columna con todos sus valores igual a cero.
  3. tc es tipo de código, ‘d’ o‘z’ para matrices dobles o complejas, respectivamente.
  4. x puede ser un número, una secuencia de números o una matriz densa.

A continuación, se muestra cómo se escribe la notación para escribir estas matrices:

>>> from cvxopt import spmatrix
>>> A = spmatrix(1.0, range(4), range(4))
>>> print(A)
[ 1.00e+00 0 0 0 ]
[ 0 1.00e+00 0 0 ]
[ 0 0 1.00e+00 0 ]
[ 0 0 0 1.00e+00]
>>> A = spmatrix([2,-1,2,-2,1,4,3], [1,2,0,2,3,2,0], [0,0,1,1,2,3,4])
>>> print(A)
[ 0 2.00e+00 0 0 3.00e+00]
[ 2.00e+00 0 0 0 0 ]
[-1.00e+00 -2.00e+00 0 4.00e+00 0 ]
[ 0 0 1.00e+00 0 0 ]

Hay que reseñar que existen más formas para definir las matrices y muchas operaciones aritméticas que se realizan en el paquete CVXOpt. Para tener más información de las mismas, se recomienda visitar el siguiente enlace: http://cvxopt.org/userguide/matrices.html

Para resolver problemas de optimización CVXOpt llama a una serie de solvers siendo algunos muy generales como cvxopt.umfpack o cvxopt.cholmod que resuelven ecuaciones lineales agrupadas en matrices del tipo AX = B.

En cualquier caso, por lo general, es mejor opción emplear algún solver más potente, como ocurre con cvxopt.solvers, dentro de los cuales existen diferentes opciones de solvers, siendo lp– para programación lineal – y qp– para programación cuadrática – los principales (aunque en función de cómo sea el programa, sería conveniente emplear otro de los disponibles)

Programación lineal con CVXOpt

La programación lineal supone el caso más común de la programación y, por ello, nos detenemos en cómo se lleva a cabo con CVXOpt. Como se ha mencionado anteriormente, el comando cvxopt.solvers.lp es el mejor para realizar programación de este tipo. La llamada al mismo se hace de la siguiente manera:

cvxopt.solvers.lp(c, G, h[, A, b[, solver[, primalstart[, dualstart]]]])

Esta sentencia nos va a permitir resolver tanto el problema principal – o primal  - y el problema secundario – o dual  - relacionado con el principal.

prim   

El argumento solver se puede dejar en blanco – con lo que el programa emplearía conelp por defecto – o bien emplear algún solver instalado externamente a este paquete, como puede ser GLPK o MOSEK. A modo de ejemplo, se muestra la siguiente notación para el LP siguiente:

>>> from cvxopt import matrix, solvers
>>> c = matrix([-4., -5.])
>>> G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]])
>>> h = matrix([3., 3., 0., 0.])
>>> sol = solvers.lp(c, G, h)
>>> print(sol['x'])
[ 1.00e+00]
[ 1.00e+00]

Optimización en CVXOpt

En los casos en los que se tiene una función objetivo y una serie de restricciones en las que es complicado modificar el problema – principalmente, la modificación de las desigualdades – es posible realizar un modelado del problema, especificando la función objetivo, las restricciones y las variables del mismo. Para ello, se puede llamar a la siguiente función:

cvxopt.modeling.op([objective[,constraints[,name]]])

Por defecto, se va a minimizar la función objetivo, que se puede definir aparte o en esa misma línea. Constraints hace referencia a las restricciones y puede ser tanto una restricción como una lista de restricciones. Finalmente, name indica el nombre del problema.

Por lo general, en un problema de modelado, es conveniente incluir los siguientes atributos:

  • objective– Función objetivo, en muchas ocasiones relacionada con el coste.
  • variables()– Devuelve una lista con las variables del problema
  • constraints()– Devuelve una lista de restricciones
  • inequalities()– Devuelve una lista de restricciones de desigualdad
  • equalities()– Devuelve una lista de restricciones de igualdad
  • solve([format[,solver]])– esta función convierte el problema de optimización en un programa lineal en forma matricial y lo resuelve empleando el solver de la programación lineal.

Como ejemplo, se puede resolver el sistema lineal siguiente empleando dos notaciones distintas, la primera modelizando el problema con las ecuaciones independientes y la segunda agrupándolas en una única matriz:

>>> from cvxopt.modeling import op
>>> x = variable()
>>> y = variable()
>>> c1 = ( 2*x+y >> c2 = ( x+2*y >> c3 = ( x >= 0 )
>>> c4 = ( y >= 0 )
>>> lp1 = op(-4*x-5*y, [c1,c2,c3,c4])
>>> lp1.solve()
>>> lp1.status
'optimal'
>>> print(lp1.objective.value())
[-9.00e+00]
>>> print(x.value)
[ 1.00e+00]
>>> print(y.value)
[ 1.00e+00]
>>> print(c1.multiplier.value)
[ 1.00e+00]
>>> print(c2.multiplier.value)
[ 2.00e+00]
>>> print(c3.multiplier.value)
[ 2.87e-08]
>>> print(c4.multiplier.value)
[ 2.80e-08]
>>> from cvxopt.modeling import op, dot
>>> x = variable(2)
>>> A = matrix([[2.,1.,-1.,0.], [1.,2.,0.,-1.]])
>>> b = matrix([3.,3.,0.,0.])
>>> c = matrix([-4.,-5.])
>>> ineq = ( A*x >> lp2 = op(dot(c,x), ineq)
>>> lp2.solve()
>>> print(lp2.objective.value())
[-9.00e+00]
>>> print(x.value)
[ 1.00e+00]
[ 1.00e+00]
>>> print(ineq.multiplier.value)
[1.00e+00]
[2.00e+00]
[2.87e-08]
[2.80e-08]

En definitiva, dentro de Python nos encontramos con una serie de paquetes de optimización (en este artículo hemos visto CVXOpt, aunque existen más como Pyomo) que nos permiten realizar problemas de optimización más o menos complejos con resultados totalmente satisfactorios y que nos pueden servir tanto a nivel académico como a nivel profesional.

Jorge M. Bernabé Ruiz (@Jorge_Poti) de @CAChemEorg.


Archivado en: Básico, Optimización

python majibu: como pasar aplicación en wxpython a exe?

$
0
0

buenas tardes! les comento, hice una aplicación con Boa, que usa wxPython y MySQL lo intente pasar a ejecutable con el script:

1
2
3
4
5
# -*- coding: utf-8 -*-fromdistutils.coreimportsetupimportpy2exesetup(console=['AplicacionFinal\Gestion_Proyecto.py'])

El archivo Gestion_Proyecto es asi:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env python#Boa:App:BoaAppimportwximportMenumodules={u'Consulta':[0,'',u'Consulta.py'],u'Gestor_Altas':[0,'',u'Gestor_Altas.py'],u'Menu':[1,'Main frame of Application',u'Menu.py'],u'Modificar':[0,'',u'Modificar.py']}classBoaApp(wx.App):defOnInit(self):self.main=Menu.create(None)self.main.Show()self.SetTopWindow(self.main)returnTruedefmain():application=BoaApp(0)application.MainLoop()if__name__=='__main__':main()

El problema es que cuando lo ejecuto simplemente se cierra y no pasa nada. Lo estoy haciendo bien o se hace de otra forma? cual puede ser el error? muchisimas gracias!

python majibu: Extracción de texto plano de una web con Python. ¿Cómo?

$
0
0

Hola a todos:

Llevo un tiempo intentando encontrar la forma de poder bajar una pagina web desde un programa, con wget es bastante fácil y con las librerías urllib también se puede conseguir en Python pero no encuentro la forma de conseguir que sólo se baje el texto de la página.

En síntesis, mi objetivo es conseguir un pequeño programa al que poder pasarle una url y que me devuelva todo el texto que esa página contiene, como si nos fuéramos al navegado e hiciéramos: botón derecho, seleccionar todo, copiar.

También he estado probando con los navegadores por terminal pero en algunos foros, blogs y periódicos digitales no muestra el contenido de forma correcta.

Alguien sabe como poder realizar esto en Python? Seguro que hay algo que esto pasando por algo. Agredecería cualquier aporte.

Un saludo enorme y gracias a todos !

python majibu: Error TemplateDoesNotExist en Django

$
0
0

Hola amigos tengo este problema con django 1.5 y es que básicamente he creado una vista en la cual hago referencia al template index.html que se encuentra ubicado en templates/inicio/index.html donde templates es la carpeta que he añadido para guardar todos mis archivos html, esta definida en settings de la siguiente manera:

1
2
3
4
5
6
importosRUTA_PROYECTO=os.path.normpath(os.path.dirname(__file__))# Django identifica esta carpeta para guardar todos los templatesSTATICFILES_DIRS=(os.path.join(RUTA_PROYECTO,'templates'),)

y en views.py la llamo de esta forma:

1
2
3
4
fromdjango.shortcutsimportrender_to_responsedefindex(request):returnrender_to_response('inicio/index.html')

Al ver mi sitio me sale el siguiente TraceBack:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Traceback:File"/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py"inget_response115.response=callback(request,*callback_args,**callback_kwargs)File"/home/jorge/sites/BibliotecaVirtual/apps/inicio/views.py"inindex5.returnrender_to_response('inicio/index.html')File"/usr/local/lib/python2.7/dist-packages/django/shortcuts/__init__.py"inrender_to_response29.returnHttpResponse(loader.render_to_string(*args,**kwargs),**httpresponse_kwargs)File"/usr/local/lib/python2.7/dist-packages/django/template/loader.py"inrender_to_string170.t=get_template(template_name)File"/usr/local/lib/python2.7/dist-packages/django/template/loader.py"inget_template146.template,origin=find_template(template_name)File"/usr/local/lib/python2.7/dist-packages/django/template/loader.py"infind_template139.raiseTemplateDoesNotExist(name)ExceptionType:TemplateDoesNotExistat/ExceptionValue:inicio/index.html

Al parecer no encuentra el template y por lo tanto asume que no existe pero no creo haberme equivocado escribiendo la ubicación :S, les agradezco su ayuda amigos.

python majibu: Cual es la forma correcta para realizar el bloqueo de tablas o registros

$
0
0

Hola

Señores estoy interesado en saber cual es la forma correcta para bloquear tablas o registros al momento de realizar una actualización o si existe una función que se pueda aplicar.

Gracias

Saludos

Antonio Samper

python majibu: ¿ Cuales herramientas aconsejais para imprimr reportes ?

$
0
0

Trabajo en Windows. Soy nuevo en Python y no veo muy claro como atacar el tema reportes, listados, documentos,etc. ¿ Qué herramientas de diseño visuales existen para python tipo Crystal Reports, Jasper...?

Gracias

python majibu: Plantilla excel

$
0
0

Un saludo,

tengo una pregunta:

como puedo utilizar un documento de exel como plantilla para generar reportes desde una base de datos...?

Gracias por responder

python majibu: TypeError: 'NoneType' object is not iterable

$
0
0

Muy buen día a todos, antes que nada, gracias por leer mi pregunta, espero me puedan ayudar.

Tengo este programa, que es mínimo lo que hace, apenas lo estoy empezando y no se mucho sobre Python.

Proyecto.py

1
2
3
4
5
6
7
8
9
defleer_codigo():codigo=raw_input("Ingrese su codigo: ")ifobtener_tipo_de_dato(codigo)==int:codigo=int(codigo)returnTrue,codigoelse:print"Por favor ingrese un código válido."leer_codigo()

def obtener_tipo_de_dato(dato):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
ifdato.isdigit():returnintelifdato.isalpha():returnstrelse:try:dato=float(dato)returnfloatexceptValueError:returnFalsereturnfloat

def main():

1
2
bandera,entero=leer_codigo()printbandera,entero

if name == 'main': main()

Aquí el problema...

Cuando escribo directamente un número válido, no hay problema, pero cuando provoco algún error, pues se rompe, y creo que no debería de pasar.

https://www.dropbox.com/s/eqo0ui5jhx9neer/1.png

Esta sin problemas, pero las 2 que vienen aparece el error.

https://www.dropbox.com/s/1sc5qav1r94ap3u/2.png

https://www.dropbox.com/s/ty50lvn57x68nm6/3.png

Al parecer falla en el return, no entiendo por que.

De ante mano, Gracias.


Pybonacci: Meme Python de Año Nuevo 2014

$
0
0

¡Feliz año a todo el mundo! Hoy queremos celebrar que ha empezado el 2014 ¡con nuestro artículo número 100! :D Para ello y como es costumbre desde el año pasado vamos con el Meme Python de Año Nuevo de Tarek Ziadé.

1. ¿Cuál es la aplicación, framework o biblioteca Python más interesante que has descubierto en el 2013?

He seguido utilizando mucho el notebook de IPython, y Anaconda me ha facilitado mucho la vida cuando me las he tenido que ver en Windows. La biblioteca que más me ha gustado usar ha sido pytest, porque hace escribir tests y medir cobertura de código extremadamente sencillo.

2. ¿Qué nueva técnica de programación aprendiste en el 2013?

Progresé bastante con el desarrollo dirigido por tests (puedes leer cómo fue mi primera auditoría de código) y utilicé por primera vez un servidor de integración continua, Travis CI, para mi paquete poliastro. Este servidor corre todos los tests de tu paquete bajo diversas configuraciones (diferentes versiones de Python, por ejemplo), con lo cual es una herramienta perfecta para integrar pull requests y para comprobar que tu código funciona en plataformas a las que no puedes acceder. ¡Simplemente genial!

3. ¿A qué proyecto de software libre contribuiste más en el 2013? ¿Qué hiciste?

Este año fui tomando más confianza a la hora de contribuir código a los proyectos que más uso. Concretamente, entre julio y septiembre trabajé un poco en el módulo signal de SciPy, en la parte de sistemas LTI (estaba ya pensando en escribir un artículo sobre teoría de control en Python). También reescribí odeint desde cero en Fortran 90 utilizando f2py, pero por desgracia hice algunos cambios que rompían la compatibilidad hacia atrás y compilar Fortran 90 en Windows es mucho más difícil de lo que parecía así que de momento se ha quedado ahí.

También trabajé bastante en poliastro, una biblioteca para mecánica orbital en Python. Ahora mismo estaba reescribiéndola para deshacerme del código Fortran existente (y así simplificar la instalación) y que tuviera una API más atractiva, pero está siendo más difícil de lo esperado y el tiempo de los exámenes se acerca :)

4. ¿Qué blog o web sobre Python leíste más en el 2013?

Un año más, la web sobre Python que más he leído es la propia documentación de NumPy y SciPy. Estoy en un proceso de aprendizaje constante y me hace mucha falta para ir solucionando las dudas que me surgen. Sigo echando de menos más blogs sobre Python en español, aunque muy pronto vamos a relanzar el planet de Python Hispano y vamos a recolectar unos cuantos :) Este año descubrí CAChemE y a menudo escriben sobre Python. ¡No les perdáis de vista!

He leído también mucho código ajeno, especialmente de SymPy y Astropy, en GitHub. Son una excelente fuente de inspiración.

5. ¿Cuáles son las tres cosas que más te gustaría aprender en el 2014?

  • Computación paralela
  • Aprendizaje automático (machine learning)
  • Creación de interfaces gráficas con Python (la mantengo desde el meme anterior :P)

6. ¿Cuál es el programa, aplicación o biblioteca que más te gustaría que alguien escribiera en 2014?

No sabría cuál elegir entre una wiki en Python decente (no considero MoinMoin decente en casi ningún sentido) o un motor de blogs tipo WordPress en Python (no considero que haya ninguno que se le acerque). O un editor WYSIWYG web para reStructuredText. O algo tipo wxWidgets pero que no sea ultra complicado de instalar y cuya web no parezca hecha a principios de los ’90 :)


Recuerda, las reglas del meme son:

  1. Copia y responde las preguntas en tu blog.
  2. Si tienes tuiter, anúncialo en el hashtag #2014pythonmeme

¡Anímate! Un saludo :D


Archivado en: Básico

python majibu: ¿como ejecutar un programa desde otro programa en python?

$
0
0

Hola buenos dias,

Lo que yo quiero hacer es diseñar una interfaz,en la que al darle a un boton ejecute un programa.

¿alguien podría ayudarme?

python majibu: ¿como ejecutar un programa desde otro ptograma en python?

$
0
0

Hola buenos dias,

Lo que yo quiero hacer es diseñar una interfaz,en la que al darle a un boton ejecute un programa.

¿alguien podría ayudarme?

python majibu: problema con logout en django en produccion

$
0
0

Hola como les va, les cuento mi problema, en mi servidor de desarrollo tengo una aplicacion que funciona correctamente, pero en produccion el logout no me funciona.

la funcion de logout la tengo asi

@login_required(login_url='/')
def salir(request):
    logout(request)
    return HttpResponseRedirect('/')

y para chequear si esta o no logueado el usuario lo hago con la siguiente instruccion
if request.user.is_anonymous():

el tema es que el usuario siempre queda registrado o sea que cuando llamo a la funcion salir no se ejecuta el logout.

alguna idea de que pueda estar pasando?

Saludos

python majibu: Iterar sobre lista de n nivel?

$
0
0

Tengo este codigo y el resultado subsiguiente, tengo un problema, no entiendo como iterar sobre cada elemento de cada bloque.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
n=30izq=nder=n+1blocksize=n+2pos=0hashblock=[None]*blocksizeforiinrange(n):pos+=1hashblock[i]=abs(hash(i))ifpos==n:pos=0newblock=[None]*blocksizehashblock[der]=newblocknewblock[izq]=hashblockhashblock=newblock#>>> hashblock#[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, None, [...]], [...]], [...]], None]

Hyperreals *R: Clausuras en python – Parte 1

$
0
0

Funciones Lambda

Antes de ver qué son las clausuras (closures), veamos qué tienen las funciones lambda que las hacen tan polémicas algunas veces.

Comencemos con un ejemplo. Te recomiendo que te esfuerces en deducir cómo funciona sin ir a probar cómo funciona. A continuación te pondré algunos valores para que elijas los valores de las tres listas:

    i=1
    add_one=lambda x:x+i
   
    lista1=[add_one(i)for i in[0,1,2]]

    i=0
    lista2=[add_one(i)for i in[0,1,2]]

    i=2
    lista3=[add_one(i+1)for i in[0,1,2]]

Valores para lista1:

  1. [0,1,2]
  2. [1,2,3]
  3. [0,2,4]
  4. [1,3,5]

Valores para lista2:

  1. [0,1,2]
  2. [1,2,3]
  3. [0,2,4]
  4. [1,3,5]

Valores para lista3:

  1. [0,1,2]
  2. [1,2,3]
  3. [2,3,4]
  4. [1,3,5]

Las soluciones están al final del artículo1, pero puedes probarlo ahora para que lo veas tú mismo.

¿Qué es lo que ha pasado?

Contrariamente a lo que estamos acostrumbrados con las funciones normales, la evaluación de una función lambda se hace dentro del entorno donde se ejecuta, independiente del entorno donde se ha definido. Así pués, en la función lambdalambda x:x+i, la variable i toma el valor de esta variable en el momento de evaluar la función. Como se usa esta variable para la compresión de la lista, irá cambiando de valor a medida que se recorre la lista [0,1,2], por lo que la expresión add_one(i) termina convirtiéndose en la expresión i+i, y la expresión add_one(i+1) en i+1+i.

Tiene un funcionamiento similar a los macros, donde se sustituye literalmente la llamada a la función por la expresión equivalente. En python3, se hace más evidente al denominarse expresiones lambda en lugar de funciones lambda.

Clausuras

En una función podemos distinguir dos partes:

  • Código ejecutable
  • Entorno de evaluación, más conocido por Ámbito o Scope

Antes de ejecutar el código de la función, se aumenta el entorno de evaluación con los argumentos de entrada de la función.

Según en qué entorno se evalua la función, tenemos dos ámbitos:

  • Clausura, también llamado Ámbito léxico o Ámbito Estático, cuando la función se evalua en el entorno donde se ha definido.
  • Ámbito dinámico cuando se evalua en el entorno donde se invoca la función.

Con esta definición, podemos afirmar que en python las funciones tienen ámbito léxico, con excepción de las funciones lambda que tienen ámbito dinámico.

No voy a considerar las ventajas de uno u otro tipo. Por lo general, las clausuras se consideran mejores para desacoplar el código de la función del código donde se invoca, lo que ayuda mucho al mantenimiento y corrección de errores. Es por ello la manera normal de crear funciones en la mayoría de lenguajes de programación.

¿Cómo hacer que una función lambda se comporte como si tuviera clausura?

La forma de hacer que un función lambda se evalue en el entorno donde se define consiste en pasar las variables de ese entorno que necesite en los argumentos de entrada, casi siempre como argumentos por defecto.

En el ejemplo anterior sería:

    i=1
    add_one=lambda x,i=i:x+i

que equivaldrá a

    add_one=lambda x,i=1:x+i

En este caso i se toma de los argumentos de la función, y tendrá por defecto el valor de i en el momento de la definición de la función lambda.

No es perfecto, pero es lo mejor que tenemos. Lo recomendable es evitar las funciones lambda complejas si no queremos llevarnos algunas sorpresas.


  1. Los valores de las listas son las opciones 3, 3 y 4, respectivamente. 

Pybonacci: ¿Cómo borrar por encima de una línea en matplotlib?

$
0
0

Inauguramos sección nueva en el 2014 con las preguntas que nos llegan de nuestros lectores por las redes sociales o el correo electrónico :) Nos llegan unas cuantas, ¡así que tenemos material para al menos una pregunta semanal! Estas serán entradas breves que publicaremos cada martes y que tratarán de responder vuestras dudas sin rodeos. ¡Si queréis mandar las vuestras no dudéis en contactar con nosotros!

Empezamos con Alberto, que me comenta:

¿Cómo puedo «borrar» lo que tengo por encima de una línea en matplotlib? He intentado con fill_between entre la línea de estabilidad funcional (línea roja) pero solo rellena con color, no sobreescribe que es lo que pretendo. ¿Se te ocurre alguna forma?

Mapa compresor - Primera versión

Alberto está escribiendo un programa para dibujar mapas de actuaciones de turbomáquinas en Python, similares a los que producen programas privativos como GSP (ejemplos) o GasTurb (ejemplos). En esos mapas aparece la línea de estabilidad funcional (surge line o stall line) por encima de la cual la turbomáquina no puede funcionar. Es preciso, por tanto, borrar todo lo que quede por encima de ella para suprimir información innecesaria del gráfico. El código es un poco complicado, así que voy a comentar solo los conceptos fundamentales.

Lo primero que hice (después de admitir que no tenía ni idea) fue intentar trabajar sobre lo que ya había intentado. Efectivamente, si usas la función fill_between el relleno se queda «por debajo» de las líneas que ya había, en lugar de taparlas. Consultando la documentación de fill_between vi que admitía un parámetro zorder, que controla la visibilidad de los elementos de la gráfica: por defecto vale 0, y cuanto mayor es más arriba aparece el elemento. Usando un valor lo suficientemente alto se llega a este resultado:

Mapa compresor - Segunda versión

Que es más o menos lo que se pretendía… pero en mi ordenador se vio el detalle fatal: el color de fondo y la rejilla quedan tapados. Esta solución no es suficiente.

A continuación me puse a pensar en si habría alguna manera de calcular la intersección de esas líneas con matplotlib. Ya Kiko escribió un artículo que utilizaba Shapely para calcular intersecciones entre formas geométricas, así que tenía un punto de partida, pero introducir Shapely para resolver algo tan aparentemente simple no me gustaba.

Otra opción era crear funciones interpolantes usando SciPy y calcular intersecciones entre funciones usando cualquiera de los métodos de optimización disponibles. El problema es que las curvas negras de la figura, que se obtienen con la función contour, no se pueden trasformar en una función tan fácilmente y eso me causaría problemas.

Estaba ya desempolvando mi ejemplar de «Computational Geometry: Algorithms and Applications» cuando se me ocurrió que tal vez matplotlib tuviese el concepto de máscaras, es decir, poder utilizar una forma geométrica para enmascarar otra, de la misma forma que usamos máscaras en arrays de NumPy. Y efectivamente, después de un rato buscando en Google encontré justo lo que buscaba: el método set_clip_path.

La palabra clave aquí era clip, que en inglés quiere decir algo así como «recortar»: hay que pasarle al método la forma que queremos usar para recortar la línea. En este caso, podemos extraer el área que resulta de fill_between (hacia abajo esta vez).

Si queremos además incluir etiquetas para las curvas de nivel, podemos definir manualmente su posición para que no queden fuera de la máscara. Esto se hace con el parámetro manual de la función clabel.

El código quedaría así:

from matplotlib.patches import PathPatch

# Relleno desde la línea hacia abajo
fillb = plt.fill_between(surge_line_x, surge_line_y, color='none')
# Extraemos el Path
path, = fillb.get_paths()
# Lo convertimos en un Patch
mask = PathPatch(path, fc='none')
# Y lo añadimos a la figura
plt.gca().add_patch(mask)

# Lo aplicamos a las curvas de nivel
cs = plt.contour(cx, cy, cz, colors="black")
for contour in cs.collections:
    cs.set_clip_path(mask)

# Posicionamos las etiquetas
labels_xy = [(10.8, 2.0), (12.4, 2.7), (12.4, 3.3)]
plt.clabel(cs, fmt='%1.2f', manual=labels_xy)

# Y aplicamos la máscara a las líneas normales
ll, = plt.plot(lx, ly, color="blue")
ll.set_clip_path(mask)

Y este sería el resultado:

Mapa compresor - Final

¡Ahora sí! :)

¡Y hasta aquí la pregunta de la semana! ¿Qué te ha parecido el método para llegar a la solución? ¿Se te ocurre una manera mejor? ¿Crees que te será útil para algo que estás haciendo ahora mismo? ¡Cuéntanos en los comentarios! Y si quieres mandarnos tu pregunta, ya sabes dónde estamos ;)


Archivado en: Preguntas Tagged: clip, matplotlib, python

python majibu: acceder a tuplas dentro de diccionarios

$
0
0

Hola a todos!!, tengo una pregunta, espero me puedan ayudar...

Como saben, en Python no existe la sentencia switch - case, por lo tanto una manera de solucionarlo es emulandolo con un diccionario, por ejemplo:

Simulación de sentencia switch(case) en python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
defCero():print'Cero'defUno():print'Uno'defDos():print'Dos'Switch={0:Cero,1:Uno,2:Dos,}Num=1Switch[Num]()

Ok, funciona sin problemas, pero que tal si necesito correr 2 o mas funciones a la vez...

1
2
3
4
5
Switch={0:Cero,1:(Uno,Dos)}Switch[Num]()# No funciona!!

TypeError Traceback (most recent call last)

/media/datos/home/centos/roberto/<ipython console=""> in <module>()

TypeError: 'tuple' object is not callable

1
Switch[Num[0]]()# No funciona!!

TypeError Traceback (most recent call last)

/media/datos/home/centos/roberto/<ipython console=""> in <module>()

TypeError: 'int' object is unsubscriptable

Me doy cuenta de que es una tupla dentro de un diccionario, por lo tanto, ¿Se puede acceder a los datos de la tupla dentro del diccionario, de tal forma que se pueda simular el switch(case)?

Si no se puede, entiendo que debe de hacerse con if, elif, else, pero me gustaría saber si se puede de la forma que propongo...

De antemano, Gracias.

Edición: Me acabo de dar cuenta que puedo acceder al índice uno del diccionario, pero sólo ejecuta la última función, por lo que la pregunta sigue vigente.

1
2
3
4
5
6
7
In[136]:SwitchOut[136]:{0:<functionCeroat0x7f5f855d31b8>,1:(<functionUnoat0x7f5f855d37d0>,<functionDosat0x7f5f855d3140>)}In[137]:Switch[Num][1]()Dos

La libertad de desarrollar...: Jugando con RSS del blog desde Python

$
0
0

Feliz año a todos.
Tenía algo de tiempo sin escribir en el blog.
Este artículo trata del como usar la librería Feedparser para extraer información del RSS de este blog.

Al final del blog (blog.crespo.org.ve) aparece la suscripción al Blog por medio de Atom (ver imagen):


Al darle clip al enlace aparece lo siguiente (http://feeds.feedburner.com/LaLibertadDeDesarrollarNoTienePrecio):


El blog está sindicalizado desde FeedBurner.

La idea es utilizar la librería feedparser para extraer información de la sindicalización del blog.

Se importa la librería feedparser:
>>>import feedparser

Se instancia la clase parse con el url  de la sindicalización del blog:
>>>d = feedparser.parse('http://feeds.feedburner.com/LaLibertadDeDesarrollarNoTienePrecio')

Se muestra el título del blog:
>>> d['feed']['title']

u'La libertad de desarrollar no tiene  precio...'

Otra forma de obtener el título del blog:
>>> d.feed.title

u'La libertad de desarrollar no tiene  precio...'

Enlace del blog:
>>> d.feed.link

u'http://blog.crespo.org.ve/'

Descripción del blog:
>>> d.feed.description

u'Blog dedicado al Software Libre en especial Linux Debian, Android y FreeBSD, a la programaci\xf3n en python con gtk, qt y en Android.'

Elementos del diccionario:
>>> d.keys()

['feed', 'status', 'updated', 'updated_parsed', 'encoding', 'bozo', 'headers', 'etag', 'href', 'version', 'entries', 'namespaces']

Para obtener el author del blog, se ejecuta author en feed:
>>> d.feed.author

u'Ernesto Crespo (noreply@blogger.com)'

La codificación del texto del blog es UTF-8:
>>> d.encoding

u'UTF-8'

Estatus:
>>> d.status

200

Actualización:
>>> d.updated

'Sun, 19 Jan 2014 00:03:47 GMT'

En este caso devuelve la hora pero la información separada:
>>> d.updated_parsed

time.struct_time(tm_year=2014, tm_mon=1, tm_mday=19, tm_hour=0, tm_min=3, tm_sec=47, tm_wday=6, tm_yday=19, tm_isdst=0)

Encabezados del blog:
>>> d.headers

{'alternate-protocol': '80:quic', 'x-xss-protection': '1; mode=block', 'x-content-type-options': 'nosniff', 'expires': 'Sun, 19 Jan 2014 01:01:50 GMT', 'server': 'GSE', 'last-modified': 'Sun, 19 Jan 2014 00:03:47 GMT', 'connection': 'close', 'etag': 'hSh9ZbFEawbSc3BqlNVkqha27os', 'cache-control': 'private, max-age=0', 'date': 'Sun, 19 Jan 2014 01:01:50 GMT', 'content-type': 'text/xml; charset=UTF-8'}

Enlace:
>>> d.href

u'http://feeds.feedburner.com/LaLibertadDeDesarrollarNoTienePrecio'

Tipo de RSS (Atom1.0):
>>> d.version

u'atom10'


Cantidad de entradas:
>>> len(d.entries)

25

Si se desea obtener el título de la última entrada en el blog:
>>> d.entries[0].title

u'Webscraping con Python Mechanize y BeautifulSoup4'

Si se desea ver el contenido de la última entrada ( en html) :
>>> d.entries[0]

.....

'guidislink': True, 'published': u'2013-10-29T03:30:00.000-04:30', u'thr_total': u'0'}

Devuelve un diccionario con dentro código html  e información adicional.

Para obtener el link del último artículo:
>>> d.entries[0].link

u'http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/A9jUi9ATI2g/webscraping-con-python-mechanize-y.html'

La fecha de publicación del último artículo:
>>> d.entries[0].published

u'2013-10-29T03:30:00.000-04:30'

El id del último artículo:
>>> d.entries[0].id

u'tag:blogger.com,1999:blog-882744969176160062.post-8013337259867824164'

Si se desea listar los últimos 25 artículos con su título y enlace se ejecuta un ciclo:
>>> for post in d.entries:

...     print post.title + ": " + post.link + "\n"

... 

Webscraping con Python Mechanize y BeautifulSoup4: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/A9jUi9ATI2g/webscraping-con-python-mechanize-y.html



Extracción de datos con Scraperwiki y Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/UbQD5y9jbr0/extraccion-de-datos-con-scraperwiki-y.html



Extracción de datos de página web con pyquery y Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/1QbC7CmSqpk/extraccion-de-datos-de-pagina-web-con.html



Extracción de datos de páginas web con Scrapemark y Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/g2iUGraxW0M/extraccion-de-datos-de-paginas-web-con.html



Extracción de datos en páginas web con Webscraping y Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/W9NyMTnRYok/extraccion-de-datos-en-paginas-web-con.html



Webscraping o extracción de datos de páginas web con BeautifulSoup4 y Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/xFr0x9bSo7E/webscraping-o-extraccion-de-datos-de.html



Un introducción a Beautiful Soup 4 en Python.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/_7MGtsSCnPg/un-introduccion-beautiful-soup-4-en.html



Obtener información de metadatos EXIF de una imagen con Python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/8U6SjV9RS-w/obtener-informacion-de-metadatos-exif.html



Mostrar tweets en tiempo real con twython y el API Stream de Twitter: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/jdMIKN04gDs/mostrar-tweets-en-tiempo-real-con.html



Descrubiendo Trending Topics de Twitter con twython y python: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/hfKN5Cat5Hw/descrubiendo-trending-topics-de-twitter.html



Probando la librería twython para twitter: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/qfv-BUMniFA/probando-la-libreria-twython-para.html



Manejo de sesión en el ORM sqlalchemy: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/OjR1D7SxjGQ/manejo-de-sesion-en-el-orm-sqlalchemy.html



Bajar vídeos de youtube desde Python con Pafy.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/IV42QCqWZA8/bajar-videos-de-youtube-desde-python.html



Día Debian en Barquisimeto: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/fK8Q4DtjW8c/dia-debian-en-barquisimeto.html



Nodos más influenyes en un grafo con networkx. Parte 4.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/knGC3Agy03M/nodos-mas-influenyes-en-un-grafo-con.html



Mejorar la privacidad en celulares y tabletas con Android: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/WHiecOQggP4/mejorar-la-privacidad-en-celulares-y.html



Graficar la tangente de una curva con python, numpy y pylab.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/YB9pcnkSjPg/graficar-la-tangente-de-una-curva-con.html



Utilizando el API de Stream de Twitter con Python y tweetstream. Parte 1.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/4XndFuAR-wQ/utilizando-el-api-de-stream-de-twitter.html



Máquinas virtuales con kvm y qemu: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/hBovEziYwnM/maquinas-virtuales-con-kvm-y-qemu.html



Descubriendo trending topics de twitter con python-twitter.: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/kAqQ7BRC_4w/descubriendo-trending-topics-de-twitter.html



Descubrir equipos en una Red Local con Python (ipcalc y scapy).: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/KSulfIHpfaA/descubrir-equipos-en-una-red-local-con.html



Resolución de sistemas de ecuaciones lineales por descomposión QR usando Numpy: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/KJ6mmAemwzk/resolucion-de-sistemas-de-ecuaciones.html



Creación de gráfico de burbujas con matplotlib: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/Lu7ps2Z-zQI/creacion-de-grafico-de-burbujas-con.html



Manejar información de un archivo csv con csvkit: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/6opCWEx9RoU/manejar-informacion-de-un-archivo-csv.html



Teorema de muestreo explicado con numpy: http://feedproxy.google.com/~r/LaLibertadDeDesarrollarNoTienePrecio/~3/VoY_nZzRtwY/teorema-de-muestreo-explicado-con-numpy.html

De está forma se puede acceder con python al RSS de blogs.
En próximo artículo se buscará recortar los urls desde python.

Pybonacci: Leer datos de Arduino desde Python

$
0
0

Introducción

En este artículo vamos a ver cómo leer datos procedentes de una plataforma Arduino con Python. Para quienes no lo conozcáis, Arduino es una plataforma de hardware libre concebida para crear prototipos de manera rápida y fácil usando componentes electrónicos. Gracias a Arduino vamos a alejarnos un poco de lo que solemos ver en este blog, que es solo software, y vamos a poder interactuar con el mundo real de una manera más directa.

Arduino Uno

Este artículo nace gracias a mi reciente incorporación a Aerobot, el club de robótica de mi escuela, donde iré explorando las posibilidades de Arduino y Python :)

En esta entrada se han usado python 3.3.3, numpy 1.8.0, pyserial 2.7 y matplotlib 1.3.1.

Prefacio: ¿cómo funciona?

En este artículo no vamos a ver en detalle qué es Arduino o el lenguaje con el que se programa. Para ello os remito a gente que sabe mucho más que nosotros: al final del artículo incluyo unos enlaces que os pueden interesar si queréis profundizar en este tema. Sin embargo, sí que vamos a explicar brevemente cómo es el proceso de escribir un programa para Arduino, por razones que en seguida veremos.

Tal y como se detalla en la documentación, el proceso de compilación en Arduino funciona a grandes rasgos de la siguiente manera:

  1. Se escribe un programa (sketch) en el IDE de Arduino en C o C++.
  2. El IDE comprueba que la sintaxis es correcta y añade #include "Arduino.h" y una función main() propia de la placa.
  3. El programa se compila con avr-gcc y se manda el binario a la placa.
  4. Una vez Arduino tiene el programa y mientras esté alimentado, el programa se ejecutará, normalmente de manera indefinida.

Esta explicación viene para aclarar que, al menos en este artículo, no vamos a programar nuestra placa en Python. Por el proceso que hemos visto, las únicas maneras de hacer esto serían:

Con el segundo método no tenemos disponibles todas las funciones de Arduino, de modo que solo sirve para prototipar programas. Hoy me voy a olvidar de esto y voy a usar Arduino para programar la placa y Python para obtener los datos.

En esta entrada se han usado python 3.3.3, pyserial 2.7.

Comunicación por puerto serie con pySerial

El código mínimo

Para comunicarnos con nuestra placa Arduino por puerto serie utilizaremos la biblioteca pySerial, disponible también en PyPI. Una vez que tenemos nuestra placa enchufada, lo único que necesitamos para acceder a ella es esto:

import serial

arduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1.0)

La clase Serial puede recibir muchos parámetros, pero los fundamentales son estos:

  • El puerto (en nuestro caso '/dev/ttyACM0') que identifica la placa. En Windows sería 'COM3'.
  • La velocidad en baudios (en nuestro caso 9600). Algunos valores estándares son 9600, 19200, 38400…
  • El timeout (en nuestro caso 1 segundo) o tiempo máximo de espera para una lectura. Es importante poner un valor mayor que 0 para que en caso de error la lectura no «se cuelgue» indefinidamente.

Nota: La función readline() esperará a que se reciba una nueva línea, independientemente del timeout.

A partir de este momento podemos leer de la variable arduino como si fuera un fichero normal (de hecho los objetos Serial heredan de RawIOBase). Supongamos que en nuestra placa Arduino hemos cargado el ejemplo AnalogInOutSerial, y que por tanto nuestra placa está escribiendo datos al puerto serie:

while True:
    line = arduino.readline()
    print(line)

Y la salida será algo así:

$ python arduino_python.py 
b'sensor = 0\toutput = 0\r\n'
b'sensor = 0\toutput = 0\r\n'
b'sensor = 0\toutput = 0\r\n'
b'sensor = 0\toutput = 0\r\n'
b'sensor = 0\toutput = 0\r\n'
^CTraceback (most recent call last):
  File "arduino_python.py", line 34, in 
    line = arduino.readline()
  File "arduino_python.py", line 22, in readline
    time.sleep(0.1)
KeyboardInterrupt

Y podríamos dejarlo aquí, pero podemos hacer el código un poco más robusto.

Algunas mejoras

Con esto ya estamos leyendo los datos, pero podemos mejorar algunas cosas:

  • La función readline devuelve un objeto bytes: por eso vemos “\r\n” al final, los caracteres especiales de terminación de línea. Desde Arduino solo podemos mandar caracteres ASCII, así que podemos decodificar los bytes a una cadena. No obstante, habrá que indicar que en caso de recibir un byte erróneo no queremos que la función falle, sino que escriba algo como �.
  • Al detener el programa (Ctrl+C en la consola) no queremos ver una traza de error. Podemos capturar la excepción KeyboardInterrupt con un bloque try-except.
  • Faltaría incluir una llamada a arduino.close() al final del programa por seguridad, pero en vez de eso podemos utilizar la sentencia with y Python se encarga de cerrar la comunicación por nosotros.

El código final sería este:

¡Y ya lo tenemos! Esto es todo lo que necesitamos para leer datos desde una placa Arduino :)

Precauciones en el MundoReal™

La conexión a Arduino no siempre funcionará de manera ideal, y puede haber momentos en los que recibamos bytes erróneos. Hay un par de comentarios importantes que hacer al código anterior:

  • No se puede leer la placa desde dos fuentes a la vez. Si mientras corre este programa abres el monitor Serial del IDE de Arduino uno de los dos acabará fallando.
  • Podríamos iterar sobre el flujo de datos con un bucle for line in arduino, y Python se encargaría de ir invocando sucesivamente la función readline, pero este método puede fallar si se recibe algún byte corrupto. He comprobado que es más seguro hacerlo manualmente.

Esto afecta también a la hora de almacenar los datos recibidos, como veremos en la sección siguiente.

Por otro lado, hay otro asunto que hay que tener en cuenta: la placa Arduino se reinicia automáticamente al abrir una conexión por puerto serie, y al probar este código en Linux estaba dándome problemas. En los primeros segundos, entre el inicio de la conexión y el reinicio de la placa recibía datos erróneos. Por eso pregunté en Stack Overflow cómo reiniciar manualmente la placa usando pySerial y me dieron la solución:

import serial
import time
arduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1.0)

# Provocamos un reseteo manual de la placa para leer desde
# el principio, ver http://stackoverflow.com/a/21082531/554319
arduino.setDTR(False)
time.sleep(1)
arduino.flushInput()
arduino.setDTR(True)

De este modo, si empezamos a leer justo después deja de haber problemas. Dejo esta solución aquí en caso de que otros hayan experimentado este problema; en Windows, por ejemplo, no es necesario.

Almacenando los datos

Una vez que ya podemos leer los datos desde Arduino, vamos a dar algunas ideas sobre cómo almacenarlos y cómo procesarlos.

Leer un bloque de datos y cerrar

El caso más sencillo es leer un número predeterminado de líneas desde la placa y cerrar la conexión, para después procesar esos datos de la manera que queramos. Para ello, lo mejor es que empleemos un array de NumPy y que incorporemos los datos utilizando la función np.fromstring. Esta función acepta como argumentos la cadena que se va a leer y un argumento que indica cuál es el separador entre datos. Para cadenas ASCII como los que manejamos ahora, debemos especificar que los datos están separados por espacios. Utilizando de nuevo el sketch AnalogInOutSerial pero con las líneas de escritura de esta forma:

// print the results to the serial monitor:
//Serial.print("sensor = " );
Serial.print(sensorValue);
Serial.print("\t");
Serial.println(outputValue);

Este sería el código Python:

import time
import serial

import numpy as np

N = 10
data = np.zeros((N, 2))

# Abrimos la conexión con Arduino
arduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1.0)

with arduino:
    ii = 0
    while ii < N:
        try:
            line = arduino.readline()
            if not line:
                # HACK: Descartamos líneas vacías porque fromstring produce
                # resultados erróneos, ver
                # https://github.com/numpy/numpy/issues/1714
                continue
            data[ii] = np.fromstring(line.decode('ascii', errors='replace'),
                                     sep=' ')
            ii += 1

        except KeyboardInterrupt:
            print("Exiting")
            break

print(data)

¿Por qué usamos un contador con un bucle while en este caso, que parece que no queda muy pythonico? El motivo es que en algunos casos tendremos que descartar líneas (como se ha visto en el código por culpa de un fallo de NumPy) y esta estructura es más adecuada.

Procesar una cola de datos

Otra cosa que podemos necesitar es almacenar los datos en una cola e ir procesándolos sobre la marcha. Esto puede ser interesante si, por ejemplo, queremos representar gráficamente en tiempo real la evolución de una variable, pero solo nos interesan los últimos segundos. En este caso el módulo collections de la biblioteca estándar de Python nos proporciona la estructura deque (double-ended queue, que podríamos traducir por cola doblemente terminada), que funciona de manera que si añadimos elementos al final, a partir de una cierta longitud máxima se descartan elementos del principio.

Si quisiéramos usar una deque, el código sería este:

N = 10
data = deque(maxlen=N)  # deque con longitud máxima N

while True:
    # ...
    data.append(dd)  # Añadimos elementos al final de la cola

Y para usar arrays de NumPy, podemos usar un truco para ir recorriendo cíclicamente sus elementos:

N = 10
data = np.zeros(N)  # deque con longitud máxima N

ii = 0
while True:
    data[ii % N] = dd  # Recorremos cíclicamente el array
    ii += 1

Puedo tener dos efectos diferentes: con buff[i % N] tengo «efecto barrido», que sería similar a como representa los datos un osciloscopio, y con deque tengo «efecto pasada», que podríamos comparar con una ventana que se va desplazando.

Finale: Representación en tiempo real

Ahora no tenemos más que integrar todo lo que hemos visto arriba, y ya podremos representar en tiempo real datos procedentes de una placa Arduino con Python.

import time
import warnings
from collections import deque

import serial

import numpy as np
import matplotlib.pyplot as plt

N = 200
data = deque([0] * N, maxlen=N)  # deque con longitud máxima N

#Creamos la figura
plt.ion()
fig, ax = plt.subplots()
ll, = ax.plot(data)

# Abrimos la conexión con Arduino
arduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1.0)

arduino.setDTR(False)
time.sleep(1)
arduino.flushInput()
arduino.setDTR(True)

with arduino:
    while True:
        try:
            line = arduino.readline()
            if not line:
                # HACK: Descartamos líneas vacías porque fromstring produce
                # resultados erróneos, ver
                # https://github.com/numpy/numpy/issues/1714
                continue
            xx, yy = np.fromstring(line.decode('ascii', errors='replace'),
                                   sep=' ')
            data.append(yy)
            ll.set_ydata(data)
            ax.set_ylim(min(data) - 10, max(data) + 10)
            plt.pause(0.001)

        except ValueError:
            warnings.warn("Line {} didn't parse, skipping".format(line))

        except KeyboardInterrupt:
            print("Exiting")
            break

Y este es el resultado:

Datos Arduino en tiempo real

Datos Arduino en tiempo real

Aunque mejor que lo ejecutes en tu ordenador ;)

Para saber más

No soy ni mucho menos un experto en Arduino. Si estáis buscando un blog especializado os recomiendo GeekyTheory, y si queréis saber más acerca de Python + Arduino os interesará la charla de Núria Pujol sobre tracking GPS con Python y Arduino que dio recientemente en el grupo Python Barcelona. Además Núria accedió amablemente a revisar el borrador de esta entrada, ¡mil gracias! :)

Y tú, ¿tienes ya pensado cómo vas a combinar Python y Arduino? ¿Alguna idea o proyecto interesante que nos quieras contar? ¡Escríbenos en los comentarios!


Archivado en: Tutoriales Tagged: arduino, datos, numpy, python

La libertad de desarrollar...: Obtener información del clima en una ciudad con Python

$
0
0


Existe la librería PyOWM el cual es un wrapper para el API de OpenWeatherMap.
La documentación para utilizar la librería se encuentra en el siguiente enlace.

Para poder utilizar la librería es necesario crear una cuenta en OpenWeatherMap y en el perfil del usuario buscar el APPID. En el  enlace explican el procedimiento.

Para instalar la librería se ejecuta pip:

#pip install pyowm

A continuación se muestra el código de un script que muestra el uso de la librería:





#!/usr/bin/env python


# -*- coding: utf-8 -*-


import pyowm





#Llave del uso del API


apikey = "abcdefghijklimnopqrstuvxyz"


#Se crea la instancia OWM pasando la llave para el uso del API.


owm = pyowm.OWM(apikey)


#Se obtiene la llave de uso del API


print owm.get_API_key()


#Se define la ciudad por nombre o se pasa la coordenada.


obs = owm.weather_at('Valencia,ve')


#obs = owm.weather_at_coords(-0.107331,51.503614)





print "tiempo: ", obs.get_reception_time()


print "tiempo: ", obs.get_reception_time(timeformat='iso')





#Se Instancia los datos de la estacion meterologica.


w = obs.get_weather()





print "Fecha y hora ",w.get_reference_time(timeformat='iso')





print "Nubes:", w.get_clouds()





print "lluvias:", w.get_rain()





print "Nieve: ", w.get_snow()


print "viento", w.get_wind()





print "humedad:",w.get_humidity()


print "presion:", w.get_pressure()


print "Temperatura:",w.get_temperature()


print "Temperatura:",w.get_temperature(unit='celsius')


print "Estatus", w.get_status()


print "Hora de salida del sol",w.get_sunrise_time("iso")


print "Hora de ocultarse el sol",w.get_sunset_time('iso')


l = obs.get_location()


print "nombre:", l.get_name()


print "Longitud: %s, Latitud: %s" %(l.get_lon(),l.get_lat())

print "Identificador", l.get_ID()





Al ejecutar la aplicación se tiene lo siguiente:



ernesto@heimdal:~/bin/python$ ./clima.py 

abcdefghijklimnopqrstuvxyz

tiempo:  1390165372

tiempo:  2014-01-19 21:02:52+00

Fecha y hora  2014-01-19 20:00:00+00

Nubes: 20

lluvias: {}

Nieve:  {}

viento {u'speed': 2.1, u'deg': 110}

humedad: 41

presion: {'press': 1012, 'sea_level': None}

Temperatura: {'temp_kf': None, 'temp_min': 308.15, 'temp': 308.15, 'temp_max': 308.15}

Temperatura: {'temp_kf': None, 'temp_max': 35.0, 'temp': 35.0, 'temp_min': 35.0}

Estatus clouds

Hora de salida del sol 2014-01-19 10:54:19+00

Hora de ocultarse el sol 2014-01-19 22:31:34+00

nombre: Valencia

Longitud: -68.01, Latitud: 10.16



Identificador 3625549



Noten que la hora de salida y ocultamiento del sol está referente al meridiano 
de greenwich (es necesario ajustar al huso horario correspondiente).

Genbeta:dev: Cython llega a su versión 0.20 con jugosas novedades

$
0
0

python

Soy como mi prima Pitón pero más rápida

Cython es un superconjunto de Python, el lenguaje más hipster de la actualidad, que permite llamar a funciones y declarar variables y atributos de C, es decir, permite compilar de código Python a código C que vaya como un rayo. Cython está subiendo como la espuma entre la comunidad pythonera y hace escasos días se liberó su versión 0.20 con una buena ración de novedades entre las que destacan las siguientes:

  • Soporte para CPython 3.4
  • Soporte para llamadas a templates de C++
  • Constantes Python cacheadas
  • El formateo a través del operador % usa una llamada a la C-API más rápida
  • Soporte para __debug_builtin
  • El algoritmo de inferencia de tipos trabaja más fino teniendo en cuenta los resultados del análisis del flujo de control
  • Durante la recolección de basura cíclica, atributos de tipos de extensión que no pueden crear ciclos de referencia debido a su tipo (como los strings) ya no son considerados para el recorrido de limpieza. Esto reducirá la sobrecarga de procesamiento cuando se buscan o limpian ciclos de referencia
  • Compilación de paquetes funciona de Python 3.3 en adelante
  • Y por supuesto un gran número de bugs reparados y subsanados adecuadamente.

Todos los cambios y nuevas funcionalidades en el changelog de esta nueva versión. Y la puedes descargar y/o forkear desde (¿dónde si no?) Github.

Más información | cython.org

Viewing all 180 articles
Browse latest View live