Como pintar una gráfica con matplolib a partir de un dataframe de Pandas

publicado por: Anonymous

Ante todo he de decir que no tengo muchos conocimientos de programación porque llevo sólo 1 mes con ello.
Tengo un dataframe obtenido a partir de un excel *xls en el que un campo “Barrio” refleja los barrios de Madrid y además tengo datos de densidades de población por año para cada barrio. (Dens_año)

Pongo por aquí el código con el que he obtenido el df a patir del excel original.

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
#CamposDens = ["Dens_2008","Dens_2009","Dens_2010","Dens_2011","Dens_2012","Dens_2013","Dens_2014","Dens_2015","Dens_2016","Dens_2017","Dens_2018"]
def DfTranXLS (excel):
    datos = pd.read_excel(excel)
    df=pd.DataFrame(datos)
    df = df.drop(df.columns[[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16]], axis=1)
    return df
print DfTranXLS(r"C:UsersEstebanDesktopTrabajo Python actualizadoH_Poblacion.xls") 

Necesito que alguien me explique cómo puedo pintar una gráfica que refleje la evolución de densidad para cada barrio con los años, sé que lo más fácil es definir una función con un parámetro barrio con el que llamar después a la función, pero no sé cómo hacerlo.

Gracias!

Edición 1

Añado enlace al excel original

https://www101.zippyshare.com/v/A6OwPfTU/file.html

Edición 2

gracias por tu explicación, y siento no haber comentado antes que trabajo en IDLE, pero mis limitados conocimientos hacen que no entienda muy bien la implicación de trabajar en un entorno u otro, aunque según me contó un amigo informático IDLE en el mundillo es de lo más rudimentario que hay ahora mismo. En fin estoy intentando escribir el código para que pinte la gráfica pero no me sale:

import pandas as pd
import matplotlib.pyplot as plt

def grafica(data, Barrio):

    info_barrios = data.loc[data['Barrio'] == Barrio]
    info_barrios = info_barrios.drop(info_barrios.columns[[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16]], axis=1)
    info_barrios = info_barrios.set_index("Barrio").T     # La T es de "Transpose", cambia filas por columnas
    info_barrios.index=list(range(2008, 2019))  # Reasignar el índice para que sea numérico
    print info_barrios
    return info_barrios

Barrios_data = pd.read_excel("C:UsersEstebanDesktopTrabajo Python 
actualizadoH_Poblacion.xls")

print ("Llamada Moncloa")
Moncloa_grafica = grafica(Barrios_data,"MONCLOA")
plt.plot(Moncloa_grafica)
plt.show()

El error que sale es:

Traceback (most recent call last):
File "C:UsersEstebanDesktopTrabajo Python actualizadografica4.py", line 17, in <module>
    plt.plot(Moncloa_grafica)
File "C:Python27ArcGIS10.5libsite-packagesmatplotlibpyplot.py", line 3153, in plot
    ret = ax.plot(*args, **kwargs)
File "C:Python27ArcGIS10.5libsite-packagesmatplotlib__init__.py", line 1819, in inner
    return func(ax, *args, **kwargs)
File "C:Python27ArcGIS10.5libsite-packagesmatplotlibaxes_axes.py", line 1382, in plot
    for line in self._get_lines(*args, **kwargs):
File "C:Python27ArcGIS10.5libsite-packagesmatplotlibaxes_base.py", line 381, in _grab_next_args
    for seg in self._plot_args(remaining, kwargs):
File "C:Python27ArcGIS10.5libsite-packagesmatplotlibaxes_base.py", line 369, in _plot_args
    seg = func(x[:, j % ncx], y[:, j % ncy], kw, kwargs)
ZeroDivisionError: integer division or modulo by zero
>>>

No entiendo de dónde saca el error de división por cero, si se supone que estoy pintando una gráfica… siento que estoy cerca, si me puedes ayudar t lo agradezco

solución

De mano necesitas cambiar la organización del dataframe, para que sea más fácil de graficar. Te interesa que los barrios sean las columnas y los diferentes años las filas. Esto es fácil de conseguir:

import pandas as pd

df = pd.read_excel("H_Poblacion.xls")
df = df.drop(df.columns[[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16]], axis=1)
df = df.set_index("Barrio").T     # La T es de "Transpose", cambia filas por columnas
df.index=list(range(2008, 2019))  # Reasignar el índice para que sea numérico

Ahora el dataframe ya tiene la estructura que necesitamos:

Dataframe

Basta seleccionar qué columnas queremos ver (podemos especificar varias, en una lista), y pedirle a pandas que haga el plot(). No necesitas importar matplotlib (pandas lo hace por tí). Si queremos manipular aspectos de la gráfica, como la posición de la leyenda, el etiquetado de los ejes, etc. podemos recoger el resultado devuelto por DataFrame.plot(), que será un “axis” matplotlib sobre el que podemos realizar las operaciones necesarias.

Por ejemplo:

subset = ["EMBAJADORES", "COMILLAS", "UNIVERSIDAD", "LOS ROSALES", "ARAVACA", ]
ax = df[subset].plot(marker="o")
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))

