sábado, 27 de abril de 2024

Campeones de Gráficos.

 Basado en el proyecto de la RapsberryPi Org "Charting Champions".

¿Qué es lo que haremos?

Descubriremos el poder de las listas en Python creando un gráfico interactivo de la medallas olímpicas conseguidas por los diferentes países.

Los juegos olímpicos empezaron en el año 1896: miles de atletas representaron a centenares de naciones de todo el mundo. Los juegos olímpicos modernos se inspiraron en las olimpiadas que se realizaban en Grecia en la antigüedad.

Lo que haremos:

- Usar listas para almacenar los datos.

- Crear un gráfico usando la librería Pygal.

- Cargar los datos haciendo que tu programa los lea desde un archivo.


Creando un gráfico.

Lo primero que haremos será instalar la librería que vamos a utilizar para crear el gráfico, la librería Pygal. Para presentar los gráficos por defecto se utiliza el formato SVG (escalable vector graphics), que incluso nos servirá para incluirlo en una página web.

Información: INSTALANDO PYGAL

En WINDOWS:

En la consola de comandos teclea lo siguiente y pulsa la tecla Enter.

pip install pygal

Espera que la instalación se complete y luego continua con el proyecto.

En un MAC:

En una ventana de terminal teclea lo siguiente y pulsa la tecla Enter.

pip3 install pygal

Espera que la instalación se complete y luego continua con el proyecto.

En LINUX, incluyendo el sistema operativo de la Rapsberry Pi.

En una ventana de terminal teclea lo siguiente y pulsa la tecla Enter.

pip3 install pygal

Espera que la instalación se complete y luego continua con el proyecto.
Para comenzar el proyecto importaremos algo de código de la librería pygal que utilizaremos para dibujar el gráfico. Empieza creando un nuevo archivo, por ejemplo main.py, y teclea el siguiente código:

from pygal import Bar

Después vamos a crear un gráfico de barras para mostrar los resultados. Añade el siguiente código y luego ejecútalo:

from pygal import Bar
import webbrowser

# Creando un gráfico
grafico = Bar(title="Medallas Olímpicas")
grafico.render_to_file('prueba.svg')
webbrowser.open('prueba.svg')

Si todo ha ido bien se abrirá tu navegador predeterminado y te mostrará la siguiente imagen:


grafico creado sin datos


Vamos a pararnos un momento para explicar el código. Aunque en teoría para renderizar el gráfico simplemente se podría usar grafico.render()  a la fecha de este post no lo he conseguido en la versión que uso de Debian o Ubuntu. No obtengo ningún error, pero tampoco se renderiza el gráfico. Así que he optado por pasar el gráfico renderizado a un archivo con grafico.renter_to_file('prueba.svg') y luego abrirlo con el navegador para visualizarlo. Para ello he importado la librería webbrowser y luego he utilizado el método open para abrir el grafico creado en el navegador. No obstante también se permite abrir directamente el grafico en el navegador usando grafico.render_in_browser(), si prefieres pero seguramente tendrás que instalar una librería dependiente (lxlm).

Otro inciso antes de seguir es que además de diagramas de barras también podemos usar muchos más tipos de gráficos como líneas, gráficos circulares, etc. Para más información consulta la documentación


Añadiendo algunos datos.


Para almacenar los datos vamos a utilizar las listas de Python. Puedes crearlas poniendo los datos separados por comas entre corchetes [ ]. 

Vamos a crear cuatro listas con datos para mostrar en nuestro gráfico.

Cada lista guardará el nombre de la nación y el número de medallas que ha ganado.

# Añadiendo datos
us = ['Estados Unidos', 2655]
gb = ['Gran Bretaña', 931]
fr = ['Francia', 772]
sp = ['España', 169]
Cuando guardas algo en una lista, cada uno de los elementos tiene un índice. Un índice es un número que nos dice la posición del elemento en la lista. Los índices comienzan en el 0 en vez de en el 1.

Puedes obtener cualquier elemento de una lista a partir de su índice. Por ejemplo, mi_lista[3] nos devolverá el cuarto elemento de esa lista, porque recuerda que el índice comienza en el cero. 

Utiliza los índices de tu lista y grafico.add() para mostrar los datos. El nombre del país que está en el primer elemento de la lista (indice 0) se utilizará como etiqueta de la categoría y la cantidad de medallas que es el segundo elemento de la lista (índice 1) determinará la altura de la barra.

# Añadiendo datos
us = ['Estados Unidos', 2655]
gb = ['Gran Bretaña', 931]
fr = ['Francia', 772]
sp = ['España', 169]

grafico.add(us[0], us[1])
grafico.add(gb[0], gb[1])
grafico.add(fr[0], fr[1])
grafico.add(sp[0], sp[1])

Ejecuta el código para ver el gráfico. 


gráfico creado con algunos datos

Si obtienes un mensaje de ERROR del tipo IndexError, es que tu código esta intentando obtener un valor desde un indice que no existe en la lista (por ejemplo us[2]). Para solucionarlo:

- comprueba cada línea grafico.add() y comprueba que solo estás utilizando los indices 0 y 1.

- comprueba las líneas donde creaste las listas. Verifica que cada lista tenga solo dos elementos, separados por una coma.

Ahora, introduciremos dos nuevos paises, añadiendo nuevas listas y luego las cargaremos en el gráfico usando grafico.add().

# Añadiendo datos
us = ['Estados Unidos', 2655]
gb = ['Gran Bretaña', 931]
fr = ['Francia', 772]
sp = ['España', 169]
ch = ['China', 634]
al = ['Alemania', 797]

grafico.add(us[0], us[1])
grafico.add(gb[0], gb[1])
grafico.add(fr[0], fr[1])
grafico.add(sp[0], sp[1])
grafico.add(ch[0], ch[1])
grafico.add(al[0], al[1])

Vuelve a ejecutar el código para actualizar el gráfico.


gráfico con más datos añadidos


Cargando los datos desde un archivo.


¡Nuestro gráfico tiene buena pinta! Pero, casi 150 naciones han competido en los juegos olimpico de verano. Para hacer un gráfico con todos, vamos a cargar sus datos desde un archivo lo que nos hará ahorrar un montón de tiempo en teclear datos.

Si vas a la carpeta del proyecto en Github encontrarás un archivo csv llamado medals.csv. Ábrelo y echa un vistazo a los datos que contiene.


imagen del archivo csv

Como ves en cada línea aparece el nombre del equipo, y el número de medallas que ha ganado hasta los últimos juegos olímpicos de verano de Tokio 2020. (Oro, plata, bronce y total de medallas)

Información: Archivos CSV
Los archivos CSV (Comma Separated Values) o archivos con valores separados
por comas, contienen datos en filas y columnas como en una tabla. Cada lí-
nea es una fila, en la que los datos (columnas) están separados por comas.

Pais, Abreviatura, Oro, Plata, Bronce, Total

United States,USA,1070,841,744,2655
Soviet Union,URS,395,319,296,1010
Great Britain,GBR,292,324,315,931
Germany,GER,239,267,291,797

Para hacer el gráfico tenemos que volcar la información de cada línea al programa que estamos haciendo, al igual que hicimos con las listas anteriormente.

Para ello vuelve al archivo donde tienes el código del programa y añade el siguiente código que nos permitirá cargar los datos del archivo en una variable, para ello utilizaremos "with open() as". Después mediante un bucle for imprimiremos los datos de cada línea.

El usar el bucle for hace que se repita el código. Así que cargaremos cientos de líneas con los equipos participantes y sus datos ¡con unas pocas líneas de código!

Añade el siguiente código.

with open('medals.csv', 'r') as lineas:
    for linea in lineas:
        print(linea)


¿Cómo se lee un archivo con Python?

Para leer un archivo de texto en Python debes abrir el archivo y leer su contenido. 

Cuando abras un archivo, utiliza los comandos with con as. Con esto te asegurarás de que una vez ejecutado el código que contiene, el archivo se cerrará automáticamente. El argumento dentro de open() en este caso 'medals.csv' es el nombre del archivo de texto que queremos abrir. 

Una vez que hemos cargado el archivo, tenemos dos opciones. La primera es volcarlo íntegramente en una variable y una segunda que es usar un bucle for para recorrer el archivo línea por línea.

La primera opción no la hemos usado en este caso pero sería algo como esto:

with open(nombre_archivo) as f:
  archivo_texto = f.read()
  # Hacer algo con el texto

La segunda opción es la que hemos usado nosotros para iterar sobre cada línea del código:

with open(nombre_archivo) as f:
  for línea_archivo in f:
    # hacer algo con la línea.

Si ejecutas ahora el código verás como cada línea tiene seis valores separados por comas.

United States,USA,1070,841,744,2655

Soviet Union,URS,395,319,296,1010

Great Britain,GBR,292,324,315,931

Germany,GER,239,267,291,797

France,FRA,231,256,285,772

People's Republic,of China,CHN,263,199,174,636

Italy,ITA,222,195,215,632

Australia,AUS,162,170,209,541

Hungary,HUN,182,156,177,515

Sweden,SWE,149,177,181,507

Japan,JPN,169,150,180,499

Cada cadena que imprime el bucle se compone de seis valores separados por comas. La función grafico.add() necesita cada una de esas piezas pero como entradas separadas. 

La función split() divide una cadena en una lista, al igual que las listas que hicimos al principio del post. Si usamos split(',') se creara una lista poniendo un nuevo elemento cada vez que encuentre una coma, es decir separa el texto en diferentes valores usando para ello la coma. 

Consejo: split() puede dividir una cadena en una lista usando como separador cualquier texto que se desee, no tiene porque ser una coma, puede ser un punto, una letra e incluso una palabra.

Modifica un poco el código para que recoja esto que hemos comentado:

with open('medals.csv', 'r') as lineas:
    for linea in lineas:
        dato = linea.split(',')
        print(dato)

Si lo ejecutas verás lo siguiente:

>>> %Run main.py
['United States', 'USA', '1070', '841', '744', '2655\n']
['Soviet Union', 'URS', '395', '319', '296', '1010\n']
['Great Britain', 'GBR', '292', '324', '315', '931\n']
['Germany', 'GER', '239', '267', '291', '797\n']
['France', 'FRA', '231', '256', '285', '772\n']
["People's Republic", 'of China', 'CHN', '263', '199', '174', '636\n']
['Italy', 'ITA', '222', '195', '215', '632\n']
['Australia', 'AUS', '162', '170', '209', '541\n']
['Hungary', 'HUN', '182', '156', '177', '515\n']
...

Como te habrás dado cuenta cada línea finaliza con "\n" al final. "\n" es normalmente invisible cuando se imprime un texto, por eso no lo has visto antes. Es un salto de línea, le dice al ordenador cuando imprime un texto, que se ha alcanzado el final de la línea.

Sin embargo como para hacer nuestro gráfico necesitamos el primer valor, el nombre del equipo, y el último, el número total de medallas, tenemos que quitar el salto de línea "\n". Para ello usaremos el método strip() que utilizado sin argumentos elimina los espacios en blanco y saltos de línea que pudiera haber tanto al principio como al final de la cadena.

El código sería de momento este:

with open('medals.csv', 'r') as lineas:
    for linea in lineas:
        linea = linea.strip()
        dato = linea.split(",")
        print(dato)

Salida:

>>> %Run main.py
['United States', 'USA', '1070', '841', '744', '2655']
['Soviet Union', 'URS', '395', '319', '296', '1010']
['Great Britain', 'GBR', '292', '324', '315', '931']
['Germany', 'GER', '239', '267', '291', '797']
['France', 'FRA', '231', '256', '285', '772']
["People's Republic", 'of China', 'CHN', '263', '199', '174', '636']
['Italy', 'ITA', '222', '195', '215', '632']
['Australia', 'AUS', '162', '170', '209', '541']

Antes de cargar los datos en el gráfico nos queda una cuestión. Todos los valores que nos pasa la cadena son de tipo string. Eso no nos importa para el nombre del equipo puesto que el primer argumento que le pasamos a grafico.add() es un texto para que lo use como etiqueta. Sin embargo para el número total de medallas necesitamos que el dato se un número entero. Podemos usar la función int() para pasar ese dato de tipo texto a número. 

Ten además en cuenta que el nombre del equipo es el primer elemento de la lista (indice 0)  y que el número total de medallas es el elemento seis (indice 5). Con esto ya podemos construir el grafico. El programa completo quedaría de la siguiente forma:

from pygal import Bar
import webbrowser

# Creando un gráfico
grafico = Bar(title="Medallas Olímpicas")

# Añadiendo datos
# us = ['Estados Unidos', 2655]
# gb = ['Gran Bretaña', 931]
# ch = ['China', 634]
# al = ['Alemania', 797]
# fr = ['Francia', 772]
# sp = ['España', 169]

# grafico.add(us[0], us[1])
# grafico.add(gb[0], gb[1])
# grafico.add(fr[0], fr[1])
# grafico.add(sp[0], sp[1])
# grafico.add(ch[0], ch[1])
# grafico.add(al[0], al[1])

with open('medals.csv', 'r') as lineas:
    for linea in lineas:
        linea = linea.strip()
        dato = linea.split(',')
        grafico.add(dato[0], int(dato[5]))
        
        
grafico.render_to_file('prueba.svg')
webbrowser.open('prueba.svg')

Ejecuta el código y mira como se crea el gráfico:


gráfico final del proyecto

¿Qué podemos hacer a mayores?

Para profundizar algo más en la forma de hacer gráficos, podemos cambiar la forma de representar los datos. 

Podríamos por ejemplo:

Crear un gráfico circular -  Para crear un gráfico circular en vez de un gráfico de barras solo tenemos que cambiar el código de importación, para usar Pie en vez de Bar. Una vez importada la creación o instancia del gráfico la haremos usando Pie.

gráfico circular




Puedes encontrar los enlaces a este proyecto en esta dirección de Github.

No hay comentarios:

Publicar un comentario