domingo, 27 de diciembre de 2020

1) Trabajando con la Librería Numpy de Python. Creando Arrays.

 








Trabajando con la Librería Numpy en Python.

Aunque nos es muy cómodo trabajar con las listas en Python, cuando queremos realizar cálculos complejos o ganar velocidad en los programas, la librería estándar se queda corta. Es muy flexible, pero también lenta a la hora de realizar cálculos. Puedes ver la enorme diferencia de tiempo de ejecución en este ejemplo.

Si lo abres encontrarás el código en Python para calcular cual es el número pi usando el método Montecarlo. Lo que nos interesa es que ambos programas generan y trabajan en su ejecución con 16 millones de números, pero que mientras que el programa en python estandar tarda su tiempo, el que utiliza la libreria numpy lo realiza en nada, casi sin esfuerzo.

No voy a entrar en porque esta drástica reducción de tiempo, ya que no es objeto de este curso. Solo diré que la biblioteca Numpy nos mejora sustancialmente la velocidad al trabajar con datos. Nos introduce también un nuevo tipo de estos, como son las matrices o "arrays". Esto nos permitirá trabajar con datos multidimensionales de forma muy rápida, además de facilitarnos herramientas para trabajar con álgebra lineal, números aleatorios etc. Además se integra fenomenalmente con MatPlotLib a la hora de hacer gráficas de los mismos.

Crear arrays o matrices en Numpy.


Lo primero que tenemos que tener claro es que un array o matriz en Numpy siempre está formada por un número fijo de elementos y todos estos elementos se corresponden al mismo tipo de datos. Tanto el número de elementos como su tipo, se especifican al crear la matriz. Vamos a hablar de matriz porque creo que es más intuitivo, aunque realmente un array no es una matriz, abarca mucho más.

Aunque el número de elementos es fijo, la forma de la matriz se puede cambiar siempre que el número de elementos siga siendo el mismo.

Creando Matrices o Arrays.


La forma más sencilla de construir arrays es pasando los elementos directamente como argumento.

Por ejemplo para crear una matriz unidimensional de cinco elementos (9,8,7,6,5) podemos hacerlo de la siguiente forma.

>>> import numpy
# Importamos la librería Numpy

>>> m = numpy.array((9,8,7,6,5))
>>> m
array([9,8,7,6,5])

Esto ha generado una matriz unidimensional con cinco elementos de tipo entero.

Si no especificamos el tipo de los elementos que componen la matriz este se determina automáticamente a partir de los datos introducidos. En el ejemplo anterior, como todos eran números enteros (integer), el tipo de dato establecido por numpy automáticamente es entero. Ahora bien, si en el ejemplo anterior hubiera habido un número flotante, pej. (9,8,3.5,6,5) la matriz se hubiera creado de la misma forma solo que el tipo de datos seleccionado automáticamente para todos los elementos por numpy sería flotante (float).

El primer argumento de la función array() lo constituyen los elementos de la matriz. Puede ser una lista única (o tupla) o una lista anidada de listas de tamaño uniforme que imitan la estructura de una matriz multidimensional.

El segundo argumento de array() es el tipo de datos que se usarán en la matriz. Como hemos visto es opcional, si no lo ponemos, numpy lo establecerá automáticamente. El tipo de datos puede ser cualquiera de los tipos básicos de datos de python (int, float etc) o pueden ser mas científicos como los números complejos (complex) etc.






También podríamos crear la matriz desde una lista. Por ejemplo creando una matriz de 2 filas X 3 columnas de números complejos a partir de una lista dada.

>>> import numpy
# Importamos la librería Numpy

>>> lista = [(9,8,7),(6,5,4)]
>>> m = numpy.array(lista, complex)
>>> print(m)
[[9.+0.j 8.+0.j 7.+0.j]
 [6.+0.j 5.+0.j 4.+0.j]]


Si queremos saber la forma de la matriz usaremos la instrucción shape.

Con los datos del ejemplo anterior:

>>> print(m.shape)
(2, 3)

Y si lo que quisiéramos saber fuera el número de elementos, usaremos la instrucción size.

>>> print(m.size)
6


Funciones auxiliares que nos pueden ayudar a crear arrays.


La biblioteca NumPy nos facilita unas cuantas funciones auxiliares que nos permiten crear matrices.

Dos de las funciones más útiles para crear matrices con elementos secuenciales son arange y linspace.

1) Muy similar a la función range de python, numpy.arange() crea una matriz con elementos secuenciales que se reparten de forma uniforme en un intervalo dado.

Por ejemplo si queremos una matriz unidimensional con 10 elementos que se repartan de una forma uniforme podemos utilizar el siguiente código.

Nota. (En todos los ejemplos ya se supone que hemos importado la librería numpy previamente)

>>> matriz = numpy.arange(10)
>>> matriz
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> print(matriz)
[0 1 2 3 4 5 6 7 8 9]


Opcionalmente, también podemos especificar los valores iniciales y finales del rango a crear, así como un incremento o decremento en cada paso al crear un valor. Por ejemplo si queremos crear una matriz con elementos del 1 al 10 en el que cada elemento sea igual al anterior pero sumándole 2 lo podemos hacer con (numpy.arange(inicio, fin, paso)):

>>> m1 = numpy.arange(1,10,2)
>>> print(m1)
[1 3 5 7 9]

Los argumentos inicio, fin y paso no tienen que ser números enteros, también pueden ser números flotantes, por ejemplo.

2) Otra necesidad muy frecuente es la de tener que crear un número determinado de valores espaciados uniformemente dentro de un intervalo. Pues esto es justo lo que hace la función numpy.linspace()

Veámoslo con un ejemplo. Si queremos obtener una distribución uniforme con 5 elementos que vaya desde -3 a 3 usaremos esta instrucción:

>>> m2 = numpy.linspace(-3,3,5)
>>> print(m2)
[-3.  -1.5  0.   1.5  3. ]


3) También podemos crear una matriz de las dimensiones que queramos iniciándola con ceros, unos o el valor que queramos.

* Matriz de dos filas y cinco columnas cuyos elementos sean todos ceros.

>>> m3 = numpy.zeros((2,5))
>>> m3
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])

* Matriz de dos filas y cinco columnas cuyos elementos sean todos unos.

>>> m4 = numpy.ones((2,5))
>>> m4
array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])

* Matriz de cuatro filas por cuatro columnas rellenada con el número 3.6

>>> m5 = numpy.full((4,4),3.6)
>>> print(m5)
[[3.6 3.6 3.6 3.6]
 [3.6 3.6 3.6 3.6]
 [3.6 3.6 3.6 3.6]
 [3.6 3.6 3.6 3.6]]

4) Además de valores numéricos NumPy soporta el almacenar valores no numéricos como por ejemplo datos de tipo string o texto

>>> m6 = numpy.array(["rojo","verde","azul"])
>>> print(m6)
['rojo' 'verde' 'azul']

En alguna ocasión te puede ser útil obtener una matriz con los caracteres de una palabra.

>>> palabra = "estereoscopico"
>>> m7 = numpy.array(palabra,dtype='c')
>>> print(m7)
[b'e' b's' b't' b'e' b'r' b'e' b'o' b's' b'c' b'o' b'p' b'i' b'c' b'o']


Para finalizar este capítulo vamos a ver con un ejercicio un resumen de lo más importante de lo anterior.


EJERCICIO

1) Comencemos creando una lista de Python que contenga números enteros y flotantes y luego construyamos una matriz Numpy con ella. 

2 ) Luego creemos una matriz unidimensional que contenga todos los números de -2 a 2 con una separación de 0.2 Utilizaremos los argumentos opcionales de inicio y paso opcionales de la función np.arrange().

3) Para continuar, crearemos una matriz unidimensional que contenga 11 valores que estén distribuidos de forma igualitaria entre 0.5 y 1.5 

4) Y ya para acabar tomaremos caracteres de una cadena de Python y a partir de ella haremos una matriz de Numpy que contenga cada uno de los caracteres de forma individual.


SOLUCIÓN


import numpy as np

#1)
#lista que contiene números enteros y flotantes.
lista=[1,2,3,4,5.0,6.0,7.0]

#creamos un array de numpy con la lista anterior
n_list = np.array(lista)

#2) np.arange genera numero igual que range pero se le pueden pasar números decimales.
a = np.arange(-2.0, 2.0, 0.2)
print(a)

#3) np.linspace genera números pero en un intervalo que definimos nosotros
# por ejemplo creamos un intervalo de 11 valores entre 0.5 y 1.5
b = np.linspace(0.5,1.5,11)
print(b)

#4 muestra un string en numpy como caracteres
string = "El balonmano es un buen deporte"
s=np.array(string, dtype='c')
print(s)



Y hasta aquí el primer capítulo. 


Próximo Post. Accediendo a los datos de las matrices con Numpy. Copia de matrices.

miércoles, 16 de diciembre de 2020

Medición del rendimiento del código en python

 



Medición del rendimiento del código en python


A la hora de programar siempre hay diferentes formas de hacer la misma cosa. En ocasiones nos interesará saber cual es el código más rápido para hacer una tarea, es decir cual nos da un mejor rendimiento.

Veámoslo con un ejemplo sencillo. Imaginemos que tenemos una lista en python y queremos saber el valor de la suma de todos sus elementos:

lista=[10,15,67,45,23,423,12,22,4,56,13,22,78,98,1,43,56,22,31,11,23,56,78,22]

Podemos utilizar el comando sum, para sumar los elementos de la lista, o bien utilizar un bucle for para ir sumando los elementos uno a uno. Para saber cual es más eficiente una de las múltiples formas es usando el comando default_timer de la librería timeit.

El asunto funciona de la siguiente forma. Creamos una variable donde al comienzo del código que queremos medir establecemos el tiempo actual. Una vez ejecutado el código a medir, volvemos a estampar en la misma variable el tiempo actual. Por diferencia entre esta última y la primera vemos lo que ha tardado el código en ejecutarse. Vamos a verlo. Creamos un archivo nuevo de python y lo llamamos rendimiento.py

rendimiento.py

from timeit import default_timer
# Importamos la libreria que necesitamos para medir el tiempo

lista = [10, 15, 67, 45, 23, 423, 12, 22, 4, 56, 13,
         22, 78, 98, 1, 43, 56, 22, 31, 11, 23, 56, 78, 22]

# Suma de la lista utilizando SUM
contador = default_timer()
print(sum(lista))
t1 = default_timer()-contador
print(format(t1, 'f'))

# Suma de la lista con un bucle for
contador = default_timer()
resultado2 = 0
for i in lista:
    resultado2 = resultado2 + i
print(resultado2)
t2 = default_timer()-contador
print(format(t2, 'f'))

print(t1>t2)

Si lo ejecutamos veremos el siguiente resultado:

1231
0.000096
1231
0.000009
True

Como vemos por el resultado la función sum es menos eficiente que utilizar un bucle for ya que su tiempo de ejecución es mayor.

Nota: Como el resultado es un número muy pequeño de tiempo, la variable t sale en formato científico. Para poder ver el número más claro a simple vista voy a formatear la salida con la función format aplicada a la variable t aplicando el parametro 'f'.

Otra forma de hacer lo mismo es importando el método process_time() de la librería time.


rendimiento.py

from time import process_time
# Importamos la libreria que necesitamos para medir el tiempo

lista = [10, 15, 67, 45, 23, 423, 12, 22, 4, 56, 13,
         22, 78, 98, 1, 43, 56, 22, 31, 11, 23, 56, 78, 22]

# Suma de la lista utilizando SUM
t0 = process_time()
print(sum(lista))
t1 = process_time()
print("Tiempo transcurrido con SUM", format((t1-t0), "f"))

# Suma de la lista con un bucle for
t2=process_time()
resultado2=0
for i in lista:
    resultado2=resultado2 + i
print(resultado2)
t3=process_time()
print("Tiempo Transcurrido con bucle FOR ", format((t3-t2),"f"))
print((t1-t0)>(t3-t2))

Cuya salida es:

1231
Tiempo transcurrido con SUM 0.000045
1231
Tiempo Transcurrido con bucle FOR  0.000023
True

Lo que nos sigue confirmando que usar SUM es menos eficiente que usar un bucle For para sumar los elementos de la lista.


Una tercera forma, si estás en Linux, es usar la instrucción 'time'. Al ejecutarlo obtendremos tres comandos:

  • Real: hace referencia al tiempo transcurrido entre la ejecución y la finalización del proceso.
  • User: es la cantidad de tiempo de CPU gastado en modo usuario (fuera del núcleo) durante la ejecución del proceso.
  •  Sys: es la cantidad de tiempo de CPU que transcurre en el núcleo al ejecutar el proceso.
Vamos a ver un ejemplo. Creamos un primer archivo para ver cuando tarda en ejecutarse la suma de nuestra lista.

uno.py

lista = [10, 15, 67, 45, 23, 423, 12, 22, 4, 56, 13,
         22, 78, 98, 1, 43, 56, 22, 31, 11, 23, 56, 78, 22]

# Suma de la lista utilizando SUM
print(sum(lista))

y lo ejecutamos de esta forma para ver los resultados:

$ time python3 uno.py
1231

real	0m0,024s
user	0m0,012s
sys	0m0,008s

Y ahora creamos un segundo archivo 'dos.py' para hacer lo mismo pero a traves de un bucle for.

dos.py

lista = [10, 15, 67, 45, 23, 423, 12, 22, 4, 56, 13,
         22, 78, 98, 1, 43, 56, 22, 31, 11, 23, 56, 78, 22]

resultado2 = 0

# Suma de la lista utilizando FOR
for i in lista:
    resultado2=resultado2 + i
print(resultado2)

y ejecutamos de nuevo el comando 'time' para ver los resultados.

$ time python3 dos.py
1231

real	0m0,017s
user	0m0,010s
sys	0m0,007s

Lo que nos sigue confirmando el mismo resultado.


También nos puede ocurrir que tengamos un programa y para mejorar el rendimiento queramos saber que parte del mismo es el que esta gastando más recursos, el que esta utilizando más tiempo de computación, para intentar depurarlo y que se ejecute más rápido.

Para ver como las diferentes partes de un programa consumen los recursos, podemos utilizar el módulo cProfile.

Lo ejecutamos de la siguiente forma:

>>> python3 -m cProfile -o datos.dat rendimiento.py

Con esta instrucción le estamos diciendo a python3 que ejecute el modulo cProfile como un programa, con -o le decimos que guarde los resultados en el archivo datos.dat (puede tener el nombre que quieras) y para finalizar ponemos el nombre del programa a testear, en mi caso rendimiento.py

>>> python3 -m cProfile -o datos.dat rendimiento.py
1231
Tiempo transcurrido con SUM 0.000072
1231
Tiempo Transcurrido con bucle FOR  0.000011
True

Luego para ver las estadísticas que se han generado utilizamos un módulo que también viene dentro de python que es pstats

>>>pyhton -m pstats datos.dat

donde datos.dat es el nombre del archivo que generamos en el punto anterior.

Comandos de pstats:

help – para obtener información
Tecleamos:
1.) strip
Para acortar las rutas de los nombre de los módulos y que se vea mejor.
2.) sort time 
Para que nos ordene los datos por tiempo de ejecución. Se puede ordenar por otros campos.
3.) stats 10 
Para que nos muestre por pantalla las estadísticas, en este caso limitado a 10
resultados para que no nos sature la pantalla.

>>>python3 -m pstats datos.dat
Welcome to the profile statistics browser.
datos.dat% strip
datos.dat% sort time
datos.dat% stats 10
Tue Dec 15 19:53:12 2020    datos.dat

         15 function calls in 0.000 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        5    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        1    0.000    0.000    0.000    0.000 rendimiento.py:1(<module>)
        4    0.000    0.000    0.000    0.000 {built-in method time.process_time}
        2    0.000    0.000    0.000    0.000 {built-in method builtins.format}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


datos.dat% 

En este caso al ser un programa tan sencillo no nos aporta mucha información sobre los cuellos de botella del programa. Sin embargo si utilizamos por ejemplo este otro programa (paciencia que hace 16.000.000 de cálculos y tarda un poco), lo llamamos prueba.py  y aplicamos lo visto:

$ python3 -m cProfile -o data.dat prueba.py
Probabilidad= 0.7854415625
El numero estimado de pi= 3.14176625
El error para 16000000 REPETICIONES es de -0.00017
$ python3 -m pstats data.dat
Welcome to the profile statistics browser.
data.dat% strip
data.dat% sort time
data.dat% stats 10
Wed Dec 16 11:03:25 2020    data.dat

         32000717 function calls (32000690 primitive calls) in 15.398 seconds

   Ordered by: internal time
   List reduced from 101 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1   13.086   13.086   15.398   15.398 prueba.py:4(<module>)
 32000000    2.310    0.000    2.310    0.000 {method 'random' of '_random.Random' objects}
        2    0.000    0.000    0.000    0.000 {built-in method marshal.loads}
        3    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        2    0.000    0.000    0.000    0.000 {built-in method io.open_code}
        4    0.000    0.000    0.000    0.000 {built-in method _imp.create_builtin}
       10    0.000    0.000    0.000    0.000 {built-in method posix.stat}
        1    0.000    0.000    0.001    0.001 random.py:1(<module>)
        6    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1431(find_spec)
      6/1    0.000    0.000    0.002    0.002 <frozen importlib._bootstrap>:986(_find_and_load)


data.dat% 

Observamos como el modulo en su conjunto tarda 15.398 segundos en ejecutarse y que la principal carga de trabajo esta en el método random al que se hacen 32.000.000 millones de llamadas y es lo que mas procesamiento ocupa de cálculo de todo el programa.

En una próxima entrada veremos como se acelera enormemente la velocidad de cálculo si usamos la librería numpy con este mismo programa, de 15 segundos a prácticamente 1 segundo.

miércoles, 2 de diciembre de 2020

Dibujando Gráficos Sencillos en Python - Librería Matplotlib


 

Dibujando Gráficos Sencillos en Python - Librería Matplotlib

En este post vamos a explicar como crear gráficos sencillos para representar datos en Python.

Para ello usaremos la libreria Matplotlib.

Lo primero, como siempre, es crear un entorno virtual donde instalaremos todos las librerías necesarias.

Para ello creamos un directorio de trabajo (yo lo llamaré src) y dentro de él teclearemos:

$ python3 -m venv miEntorno

Una vez realizado lo anterior, procedemos a activar el entorno:

$ source miEntorno/bin/activate

Procedemos a instalar Matplotlib

(miEntorno) pi@rapsberry:~/scr$ pip install matplotlib

Aunque podríamos ya escribir el código de Python directamente en un archivo y luego ejecutarlo cada vez que hiciéramos alguna modificación, por comodidad vamos a utilizar Jupyter Notebook, al final del capítulo, veremos como hacerlo directamente en un archivo de Python.

Jupyter Notebook es un entorno de trabajo interactivo q permite desarrollar código en Python de manera dinámica, a la vez que integrar en un mismo documento tanto bloques de texto como gráficos e imágenes. Lo vas a ver más claro en cuanto lo instalemos y nos pongamos a funcionar con él.

Siempre dentro de nuestro entorno virtual, lo instalamos con:

(miEntorno) pi@rapsberry:~/scr$ pip install jupyter

y lo ejecutamos con la instrucción:

(miEntorno) pi@rapsberry:~/scr$ jupyter notebook

Si has realizado los pasos correctamente verás como se inicia el navegador web y te aparecerá una pantalla parecida a esta:







A la derecha selecciona New y cuando aparezca el desplegable selecciona Python3.

Comenzaremos creando el gráfico más básico que se puede hacer con Matplotlib, que es dibujar un punto o varios puntos con el comando plot. Verás como la cosa es muy sencilla. La forma general será:

plt.plot(posición x, posición y, marker=' ', color =' ')

Los argumentos marker y color son opcionales. Si no se ponen Matplotlib pone los suyos por defecto. Si quieres tú personalizar los colores, en vez de dejar que los elija el programa, los más frecuentes son los siguientes:

Colores comunes en Matplolib

‘c’ Cián

‘b’ Azul

‘g’ Verde

‘y’ Amarillo

‘k’ Negro

‘w’ Blanco

‘r’ Rojo

‘m’ Magenta

Después de dicho el matiz anterior, seguimos construyendo el gráfico. Para ello usaremos el siguiente código:


















En la primera línea importamos la librería matplolib.pyplot con el nombre de plt.

A continuación usamos lo que en Jupyter Notebook se conoce como función mágica (la distinguiremos porque usa el signo % delante de la función) %matplotlib notebook. Esto es sumamente útil ya que nos permitirá dibujar nuevos gráficos o añadir cosas sobre un gráfico que ya este creado. Es decir, nos permite añadir cosas una vez que se haya renderizado el código que hayamos puesto. Si no pusiéramos esta opción no se podría modificar la figura una vez renderizada, habría que crear otra nueva.

Para finalizar usamos el código que realmente dibuja el punto en el lugar(x=5, y=5) que es:

plt.plot(5,5,'o')

Ya ves que con poco código tenemos un bonito gráfico dibujado.

La secuencia es bien simple. En primer lugar ponemos la cordenada del eje de las x, luego la del eje de las y. La tercera posición hace referencia a la figura que se utilizará para dibujar el punto, en el ejemplo un circulo pequeño señalizado con el simbolo 'o'. Puedes utilizar un montón de símbolos para dibujar los puntos:

'.'point marker
','pixel marker
'o'circle marker
'v'triangle_down marker
'^'triangle_up marker
'<'triangle_left marker
'>'triangle_right marker
'1'tri_down marker
'2'tri_up marker
'3'tri_left marker
'4'tri_right marker
's'square marker
'p'pentagon marker
'*'star marker
'h'hexagon1 marker
'H'hexagon2 marker
'+'plus marker
'x'x marker
'D'diamond marker
'd'thin_diamond marker
'|'vline marker
'_'hline marker

Para ejecutar el código y que te salga el gráfico puedes usar la función "Run" en el menú de la parte superior que ejecuta la celda sobre la que estés o bien pulsar la combinación de teclas Ctrl+Enter. 

Y más sencillo aun es añadir una etiqueta para el eje de las x, para el eje de las y o también una descripción del gráfico. Pulsa en la celda donde tenemos el código, pulsa un intro y añade el siguiente código:

# Etiqueta del eje x
plt.xlabel("Eje de las X")
# Etiqueta del eje y
plt.ylabel("Eje de las Y")
# Título del Gráfico
plt.title("Gráfico de ejemplo de la instrucción Plot")

Luego ejecuta la celda con Ctrl+Enter

Verás de nuevo como se vuelve a generar el gráfico con las leyendas añadidas. 


Podríamos añadir tantos puntos como quisiéramos agregando al código un nuevo:

plt.plot(dato_en_el_eje_x, dato_en_el_eje_y, "figura")

Si te fijas, cada vez que se dibuja un punto (salvo que lo especificáramos nosotros) el programa dibuja el punto de un color diferente.