Produce:

Plot
Si prefieres un gráfico de barras, basta usar kind="bar" en el plot:

ax = df[subset].plot(kind="bar")
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))

De barras

Actualización

Respondiendo a un comentario del usuario. Parece que el problema no era tanto cómo crear una función para hacer un gráfico de un DataFrame, sino más bien cómo lograr mostrar la gráfica desde idle.

La verdad es que yo siempre he trabajado con Notebooks Jupyter, donde todo es más sencillo porque con sólo importar pandas todo está ya configurado para mostar las gráficas en el propio notebook. De no hacerlo así la cosa se complica un poco.

El mecanismo general sería:

  • Importar matplotlib
  • Configurar el backend que deseemos usar. El backend es el que al final convierte las gráficas en algo visible, ya sea en una imagen PNG, o en una ventana interactiva en la que se pueda hacer zoom, o en un mini-servidor web que ofrezca una página en la que ver la gráfica, etc. Qué backends tienes disponibles depende entre otras cosas del operativo en que estés y de qué otras bibliotecas tengas instaladas. Por ejemplo, si tienes instalado Qt5, puedes usarlo como backend (sería Qt el encargado de crear y mostrar una ventana con la gráfica)
  • Importar matplotlib.pyplot. El orden es crucial. El backend tiene que estar ya configurado (en el paso anterior) antes de importar pyplot.

El resto ya sería fácil. La gráfica puede crearse directamente con pandas como mostré más arriba, y la única diferencia es que hay que invocar explícitamente a matplotlib.pyplot.show() para que el backend haga visible el resultado.

Un ejemplo mínimo, que usa TkAgg como backend (que creo que estaría disponible en todos los operativos, aunque sólo lo he probado en Mac), y que usa pandas para mostrar una dataframe trivial (no he querido complicarlo más, pero puedes cambiar el dataframe por lo antes explicado), sería así:

import pandas as pd
import matplotlib
matplotlib.use("TkAgg")  # <---- Especificar el backend

import matplotlib.pyplot as plt  # <--- Ahora ya podemos importar pyplot

# Crear un dataframe trivial y mostrar la gráfica
df = pd.DataFrame([2,4,1])
df.plot(kind="bar")
plt.show()

Eso hace aparecer la gráfica en otra ventana:

idle

Espero que esto sirva también cuando idle es usado desde Arcgis, como es tu caso. Desconozco esa plataforma.

Actualización 2

Tratando de organizar un poco mejor el código que pones en tu Edicion2, propongo separarlo en dos funciones. Una que lee la excel y la “acondiciona”, para dejarla de modo que las columnas sean los barrios y las filas los años; otra que pinte una gráfica de un barrio dado (para lo cual sólo tiene que seleccionar qué columna pintar). Así:

import pandas as pd
import matplotlib
matplotlib.use("TkAgg")  # <---- Especificar el backend
import matplotlib.pyplot as plt

def leer_excel(filename):
  info_barrios = pd.read_excel(filename)
  info_barrios = info_barrios.drop(info_barrios.columns[[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16]], axis=1)
  info_barrios = info_barrios.set_index("Barrio").sort_index().T     # La T es de "Transpose", cambia filas por columnas
  info_barrios.index=list(range(2008, 2019))  # Reasignar el índice para que sea numérico
  return info_barrios

def grafica(data, Barrio):
  plt.plot(data[Barrio])
  plt.show()

df = leer_excel("H_Poblacion.xls")
grafica(df, "ATOCHA")

Esto me funciona perfectamente. Usando "MONCLOA" en cambio rompe, porque ¡MONCLOA no está entre los datos! Puedes ver qué barrios están si haces un print list(df.columns) y lo comprobarás.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *