Eventos en un botón (wx.Button)

Los botones son componentes gráficos muy comunes que nos encontramos en cualquier interfaz de usuario y cuyo propósito es, generalmente, inicializar o confirmar un evento. En wxPython un botón ordinario se crea utilizando la clase wx.Button, a la cual habrán de pasarse como argumentos de inicialización mínimos, el objeto padre, un ID, y una cadena indicando la etiqueta visible del botón. 
Por ejemplo:

# -*- coding: utf-8 -*-
import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(200,200))
self.boton = wx.Button(self, -1, u"Botón")
self.Centre(True)
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Test wxButton")
app.MainLoop()




Lo anterior crea un botón ocupando todo el espacio disponible en el Frame. Para colocar dos o más botones tendríamos que especificar el tamaño y posición de cada uno mediante los keyword argument size pos. Por ejemplo:

# -*- coding: utf-8 -*-
import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(200,200))

self.boton1 = wx.Button(self, -1, u"Uno", size=(100,20),
pos=(50,10))
self.boton2 = wx.Button(self, -1, u"Dos", size=(100,20),
pos=(50,50))
self.boton3 = wx.Button(self, -1, u"Tres", size=(100,20),
pos=(50,90))

self.Centre(True)
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Test wxButton")
app.MainLoop()




Otra manera más conveniente de posicionar los botones o cualquier objeto gráfico sería utilizando sizers, de los cuales se estará hablando en posteriores entradas, pero vamos, que por ahora veremos cómo implementar manejo eventos en botones.

Así, en wxPython cuando se presiona un botón se lanza un evento del tipo wx.EVT_BUTTON, por ello lo que debemos hacer es utilizar el método Bind y agregar eventos de tipo wx.EVT_BUTTON al escuchador de eventos, asignando además un handler, que es básicamente una función o método que se encargará de manejar la respuesta de la interfaz al evento en cuestión.

Por ejemplo, vamos a imprimir un mensaje en consola cada vez que se presiona cualquiera de los tres botones que componen nuestra interfaz de usuario:

# -*- coding: utf-8 -*-
import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(200,200))

self.boton1 = wx.Button(self, -1, u"Uno", size=(100,20),
pos=(50,10))
self.boton2 = wx.Button(self, -1, u"Dos", size=(100,20),
pos=(50,50))
self.boton3 = wx.Button(self, -1, u"Tres", size=(100,20),
pos=(50,90))
# Conectando evento
self.Bind(wx.EVT_BUTTON, self.OnClick)

self.Centre(True)
self.Show()

def OnClick(self,event):
print u"Has presionado un botón"


if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Test wxButton")
app.MainLoop()

Note que hemos conectado los eventos de tipo wx.EVT_BUTTON al método OnClick que hace las veces de un handler. Luego, el método OnClick simplemente imprime en consola un mensaje.

Ahora, ¿cómo podríamos hacer que para cada botón presionado se tenga una respuesta diferente?. Hay dos formas comunes, a saber: especificando un handler para cada botón y utilizando el argumento eventpara identificar de dónde proviene el evento.

Primero vamos a utilizar un handler para cada botón. Debemos saber entonces que el método Bind acepta como tercer argumento un source o referencia a un objeto gráfico del cual se espera que provenga el evento. Algo como:

self.Bind(wx.EVT_BUTTON, self.OnClick, boton)

Pero vamos con el ejemplo que venimos trabajando:

# -*- coding: utf-8 -*-
import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(200,200))

self.boton1 = wx.Button(self, -1, u"Uno", size=(100,20),
pos=(50,10))
self.boton2 = wx.Button(self, -1, u"Dos", size=(100,20),
pos=(50,50))
self.boton3 = wx.Button(self, -1, u"Tres", size=(100,20),
pos=(50,90))
# Conectando eventos
self.Bind(wx.EVT_BUTTON, self.OnClick1, self.boton1)
self.Bind(wx.EVT_BUTTON, self.OnClick2, self.boton2)
self.Bind(wx.EVT_BUTTON, self.OnClick3, self.boton3)

self.Centre(True)
self.Show()

def OnClick1(self,event):
print u"Has presionado el botón 1"

def OnClick2(self,event):
print u"Has presionado el botón 2"

def OnClick3(self,event):
print u"Has presionado el botón 3"


if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Test wxButton")
app.MainLoop()

Como puede ver, por cada botón se conecta un evento wx.EVT_BUTTON con el handler correspondiente, así cada vez que se presione un botón diferente la respuesta obtenida será dependiendo del handler asignado.

Finalmente, la segunda forma consiste en utilizar el segundo parámetro del handler asignado para manejar un evento (normalmente y por convención llamado event). ¿Pero qué es el parámetro event?, en términos simples es un objeto de la clase wx.CommandEvent que contiene información acerca del evento lanzado. Implementando esta manera para el ejemplo anterior se tiene:

# -*- coding: utf-8 -*-
import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(200,200))

self.boton1 = wx.Button(self, -1, u"Uno", size=(100,20),
pos=(50,10))
self.boton2 = wx.Button(self, -1, u"Dos", size=(100,20),
pos=(50,50))
self.boton3 = wx.Button(self, -1, u"Tres", size=(100,20),
pos=(50,90))
# Conectando eventos
self.Bind(wx.EVT_BUTTON, self.OnClick)

self.Centre(True)
self.Show()

def OnClick(self,event):
bt_label = event.GetEventObject().GetLabel()
print u"Has presionado el botón %s"%(bt_label)

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Test wxButton")
app.MainLoop()

El método GetEventObject del objeto event devuelve la referencia al objeto del cual proviene el evento, y posteriormente con el método GetLabel() se obtiene simplemente la etiqueta del botón correspondiente para imprimirla en pantalla.

Utilizando un ComboBox en wxPython

Un ComboBox es un control gráfico que despliega una lista de opciones cuando se interactúa con el, permitiendo desde luego la selección de sus ítems y consecuentemente el lanzamiento de un evento de tipoEVT_COMBOBOX. Resulta lógico pensar que la utilidad de un ComboBox se hace notoria cuando se requiere disponer de una serie de opciones en un control que visualmente no ocupe mucho espacio.

El ejemplo siguiente es una mini-aplicación wxPython que contiene dos ComboBox y un TextCtrl, que básicamente lo que hace es mostrar en el TextCtrl una concatenación de las opciones seleccionadas en ambos ComboBox:
import wx

class TestFrame(wx.Frame):
def __init__(self,*args,**kwargs):
wx.Frame.__init__(self,*args,**kwargs)
sizer = wx.BoxSizer(wx.VERTICAL)
# Datos para los ComboBox
nombres = u"Ana|Pablo|Daniela|Jorge|David|Dulce".split("|")
paises = u"México|Colombia|Chile|Argentina|España|Uruguay".split("|")
# Controles gráficos
self.cbbox_nombres = wx.ComboBox(self,-1,choices=nombres,size=(120,25))
self.cbbox_paises = wx.ComboBox(self,-1,choices=paises,size=(120,25))
self.txt = wx.TextCtrl(self, -1, size=(150,25), style=wx.TE_CENTRE)
self.txt.SetBackgroundColour("#d0fefe")
# Agregando controles al sizer
sizer.Add(self.cbbox_nombres, 0, wx.ALIGN_CENTRE|wx.ALL, 10)
sizer.Add(self.cbbox_paises, 0, wx.ALIGN_CENTRE|wx.ALL, 10)
sizer.Add(self.txt, 0, wx.ALIGN_CENTRE|wx.ALL, 10)
# Configurando sizer
self.SetSizer(sizer)
# Configurando eventos
self.Bind(wx.EVT_COMBOBOX, self.OnSelect)
self.Show()

def OnSelect(self,event):
nombre = self.cbbox_nombres.GetValue()
pais = self.cbbox_paises.GetValue()
statxt = nombre + " es de " + pais
self.txt.SetLabel(statxt)


if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, title="ComboBox Test", size=(250,200))
app.MainLoop()



Vamos, un poco más despacio y con algunos detalles extras:

Primero (y como siempre) importamos el módulo wx para tener disponibles las clases que usaremos en el desarrollo de la aplicación. Definimos una clase TestFrame heredada de wx.Frame en la cual colocaremos todos los controles gráficos a utilizar.


Enseguida creamos los datos o listas que vamos a utilizar en los ComboBox, ha de saber que el método split de la clase str devuelve una lista de strings resultantes de cortar la cadena original en los segmentos delimitados por el caracter que se ha pasado como argumento ("|" para este caso).


Luego se crean los controles gráficos (ComboBox y TextCtrl), puede ver que para crear un ComboBox necesita instanciar un objeto de la clase wx.ComboBox, a la cual como argumentos mínimos se le debe indicar el objeto padre (parent), un id, y un lista de valores (choices) que contiene las opciones a desplegar. Adicionalmente puede definir otros keyword arguments como el tamaño y/o la posición del control.

Una vez se han creado los controles, estos se deben agregarse al sizer de la aplicación para que sean organizados acorde a la distribución o algoritmo de posicionamiento seleccionado.

Finalmente, se programa la respuesta que tendrá la aplicación cuando los ComboBox sean manejados por el usuario, para ello se asigna el método OnSelect como el handler de los eventos de tipowx.EVT_COMBOBOX. Note que el método OnSelect contiene dos parámetros obligatorios por default, self que hace referencia a la clase misma y event que contiene información acerca del evento lanzado. En este caso el método OnSelect lo único que hace es tomar los strings seleccionados en cada uno de los ComboBox, y concatenarlos utilizando un nexo cualesquiera, para finalmente asignar la cadena resultante al valor del TextCtrl.

Personalizando Frames en wxPython

Un frame ordinario en wxPython se puede construir de manera muy sencilla, heredando simplemente de wx.Frame.

import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300))
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Mi Frame")
app.MainLoop()



A continuación vamos a ver algunas cuestiones interesantes para crear frames personalizados.

Cambiando el color de fondo


Para cambiar el color de fondo de un Frame podemos utilizar el método SetBackgroundColour, al cual debemos pasarle como argumento un objeto de la clase wx.Colour o bien una cadena en notación hexadecimal para especificar el color.

import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300))
# Modificando el color de fondo
rojo = wx.Colour(255,0,0)
# rojo = "#ff0000" # Equivalente en notación hexadecimal
self.SetBackgroundColour(rojo)
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Mi Frame")
app.MainLoop()


Colocando un ícono


Para colocar un ícono en la barra superior de nuestro Frame utilizamos el método SetIcon, al cual debemos pasarle como argumento un objeto de la clase wx.Icon. Para instanciar un objeto de wx.Iconnecesitamos simplemente pasar como argumento la ruta de la imagen/ícono.

import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300))
# Colocando un ícono
icono = wx.Icon("icono.png")
self.SetIcon(icono)
# ...
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Mi Frame")
app.MainLoop()



Modificando estilos


Ventana no redimensionable

Si queremos tener una ventana con un tamaño fijo, podemos hacerlo modificando el estilo por defecto de nuestro Frame. Cuando creamos un Frame por defecto se toma el estilo wx.DEFAULT_FRAME_STYLE. Para modificarlo debemos pasar el keyword argument style con una lista de estilos determinados. Para nuestro caso de una ventana no redimensionable:

import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
styles = (wx.CLOSE_BOX|wx.CAPTION)
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300),
style=styles)
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Mi Frame")
app.MainLoop()



Ventana sin barra de título

Si queremos una ventana sin barra de título, podemos quitar el estilo wx.CAPTION:

import wx

class TestFrame(wx.Frame):
def __init__(self,parent,title):
styles = wx.DEFAULT_FRAME_STYLE & ~ (wx.CAPTION)
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300),
style=styles)
self.SetBackgroundColour("#ff00ff")
self.Show()

if __name__=='__main__':
app = wx.App()
fr = TestFrame(None, "Mi Frame")
app.MainLoop()



El estilo wx.DEFAULT_FRAME_STYLE & ~ (wx.CAPTION) toma todos los estilos incluidos en wx.DEFAULT_FRAME_STYLE, exceptuando a wx.CAPTION, un poco de combinación de operaciones lógicas AND-NOT.

Una aplicación muy básica en wxPython

La aplicación más elemental en wxPython puede lanzarse con apenas 5 líneas de código (incluyendo la instrucción de importar el módulo wx).

import wx

app = wx.App()
fr = wx.Frame(None,title="Test 01",size=(400,300))
fr.Show()
app.MainLoop()

Ahora vamos por pasos, a despedazar un poco el código anterior. Primero importamos el módulo wx, el cual contiene todo (o casi todo, exceptuando controles más especializados y sus derivados) lo que podemos utilizar para construir una aplicación. Acto seguido, creamos un objeto de la clase wx.App, que vendrá a ser la propia aplicación y se encargará de que el usuario pueda interactuar con los controles gráficos desplegados en pantalla. Luego, se crea un objeto de la clase wx.Frame que es en términos simples una ventana de las que estamos acostumbrados a ver en todos lados; note que a wx.Frame se le pasan como argumentos primeramente el valor None que hace referencia al objeto padre (ninguno en este caso), y los keyword arguments title y size que definen el título y tamaño de la ventana, respectivamente. Finalmente se llama al método MainLoop de la clase wx.App para inicializar la captura de eventos en nuestra aplicación.

¿Y ahora cómo agregamos controles?

import wx

app = wx.App()
fr = wx.Frame(None,title="Test 01",size=(400,300))
bt = wx.Button(fr, -1, u"Botón 1", pos=(0,0))
txt = wx.TextCtrl(fr, -1, pos=(100,0))
fr.Show()
app.MainLoop()



En resumen lo que se hace es crear un objeto de clase del control gráfico requerido, pasándole a este como argumento de objeto padre la ventana o frame guardado en la variable fr. Note que hemos pasado a cada control el keyword argument pos para definir una posición fija dentro del frame. Normalmente en wxPython no deberiamos hacer esto, sino utilizar Sizers para posicionar los elementos de manera automática, pero bueno, para un ejemplo básico lo daremos por bueno.

¿Y cómo definimos un evento?

import wx

def OnClick(event):
print "Hola wxPython"

app = wx.App()
fr = wx.Frame(None,title="Test 01",size=(400,300))
bt = wx.Button(fr, -1, u"Botón 1", pos=(0,0))
txt = wx.TextCtrl(fr, -1, "",pos=(100,0))
fr.Bind(wx.EVT_BUTTON, OnClick)
fr.Show()
app.MainLoop()

Con el método Bind agregamos un determinado tipo de evento a ser capturado por nuestra aplicación, pasando como primer argumento el tipo de evento (en este caso wx.EVT_BUTTON), y como segundo argumento un handler o una función en la cual habrá de definirse la respuesta de la aplicación al lanzamiento del evento. Para el caso anterior lo único que se hace es imprimir en la consola una cadena de texto cada que se oprime el botón.

Códigos como los anteriores pueden servir para mostrar una simple ventana o para una demo muy reducida de una aplicación wxPython, si quisieramos desarrollar algo más serio con esa técnica iríamos directo a una infinidad de complicaciones.