Como curiosidad si quisieras hacer un donuts con puntos usando Python este sería el código a utilizar:

import matplotlib.pyplot as plt
# https://matplotlib.org/3.1.1/
from random import random #genera numeros aleatorios entre (0,1)

n=5000 # número de puntos a dibujar
p=q=0

plt.figure(figsize=(6,6)) #tamaño del grafico en pulgadas 1 pulgada = 2,54 cm

for i in range(n):
# Esta es la parte que crea el Donuts.
    p=random()*8-4 #Limitamos x para que se este entre -4,4
    q=random()*8-4 #Limitamos y para que se este entre -4,4
    r=(p**2+q**2)**(1/2) #por el teorema de Pitágoras nos da la distancia al centro
    if 2<r<4: #Solo dejamos imprimir los puntos que tengan una distancia entre 2 y 4
        x,y=p,q
        plt.plot(x,y,'o',markersize=1) #markersize es el tamaño de los puntos.

plt.show()



Gráficos Lineales

Y al igual que hemos dibujado un punto, también podemos dibujar una línea o líneas formada por varios puntos usando las listas de Python. Vamos a usar aquí también la instrucción plt.show() para forzar que el resultado se muestre como una imagen y evitar la salida de texto que aparecía en la parte inferior de los ejemplos anteriores.

Si ejecutamos dos o más veces la función plot antes de ejecutar la función show(), todas las gráficas se mostraran en el mismo conjunto de ejes:



















Como ya dijimos, sino especificamos los colores de cada gráfica, estos saldrán de forma predefinida.

Además matplotlib se pude integrar también para usar conjunto de datos de las librerías numpy o panda.

Vamos a utilizar por ejemplo numpy para crear datos con los que poder realizar otro ejemplo de gráfica. Suponemos que tenemos instalado Numpy en nuestro entorno virtual. 

[1] Importamos las librerias necesarias y la función mágica que ya vimos antes.

[2] Utilizamos la librería numpy para crear un array que contenga 100 números decimales del 0 al 2.

[3] Por último trazamos los puntos del eje x e y. Aquí la única novedad es que asignamos una leyenda a cada uno de los gráficos con la etiqueta label. Al final renderizamos todas con la instrucción plt.legend()




Poner varios gráficos juntos en cuadriculas


Puede que en alguna ocasión nos interese poner dos gráficos juntos para poder comparar sus datos. Imaginemos una tabla compuesta por filas y columnas y en la que en cada celda podríamos poner un gráfico. Por ejemplo una tabla compuesta de una fila y dos columnas en la que en cada celda colocaremos un gráfico. Pues esto se puede hacer de forma sencilla con la instrucción plt.subplot(número) o plt.subplot(nº de filas, nº de columnas, posición en la tabla). Ambas son equivalentes. 

El primer número indica el número de filas que tendrá la tabla. El segundo el número de columnas que tendrá la tabla y finalmente el tercero indica la posición del gráfico dentro de la misma.

Por ejemplo, el siguiente cuaderno de jupyter dibujará un único grafico global que contendrá dos sub_gráficos dentro de una tabla de 2 filas y 1 columna, en la que cada gráfico estará en una de las celdas.



Gráficos Circulares.


Los gráficos circulares nos sirven para representar porcentajes o porciones. Podemos realizar este tipo de gráficos usando la función pie, en lugar de plot que habíamos visto hasta ahora.

Para poner un ejemplo del código en Jupyter para este tipo de gráficos vamos a imaginar una casa de 25 viviendas en la que cada hogar tiene una mascota. Se distribuyen de la siguiente forma:

                                                Mascota    |    Frecuencia
                                                Perros                    12
                                                Gatos                      9
                                                Peces                      3
                                                Tortugas                 1

Para representar el porcentaje de mascotas en el edificio podemos dibujar un gráfico circular. Para ello el código sería el siguiente:



Observa que lo primero que hemos hecho es importar la librería marplotlib. Luego utilizando listas de Python definimos los nombres y los números de las mascotas. Posteriormente utilizamos la función pie. Esta acepta un primer argumento que contiene los valores absolutos de cada item, además, de utilizar el argumento labels que contiene las etiquetas correspondientes.

Si quisiéramos indicar automáticamente los porcentajes de cada mascota lo podemos hacer con el argumento autopct. Todo el código sería el mismo, solamente le introduciríamos este nuevo argumento:

plt.pie(mascotas, labels=nombres, autopct="%0.1f%%")
# "%0.1f%%" indica que el % se representará con un decimal, si lo quisieramos
# con dos decimales utilizaríamos "%0.2f%%"




En matplotlib existen una multitud de opciones que se pueden especificar, como por ejemplo cambiar el color de cada quesito, pero son tantas que es mejor consultar el manual.

Una opción que puede resultar útil en el caso de los gráficos circulares es la posibilidad de separar del bloque uno o más de los quesitos de la gráfica. Para ello se debe pasar una lista o una tupla con valores entre cero y n al argumento explode, que indican el desfase respecto al centro del gráfico. El cero indica que la porción se quede como está, es decir que no haya ningún desplazamiento y si pones un número distinto n, este indica un desplazamiento equivalente a n*r, donde r es el radio del gráfico circular.

En nuestro ejemplo vamos a separa la porción que corresponde a los perros para que destaque frente a las demás.




Gráficos de Barras


Los gráficos de barras siguen la misma secuencia que el resto de gráficos, solo que la función que utilizamos es la denominada bar, no tiene más misterio.


Si quieres el gráfico con las barras en horizontal utiliza el mismo código exactamente que el ejemplo anterior pero usando la función barh.



Ejecutando Matplotlib directamente en un archivo de python.


Para finalizar este capítulo, si quisiéramos hacer lo mismo, pero no a través de Jupyter, sino ejecutando directamente un archivo de python, lo primero que tendríamos que hacer sería instalar en el entorno virtual la librería tkinter que nos permitirá generar y ver el gráfico en nuestra pantalla. Tecleamos:


(miEntorno) pi@rapsberry:~/scr$ sudo apt-get install python3-tk


Luego creamos el archivo ejemplo.py y creamos un grafico sencillo de los que ya hemos visto:


import matplotlib.pyplot as plt
plt.plot([1,3,6,8])
plt.plot([1,6,7,5])
plt.ylabel('Eje Y')
plt.xlabel('Eje x')
plt.title('Ejemplo del comando Plot')
plt.show()

Lo guardamos y ejecutamos ($ python3 ejemplo.py)



Si no queremos ver el gráfico por pantalla, no necesitamos instalar la libreria tkinter, ni usar la instrucción final plt.show() para renderizar el gráfico. Por ejemplo, podemos guardar en un archivo el gráfico generado para tratarlo posteriormente, usando la instrucción:

plt.savefig('nombre_del_grafico.extensión', bbox_inches='tight', dpi=)

Puedes guardar el gráfico con varias extensiones como png, jpg, svg

Los argumentos opcionales son:

bbox_inches='tight', se extiende o reduce el área de la figura guardada para incluir a todos los componentes de ella, eliminado también los espacios blancos sobrantes en los bordes.

dpi= resolución -> Indica la resolución con la que queremos guardar el gráfico. Ej dpi=300

Ejemplo:

import matplotlib.pyplot as plt
plt.plot([1,3,6,8])
plt.plot([1,6,7,5])
plt.ylabel('Eje Y')
plt.xlabel('Eje x')
plt.title('Ejemplo del comando Plot')
plt.savefig('miGrafico.png')

Si ahora comprobamos nuestro directorio de trabajo veremos como se ha creado un archivo llamado miGrafico.png que contiene el gráfico que hemos creado.


Puedes encontrar más información sobre gráficos y también el funcionamiento de la librería plotly en este repositorio de GITHUB.