Ce notebook présente l'utilisation de pandas
et
de matplotlib
pour la lecture de données en python
et la constructions de quelques représentations graphiques avec matplotlib.
Les données utilisées dans cet exemple sont issues de la base de données ouverte de
la Communauté d'Agglomération de Pau-Pyrénées (CAPP) opendata.agglo-pau.fr.
In [1]:
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
%matplotlib inline
Les données proviennent de http://opendata.agglo-pau.fr/index.php/fiche?idQ=27
Lors du téléchargement de l'archive, le fichier csv contient les données et un fichiers excel décrit le contenu de chaque colonne.
Ici, le fichier csv est lu directement avec la fonction read_csv
de pandas, en précisant que le séparateur est un point virgule. Cette fonction retourne un objet DataFrame
qui s'apparente à un tableau de données. On précise également que LIBGEO
, le nom de la commune, sera utilisé comme index de la DataFrame
de pandas. Chaque ligne portera alors le nom de la ville correspondante.
In [2]:
df = pd.read_csv("Evolution_et_structure_de_la_population/Evolution_structure_population.csv", sep=";")
df = df.set_index("libgeo")
df
Out[2]:
Premièrement nous allons construire un graphique sous forme de barres horizontales, représentant la population dans chaque ville de l'aglomération de Pau-Pyrénées en 2011.
Nous utiliserons un diagramme en barre horizontale avec la fonction barh
de matplotlib (exemple).
Commençons par extraire la colonne qui nous intéresse (P11_POP
) et classons les valeurs par ordre croissant.
In [3]:
pop11 = df["p11_pop"]
pop11 = pop11.sort_values(ascending=True)
pop11
Out[3]:
Construisons maintenant le graphique avec les données ci-dessus.
In [4]:
# figure
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
ax.set_title("Population de la CAPP en 2011", fontsize=20)
# bar plot
ax.barh(
# position et longueur des barres
bottom=range(pop11.count()),
width=pop11,
# labels
align="center",
tick_label=pop11.index,
# couleurs et traits
color="RoyalBlue",
linewidth=0
)
# format axis
ax.set_frame_on(False)
ax.set_xticks([])
ax.tick_params("both", length=0)
ax.vlines(0, -1, pop11.count(), color="gray", linewidth=4)
# add the value at the end of the bar
for y, pop in enumerate(pop11):
ax.annotate(
# texte
"%.0f" % pop,
# position
xy=(pop, y),
xytext=(5, -4),
textcoords="offset points",
# format
fontsize=14,
color="RoyalBlue"
)
fig.savefig("barh_pop.png", dpi=300)
Pour faire ce graphique on va utiliser la librairie squarify
. La superficie des rectangles représentera la superficie de la commune. Une échelle de couleur donnera la population de la commune.
In [5]:
import squarify
Extraction de la superficie des communes et de la population en 2011. Le tableau est trié par ordre décroissant de la superficie.
In [6]:
df2 = df[["superf", "p11_pop"]]
df2 = df2.sort_values(by="superf", ascending=False)
df2
Out[6]:
Superficie et population de Pau :
In [7]:
print("Pau: superficie = %d km2, population = %d\n" % (df2["superf"]["PAU"], df2["p11_pop"]["PAU"]))
Représentation en Treemaps avec les fonctions inclues dans squarify
.
In [8]:
x = 0.
y = 0.
width = 100.
height = 100.
cmap = matplotlib.cm.viridis
# color scale on the population
# min and max values without Pau
mini, maxi = df2.drop("PAU").p11_pop.min(), df2.drop("PAU").p11_pop.max()
norm = matplotlib.colors.Normalize(vmin=mini, vmax=maxi)
colors = [cmap(norm(value)) for value in df2.p11_pop]
colors[1] = "#FBFCFE"
# labels for squares
labels = ["%s\n%d km2\n%d hab" % (label) for label in zip(df2.index, df2.superf, df2.p11_pop)]
labels[11] = "MAZERES-\nLEZONS\n%d km2\n%d hab" % (df2["superf"]["MAZERES-LEZONS"], df2["p11_pop"]["MAZERES-LEZONS"])
# make plot
fig = plt.figure(figsize=(12, 10))
fig.suptitle("Population et superficie des communes de la CAPP", fontsize=20)
ax = fig.add_subplot(111, aspect="equal")
ax = squarify.plot(df2.superf, color=colors, label=labels, ax=ax, alpha=.7)
ax.set_xticks([])
ax.set_yticks([])
ax.set_title("L'aire de chaque carré est proportionnelle à la superficie de la commune\n", fontsize=14)
# color bar
# create dummy invisible image with a color map
img = plt.imshow([df2.p11_pop], cmap=cmap)
img.set_visible(False)
fig.colorbar(img, orientation="vertical", shrink=.96)
fig.text(.76, .9, "Population", fontsize=14)
fig.text(.5, 0.1,
"Superficie totale %d km2, Population de la CAPP : %d hab" % (df2.superf.sum(), df2.p11_pop.sum()),
fontsize=14,
ha="center")
fig.text(.5, 0.07,
"Source : http://opendata.agglo-pau.fr/",
fontsize=14,
ha="center")
fig.savefig("treemap_capp_pau.png", dpi=300)
Dans ce graphique nous allons simplement représenter le nombre de naissances et de décés à Pau entre 1999 et 2011. C'est un graphique très simple à réaliser avec pandas. Nous allons voir tout d'abord comment extraire les données puis nous ferons un premier graphique basique avec la fonction plot()
de pandas. Ensuite, nous ajouterons une courbe de tendance linéaire avec lineregress()
de scipy.
Tout d'abord nous devons extraire les colonnes NAISXX
et DECEXX
du tableau global pour la ligne concernant Pau.
In [9]:
# noms des colonnes:
years = [99] + list(range(0, 12))
naissance = ["nais%02d" % y for y in years]
deces = ["dece%02d" % y for y in years]
# nouvelle DataFrame avec les deces et les naissances à Pau en fonction des années
df4 = pd.DataFrame(
data={
"naissance": df.loc["PAU", naissance].values,
"deces": df.loc["PAU", deces].values
},
index=[1999 + i for i in range(0, 13)]
)
df4
Out[9]:
À partir de ce type de tableau, il est très simple de tracer des courbes avec la fonction plot()
de pandas
. Les arguments sont du même type que ceux de matplotlib :
In [10]:
df4.plot(
marker="o",
linestyle="dashed",
title="Naissances et décés à Pau entre 1999 et 2011",
figsize=(8, 6),
fontsize=16,
xlim=(1998, 2012)
)
Out[10]:
Ajoutons maintenant une courbe de tendance et ajoutons les données au tableau (bien que deux points seulement auraient suffit) :
In [11]:
from scipy.stats import linregress
# pour les naissances
p_naissance, i_naissance, *others = linregress(x=df4.index, y=df4.naissance)
df4["trend_naissance"] = p_naissance * df4.index + i_naissance
# pour les décés
p_deces, i_deces, *others = linregress(x=df4.index, y=df4.deces)
df4["trend_deces"] = p_deces * df4.index + i_deces
df4
Out[11]:
In [12]:
colors = sns.color_palette("husl", 2)
# figure
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111)
ax.set_title("Naissances et décés à Pau entre 1999 et 2011", color="#555555")
# plot the differents quantities
ax.plot(df4.index, df4.naissance, marker="o", label="Naissances", linestyle="--", linewidth=.5, color=colors[0])
ax.plot(df4.index, df4.deces, marker="o", label="Décés", linestyle="--", linewidth=.5, color=colors[1])
ax.plot(df4.index, df4.trend_naissance, label="", color=colors[0])
ax.plot(df4.index, df4.trend_deces, label="", color=colors[1])
# format and style
ax.set_xlabel("Année")
ax.set_ylabel("Nombre de naissances ou décés")
ax.legend()
fig.savefig("xy_pop.png", dpi=300)
Le fichiers de données de la CAPP contient aussi les catégorie socio-professionnelle pour chaque commune. Nous allons les représenter avec un diagramme de type camembert.
Commençons par regrouper les données dans une nouvelle table et faisons la somme sur toutes les communes.
In [13]:
columns = {
"c10_pop15p_cs1": "agriculteurs",
"c10_pop15p_cs2": "Artisans",
"c10_pop15p_cs3": "Cadres",
"c10_pop15p_cs4": "Intermédiaires",
"c10_pop15p_cs5": "Employés",
"c10_pop15p_cs6": "Ouvriers",
"c10_pop15p_cs7": "Retraités",
"c10_pop15p_cs8": "Autres"
}
df_cat = df[list(columns.keys())]
df_cat = df_cat.rename(columns=columns)
# add the sum over CAPP
df_cat.loc["CAPP"] = df_cat.sum(axis=0)
df_cat["total"] = df_cat.sum(axis=1)
df_cat
Out[13]:
Construction du graphique :
In [14]:
fig = plt.figure(figsize=(18, 10))
fig.suptitle("Catégories socio-professionnelles de la CAPP en 2010\nPau et Billère", fontsize=20, color="#444444")
width = .3
# color scale
colors = ["#F4A460", '#E24A33', '#348ABD', '#988ED5', '#777777', '#FBC15E', '#8EBA42', '#FFB5B8']
# PAU et CAPP
ax1 = fig.add_subplot(121, aspect="equal")
pau_pie = ax1.pie(
# data
df_cat.loc["PAU"].drop("total"),
# wedges
colors=colors,
radius=1,
wedgeprops={"width": width, "linewidth": 1},
# labels
autopct="%4.1f%%",
pctdistance=.85
)
capp_pie = ax1.pie(
df_cat.loc["CAPP"].drop("total"),
colors=colors,
radius=1 - width,
wedgeprops={"width": width, "linewidth": 1},
autopct="%4.1f%%",
pctdistance=.75
)
ax1.set_title("Pau", fontsize=18, color="#555555")
ax1.text(.1, -.1, "CAPP", fontsize=18, color='#555555')
ax1.text(.8, -.7, "Pau", size=18, color='#555555')
# Billere et CAPP
ax2 = fig.add_subplot(122, aspect="equal")
bill_pie = ax2.pie(
df_cat.loc["BILLERE"].drop("total"),
colors=colors,
radius=1,
wedgeprops={"width": width, "linewidth": 1},
autopct="%4.1f%%",
pctdistance=.85
)
capp_pie = ax2.pie(
df_cat.loc["CAPP"].drop("total"),
colors=colors,
radius=1 - width,
wedgeprops={"width": width, "linewidth": 1},
autopct="%4.1f%%",
pctdistance=.75
)
ax2.set_title("Billère", fontsize=18, color="#555555")
ax2.text(.1, -.1, "CAPP", size=18, color='#555555')
ax2.text(.8, -.7, "Billère", size=18, color='#555555')
# legende
fig.legend(pau_pie[0], df_cat.columns.values, fontsize=16)
fig.subplots_adjust(wspace=0)
fig.savefig("capp_pie.png", dpi=300)