Por ello para desarrollar aplicaciones en wxPython se utiliza otra metodología, que consiste en crear clases heredadas de las proporcionadas por la librería, y en estás clases heredadas modificar/adicionar las características que tendrá nuestro frame o cualquier otro control gráfico. Básicamente esto consiste en los siguientes puntos:
  1. Heredar una clase de wx.Frame
  2. Agregar los controles gráficos necesarios a nuestro Frame en su método __init__ (o pseudoconstructor).
  3. Definir los eventos como métodos de la clase que se ha heredado.
  4. Crear una instancia de wx.App y una de nuestra clase heredada de wx.Frame.
  5. Llamar al método MainLoop de wx.App.
Traducido a código puro y duro:

import wx

class MiFrame(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300))
# Agregando los controles
self.bt = wx.Button(self, -1, u"Botón 1", pos=(0,0))
self.txt = wx.TextCtrl(self, -1, "",pos=(100,0))
# Eventos
self.Bind(wx.EVT_BUTTON, self.OnClick)
# Mostrar la ventana
self.Show()

def OnClick(self,event):
print "Hola wxPython"


if __name__=='__main__':
app = wx.App()
fr = MiFrame(None, "Test 01")
app.MainLoop()

Por ahora ha sido todo respecto a cómo construir una aplicación muy básica, evidentemente hay muchas cosas por mejorar en esta aplicación que iremos viendo en entradas posteriores.

Bienvenidos...

Este blog se ha creado con la intención de compartir códigos básicos (y no tan básicos) para el desarrollo de interfaces gráficas en Python utilizando la librería wxPython. Lo anterior con la finalidad de mitigar un poco la falta de ejemplos en nuestra lengua acerca de esta librería.

Las dudas, sugerencias, comentarios o cualquier otro tipo de opinión siéntase libre de remitirlos al correo: delossantossantosmfq@gmail.com o bien contactar a través de Twitter o GitHub.

Y bueno, aquí comenzamos.

Introducción a scikit-image, procesamiento de imágenes en Python

En este post vamos a hacer una pequeña introducción a la librería scikit-image, la cual básicamente es una colección de algoritmos para el procesamiento de imágenes en Python.

Para comenzar


Todas las instrucciones referente a descarga e instalación, así como algunos códigos de ejemplos pueden encontrarse en la página oficial: http://scikit-image.org/.

A manera de referencia rápida, puede instalar scikit-image utilizando pip:

>> pip install -U scikit-image

En general, scikit-image o skimage, trabaja con arrays de numpy, así como también hace uso de algunas utilidades gráficas de Matplotlib para la visualización, por ello también es necesario tener instaladas las librerías SciPy, Matplotlib, NetWorkX, y PIL/pillow.

Lo muy básico: cómo leer y mostrar imágenes


Bueno, aquí un primer ejemplo de cómo leer y mostrar una imagen desde un archivo. Tenemos una imagen llamada "lenna.png" en el mismo directorio de nuestro código, luego, podemos utilizar el módulo iode scikit-image para leer y mostrar esta imagen. Básicamente se procede como sigue:

Primero importamos el modulo correspondiente:

from skimage import io

Ahora utilizamos la función imread del módulo io para leer la imagen, y guardamos esto en una variable, en la cual se almacenará un array de NumPy con la información de los colores que componen la imagen.

img = io.imread('lenna.png')

Enseguida utilizamos la función imshow para mostrar la imagen que pasemos como argumento y la función show para mostrar toda la ventana o figure que contiene la(s) imágenes a desplegar en la pantalla.

io.imshow(img)
io.show()

Juntando este mini código nos quedaría algo como lo siguiente:

from skimage import io

img = io.imread("lenna.png")
io.imshow(img)
io.show()

Si ejecutamos lo anterior nos mostrará la imagen leída en una ventana o figure de Matplotlib, tal como se aprecia en la siguiente imagen:



Podemos averiguar la forma o cantidad de elementos del array img utilizando el método shape, por ejemplo en el script anterior se puede añadir:

print img.shape

Y con ello nos mostrará en consola una tupla de 3 elementos (para el caso de esta imagen) con la información del número de filas, columnas y capas de la matriz. En nuestro ejemplo nos muestra:

(512L, 512L, 3L)

Lo cual implica que tenemos una imagen de 512x512 pixeles. El tercer número indica que tenemos tres capas o canales del módelo de color RGB, en el cual la primer capa representa el rojo, la segunda el verde y la tercera el azul. Así, toda la gama de colores para un pixel en específico se puede obtener mediante la combinación de estos tres colores primarios.

Un poco de gris...


Ahora, ya sabemos leer y mostrar imágenes. Vamos a operar un poco y a convertir nuestra matriz RGB de entrada en una matriz de intensidades en escala de grises, o en pocas palabras vamos a transformar una matriz de color en una en tono de grises. Para ello vamos a importar el módulo color y a utilizar la función rgb2gray:

from skimage import io,color

img = io.imread("lenna.png")
img_gris = color.rgb2gray(img)
io.imshow(img_gris)
io.show()



¿Y qué pasa si queremos mostrar ambas imágenes en una misma ventana?, bueno, para ello podemos hacer uso de la función subplot de Matplotlib:

import matplotlib.pyplot as plt
from skimage import io,color

img = io.imread("lenna.png")
img_gris = color.rgb2gray(img)
plt.subplot(211)
io.imshow(img)
plt.subplot(212)
io.imshow(img_gris)
io.show()




Hasta aquí esta breve introducción a scikit-image, una librería que sin duda vale la pena revisar y que proporciona una cantidad razonable de algoritmos que pueden ser muy útiles en el procesamiento digital de imágenes. Posteriormente se hablará de algunos tópicos básicos adicionales, como la binarización, segmentación, y otras operaciones típicas.

Gráficas en coordenadas polares en Matplotlib

Trazar gráficas en coordenadas polares mediante el módulo pyplot es muy sencillo, y se procede de manera similar que con las funciones en coordenadas rectangulares. Lo único que debemos cambiar es el tipo de proyección de el axes en el que vamos a plotear nuestras funciones polares.

Por ejemplo si queremos graficar una espiral de Arquímedes:

r(θ)=a + bθ

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0,2*np.pi)
r = 5 + 50*theta

fig = plt.figure()
ax = fig.add_subplot(111, projection="polar")
ax.plot(theta,r)

plt.show()


O una rosa polar:

r(θ)=acos(kθ + ϕ0)

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0,2*np.pi,1000)
r = 5*np.cos(5*theta)

fig = plt.figure()
ax = fig.add_subplot(111, projection="polar")
ax.plot(theta,r,color="#ffb6c1",linewidth=3)

plt.show()



Note que se pueden pasar argumentos de estilo y color a la función plot tal y como se hace con las gráficas en coordenadas rectangulares.

Como se observa en los ejemplos anteriores lo único que debemos hacer es adicionar el keyword argument projection='polar' al momento de crear el axes en el cual graficaremos nuestra función en coordenadas polares.

Una introducción a Pylab

Pylab es un módulo de Matplotlib que, básicamente, integra en un mismo espacio de nombres utilidades gráficas del módulo pyplot y las numéricas de NumPy, resultando un entorno que se asemeja a MATLAB en el manejo de matrices/vectores y el trazo de gráficas.

Para importar todas las funciones de pylab podemos hacerlo como sigue:

from pylab import *

Con esto tendremos disponible todas las funciones y/o constantes en el espacio de trabajo actual.

Matrices y vectores

Algo básico que podemos hacer con Pylab es crear con vectores y matrices de una forma rápida:

>>> v=array([-2,0,1,5,3]) #Definiendo un vector
>>> v
array([-2, 0, 1, 5, 3])
>>> A=array([[1,-1,-5],[8,2,10],[-5,2,3]]) # Definiendo una matriz
>>> A
array([[ 1, -1, -5],
[ 8, 2, 10],
[-5, 2, 3]])
Realizar operaciones matriciales básicas:
>>> B=array([[1,5,0],[7,-9,2],[1,1,3]])
>>> # Suma de matrices
>>> A+B
array([[ 2, 4, -5],
[15, -7, 12],
[-4, 3, 6]])
>>> # Resta de matrices
>>> A-B
array([[ 0, -6, -5],
[ 1, 11, 8],
[-6, 1, 0]])
>>> # Multiplicación matricial
>>> dot(A,B)
array([[-11, 9, -17],
[ 32, 32, 34],
[ 12, -40, 13]])

Note que la multiplicación matricial se debe realizar con la función dot, si se efectúa la multiplicación con el operador *, este dará el resultado de una multiplicación elemento por elemento.

También se pueden utilizar algunas funciones típicas de un paquete de álgebra lineal para operar sobre matrices:

>>> det(A) # Determinante de A
-69.999999999999957
>>> inv(A) # Matriz inversa de A
array([[ 2.00000000e-01, 1.00000000e-01, 2.77555756e-17],
[ 1.05714286e+00, 3.14285714e-01, 7.14285714e-01],
[ -3.71428571e-01, -4.28571429e-02, -1.42857143e-01]])
>>> transpose(A) # Transpuesta de A
array([[ 1, 8, -5],
[-1, 2, 2],
[-5, 10, 3]])

Gráficas

Otra utilidad de pylab son las gráficas, es tan sencillo como utilizar la función plot:

plot([1,3,-2,0,1])
show()



Si se requiere algo más elaborado:

x = linspace(0,10)
y = exp(0.1*x)*cos(x)

plot(x,y,'k')
xlabel("Tiempo (s)")
ylabel("Amplitud (mm)")
title(u"Gráfica 01")
grid(True)
show()



O múltiples gráficas:

x = linspace(0,10)
y1 = exp(0.1*x)*cos(x)
y2 = exp(0.5*x)*sin(x)

subplot(2,1,1)
plot(x,y1,'r')
ylabel("Amplitud (mm)")
grid(True)

subplot(2,1,2)
plot(x,y2,'b')
xlabel("Tiempo (s)")
ylabel("Amplitud (mm)")
grid(True)


Vectores y matrices en NumPy

NumPy es una librería muy útil y un estándar en Python para el manejo de matrices y/o arreglos que contienen datos de tipo numérico. La mayoría del ecosistema científico de Python está basado en los arreglos de NumPy para el manejo de datos.

Normalmente se acostumbra importar el módulo NumPy utilizando el alias np:

>>> import numpy as np

Se puede crear un arreglo de NumPy a partir de una lista ordinaria de Python, utilizando la función np.array.

>>> lista=[-1,0,2,5,8]
>>> A=np.array(lista)
>>> A
array([-1, 0, 2, 5, 8])

La función np.array crea un objeto de la clase numpy.ndarray,

>>> type(A)
<type 'numpy.ndarray'>

Si se requiere crear una matriz debe pasarse como argumento de entrada una lista de listas, donde cada sublista representa una fila de la matriz, por ejemplo para definir la matriz M siguiente:

$$ M = \left(\begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{matrix}\right) $$
utilizando una lista de listas,

>>> M=np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> M
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])

Se puede determinar la forma (número de filas y columnas) de una matriz o arreglo utilizando la propiedad shape de la clase numpy.ndarray.

>>> A.shape
(5L,)
>>> M.shape
(3L, 3L)

En entradas posteriores veremos cómo realizar operaciones matriciales con matrices vectores.

Bienvenidos...

Bienvenidos a este blog de Python para Ingenieros, en el cual hablaremos un poco-mucho de varias cosas relacionadas con la programación en Python aplicada en la ingeniería.

Lo imprescindible: bueno, aquí usaremos NumPy, Scipy, Matplotlib y Sympy como librerías básicas y casi indispensables. Y de ahí paulatinamente exploraremos otras librerías útiles en el mundo del Scientific Python.

Así pues, comencemos...