{ "cells": [ { "cell_type": "markdown", "id": "oZ511soZ8yH3", "metadata": { "id": "oZ511soZ8yH3" }, "source": [ "# **Visualisation de données sur Seaborn**\n", "\n", "---\n", "\n", "\n", "---\n", "\n" ] }, { "cell_type": "markdown", "id": "PMlRa4bO9igp", "metadata": { "id": "PMlRa4bO9igp" }, "source": [ "# Introduction\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "00ec26b2", "metadata": { "id": "00ec26b2" }, "source": [ "Afin d’utiliser seaborn, nous allons d’abord importer les bibliothèques nécessaires." ] }, { "cell_type": "code", "execution_count": null, "id": "a0640849", "metadata": { "id": "a0640849" }, "outputs": [], "source": [ "import seaborn as sns\n", "import seaborn.objects as so\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np\n", "from matplotlib.patches import Ellipse" ] }, { "cell_type": "markdown", "id": "8a76a386", "metadata": { "id": "8a76a386" }, "source": [ "Nous allons charger un jeu de données parmi ceux mis gratuitement à disposition par seaborn." ] }, { "cell_type": "code", "execution_count": null, "id": "6c0ba412", "metadata": { "id": "6c0ba412" }, "outputs": [], "source": [ "data=sns.load_dataset(\"penguins\")\n", "print(data.isnull())\n", "print(data.isnull().any())" ] }, { "cell_type": "markdown", "id": "e78894dd", "metadata": { "id": "e78894dd" }, "source": [ "Si nous voulons travailler avec des points de données contenant toutes les variables, nous pouvons utiliser la fonction dropna afin de supprimer les points de données incomplets." ] }, { "cell_type": "code", "execution_count": null, "id": "20cfdb49", "metadata": { "id": "20cfdb49" }, "outputs": [], "source": [ "data.dropna(subset=[\"body_mass_g\"])" ] }, { "cell_type": "markdown", "id": "yu0zO1IZ9zCw", "metadata": { "id": "yu0zO1IZ9zCw" }, "source": [ "# Graphiques de données quantitatives\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "363c0bdd", "metadata": { "id": "363c0bdd" }, "source": [ "Nous allons d'abord travailler avec les relplots. Ce sont des graphiques permettant de réaliser des nuages de points. Seaborn nous permet de choisir les variables des axes x et y, et d'ajouter la représentation d'autres variables grâce aux paramètres hue, style et size. Le paramètre col permet de séparer les données en différents graphiques en fonction d'une variable spécifique." ] }, { "cell_type": "code", "execution_count": null, "id": "6188b0a4", "metadata": { "id": "6188b0a4" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.relplot(data=data,x=\"bill_length_mm\",y=\"bill_depth_mm\",hue=\"species\",style=\"sex\",size=\"body_mass_g\",col=\"island\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "05c34982", "metadata": { "id": "05c34982" }, "source": [ "Nous avons 3 graphiques, un pour chaque île. La couleur représente l’espèce, le type de point représente le sexe et la taille du point représente la masse corporelle.\n", "\n", "Si nous voulons ajouter une représentation statistique de nos données en plus des points, nous pouvons utiliser Matplotlib pour tracer une ellipse de confiance. La fonction suivante, add_confidence_ellipse, utilise Ellipse de Matplotlib afin de la tracer. Le paramètre n_std de la fonction nous permet de choisir l’intervalle de confiance souhaité." ] }, { "cell_type": "code", "execution_count": null, "id": "d0cf097c", "metadata": { "id": "d0cf097c" }, "outputs": [], "source": [ "df = sns.load_dataset(\"penguins\")\n", "df = df[[\"species\", \"bill_length_mm\", \"body_mass_g\"]].dropna()\n", "\n", "g = sns.relplot(\n", " data=df,\n", " x=\"bill_length_mm\",\n", " y=\"body_mass_g\",\n", " hue=\"species\",\n", " kind=\"scatter\",\n", " height=5\n", ")\n", "ax = g.ax\n", "\n", "def add_confidence_ellipse(x, y, ax, n_std=2.0, **kwargs):\n", " cov = np.cov(x, y)\n", " mean = np.mean(x), np.mean(y)\n", " eigvals, eigvecs = np.linalg.eigh(cov)\n", " order = eigvals.argsort()[::-1]\n", " eigvals, eigvecs = eigvals[order], eigvecs[:, order]\n", " angle = np.degrees(np.arctan2(*eigvecs[:, 0][::-1]))\n", " width, height = 2 * n_std * np.sqrt(eigvals)\n", " ellipse = Ellipse(\n", " xy=mean,\n", " width=width,\n", " height=height,\n", " angle=angle,\n", " fill=False,\n", " **kwargs\n", " )\n", " ax.add_patch(ellipse)\n", "\n", "palette = sns.color_palette()\n", "\n", "for i, species in enumerate(df[\"species\"].unique()):\n", " subset = df[df[\"species\"] == species]\n", " add_confidence_ellipse(\n", " subset[\"bill_length_mm\"],\n", " subset[\"body_mass_g\"],\n", " ax,\n", " edgecolor=palette[i],\n", " linewidth=2\n", " )\n", "\n", "ax.set_xlabel(\"Bill length (mm)\")\n", "ax.set_ylabel(\"Body mass (g)\")\n", "ax.set_title(\"95% Confidence Ellipse by Species — Penguins\")\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "620810b1", "metadata": { "id": "620810b1" }, "source": [ "On peut choisir le type « line » afin de représenter les données avec des lignes." ] }, { "cell_type": "code", "execution_count": null, "id": "abcf072d", "metadata": { "id": "abcf072d" }, "outputs": [], "source": [ "df = sns.load_dataset(\"penguins\")\n", "sns.relplot(data=df,x=\"bill_length_mm\",y=\"bill_depth_mm\",hue=\"species\",style=\"sex\",col=\"island\",kind=\"line\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "dac5e185", "metadata": { "id": "dac5e185" }, "source": [ "Les données ne sont pas les plus adaptées à l’utilisation du type « line », mais on remarque que le paramètre size n’est plus utilisé, car il ne fonctionne pas avec les lignes." ] }, { "cell_type": "markdown", "id": "wYNdo3mWDDD5", "metadata": { "id": "wYNdo3mWDDD5" }, "source": [ "On peut utiliser la fonction displot de Seaborn afin de tracer la distribution statistique de nos données." ] }, { "cell_type": "code", "execution_count": null, "id": "H4aqV1o_zONV", "metadata": { "id": "H4aqV1o_zONV" }, "outputs": [], "source": [ "sns.displot(data=data, x=\"bill_length_mm\", rug=True, hue=\"sex\", bins=20)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "M4Y41U1ozeUw", "metadata": { "id": "M4Y41U1ozeUw" }, "source": [ "Par exemple, avec kind=\"kde\", on obtient une estimation de densité par noyau (kernel density estimation) des données. Le paramètre rug permet d’afficher les points de données individuels sur l’axe. Le paramètre bins permet de choisir le nombre de barres affichées. Ainsi, un nombre plus élevé de bins augmente la précision de la distribution représentée." ] }, { "cell_type": "code", "execution_count": null, "id": "eba75690", "metadata": { "id": "eba75690" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.displot(data=data,x=\"bill_length_mm\", rug=True, hue=\"sex\", kind=\"kde\")\n", "plt.show()\n" ] }, { "cell_type": "markdown", "id": "5a4557a8", "metadata": { "id": "5a4557a8" }, "source": [ "Si nous attribuons une variable à l’axe y, on obtient un graphique KDE en 2D. Il fonctionne essentiellement comme une courbe de niveau. Chaque courbe correspond à des points de données ayant une densité de probabilité similaire. Le centre d’un ensemble de courbes correspond à une zone de forte densité." ] }, { "cell_type": "code", "execution_count": null, "id": "36fb9c95", "metadata": { "id": "36fb9c95" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.displot(data=data,x=\"bill_length_mm\", y=\"bill_depth_mm\", rug=True, hue=\"sex\", kind=\"kde\")\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "id": "472dcabf", "metadata": { "id": "472dcabf" }, "source": [ "L’autre type de graphique de distribution est la fonction de distribution empirique (ECDF). Cette distribution est univariée, donc seul l’axe des x doit être défini." ] }, { "cell_type": "code", "execution_count": null, "id": "8bfcab9d", "metadata": { "id": "8bfcab9d" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.displot(data=data, x=\"body_mass_g\", rug=True, hue=\"sex\", kind=\"ecdf\", row=\"species\", col=\"sex\", height=5)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "8ChAwF7wFGL3", "metadata": { "id": "8ChAwF7wFGL3" }, "source": [ "Comme prévu, nous avons 3 espèces et elles sont assignées aux lignes, donc nous avons 3 lignes, et nous avons 2 catégories de sexe, donc nous avons 2 colonnes." ] }, { "cell_type": "markdown", "id": "378ed865", "metadata": { "id": "378ed865" }, "source": [ "Un autre type de graphique est le boxplot, un outil statistique classique. Le paramètre dodge permet de s’assurer que les différentes boîtes ne se chevauchent pas." ] }, { "cell_type": "code", "execution_count": null, "id": "033dc1c0", "metadata": { "id": "033dc1c0" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.boxplot(data=data, x=\"bill_length_mm\", hue=\"island\", dodge=True, width=0.5)\n", "plt.show()\n", "\n" ] }, { "cell_type": "markdown", "id": "DO8wl8D1FZIu", "metadata": { "id": "DO8wl8D1FZIu" }, "source": [ "Avec l’utilisation du paramètre dodge, les graphiques ne se chevauchent pas. On peut vérifier cela en mettant dodge à False." ] }, { "cell_type": "markdown", "id": "64ebd4b1", "metadata": { "id": "64ebd4b1" }, "source": [ "Le paramètre gap permet de contrôler la distance entre les boîtes, et le paramètre log_scale permet d’activer l’échelle logarithmique." ] }, { "cell_type": "code", "execution_count": null, "id": "fb8f7460", "metadata": { "id": "fb8f7460" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.boxplot(data=data, x=\"bill_length_mm\", hue=\"island\", dodge=True, width=0.5, gap=0.1, log_scale=True)\n", "plt.show()\n" ] }, { "cell_type": "markdown", "id": "c091c72e", "metadata": { "id": "c091c72e" }, "source": [ "Un autre outil statistique classique est le violin plot. Le paramètre inner permet de contrôler la représentation des données dans le graphique. Le paramètre split permet de superposer deux violin plots différents en un seul, puisqu’ils sont symétriques." ] }, { "cell_type": "code", "execution_count": null, "id": "f97f5700", "metadata": { "id": "f97f5700" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.violinplot(data=data, x=\"bill_length_mm\", hue=\"sex\", dodge=True, linewidth=3, split=True, inner=\"point\")\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "id": "436f570f", "metadata": { "id": "436f570f" }, "outputs": [], "source": [ "data = sns.load_dataset(\"penguins\")\n", "sns.violinplot(data=data, x=\"bill_length_mm\", hue=\"sex\",dodge=True,linewidth=3, split=True, inner=\"box\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "c88cad20", "metadata": { "id": "c88cad20" }, "source": [ "Les regplots sont des outils permettant de réaliser une régression sur des points de données, avec un intervalle d’incertitude visible autour de la courbe. Ici, par exemple, nous sommes confiants à 70 % que la vraie courbe se situe dans l’intervalle représenté sur le graphique." ] }, { "cell_type": "code", "execution_count": null, "id": "92d5c163", "metadata": { "id": "92d5c163" }, "outputs": [], "source": [ "sns.regplot(data=data, x=\"bill_length_mm\",y=\"bill_depth_mm\", ci=70)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "bce25baa", "metadata": { "id": "bce25baa" }, "source": [ "Différents types de régression sont disponibles, ici par exemple le type LOWESS." ] }, { "cell_type": "code", "execution_count": null, "id": "42e18e0e", "metadata": { "id": "42e18e0e" }, "outputs": [], "source": [ "sns.regplot(data=data, x=\"bill_length_mm\", y=\"bill_depth_mm\",\n", " ci=99, lowess=True)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "91602aa3", "metadata": { "id": "91602aa3" }, "source": [ "On peut choisir une régression robuste, qui est plus précise, mais aussi plus coûteuse en termes de calcul." ] }, { "cell_type": "code", "execution_count": null, "id": "9e59df9c", "metadata": { "id": "9e59df9c" }, "outputs": [], "source": [ "sns.lmplot(data=data, x=\"bill_length_mm\", y=\"bill_depth_mm\", ci=95, hue=\"island\", robust=True, col=\"sex\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "b91b2b75", "metadata": { "id": "b91b2b75" }, "source": [ "Une autre représentation disponible est la heatmap, qui nécessite une configuration spécifique des données, que les pivots nous permettent d’obtenir. L’index correspond à l’axe des y, les colonnes à l’axe des x, et les valeurs à la variable que nous cherchons à analyser. Nous allons utiliser un autre jeu de données, glue, qui représente les scores de modèles d’IA sur différentes tâches." ] }, { "cell_type": "code", "execution_count": null, "id": "e7025494", "metadata": { "id": "e7025494" }, "outputs": [], "source": [ "glue=sns.load_dataset(\"glue\").pivot(index=\"Model\",columns=\"Task\",values=\"Score\")\n", "sns.heatmap(glue)" ] }, { "cell_type": "markdown", "id": "3424b97f", "metadata": { "id": "3424b97f" }, "source": [ "On peut choisir la plage de valeurs utilisée pour la heatmap avec vmin et vmax, ainsi que sélectionner une colormap et les couleurs des lignes." ] }, { "cell_type": "code", "execution_count": null, "id": "a5910782", "metadata": { "id": "a5910782" }, "outputs": [], "source": [ "sns.heatmap(glue,cmap=\"viridis\",annot=True,vmin=20,vmax=80,linecolor=\"red\",linewidths=0.1)\n" ] }, { "cell_type": "markdown", "id": "31787103", "metadata": { "id": "31787103" }, "source": [ "Pour les besoins du clustering, nous avons la clustermap. Pour effectuer un clustering, il est nécessaire de travailler uniquement avec des valeurs numériques." ] }, { "cell_type": "code", "execution_count": null, "id": "f06e2421", "metadata": { "id": "f06e2421" }, "outputs": [], "source": [ "iris = sns.load_dataset(\"iris\")[:100]\n", "species = iris.pop(\"species\")\n", "sns.clustermap(iris)" ] }, { "cell_type": "markdown", "id": "3266aa33", "metadata": { "id": "3266aa33" }, "source": [ "On peut utiliser le paramètre row_colors afin de réintroduire les espèces que nous avions retirées des données. Cela permet de vérifier si les espèces sont effectivement proches les unes des autres dans le clustering, sachant que nous avons accès à différentes méthodes de clustering et que les résultats peuvent varier selon celles-ci. Les paramètres method et metric permettent d’essayer différents types de clustering. Ensuite, on trouve des paramètres visuels tels que dendrogram_ratio, figsize et cbar_pos. Le paramètre z_score permet de choisir si l’on souhaite calculer le z-score sur les lignes ou sur les colonnes." ] }, { "cell_type": "code", "execution_count": null, "id": "072f091c", "metadata": { "id": "072f091c" }, "outputs": [], "source": [ "lut = dict(zip(species.unique(), \"rbg\"))\n", "row_colors = species.map(lut)\n", "sns.clustermap(iris,row_cluster=True,dendrogram_ratio=(0.3,0.1),row_colors=row_colors,method=\"weighted\",metric=\"correlation\",z_score=1,annot=True,figsize=(7,12),cbar_pos=(0,0.1,0.02,0.8))" ] }, { "cell_type": "markdown", "id": "wMbexlD5-HD5", "metadata": { "id": "wMbexlD5-HD5" }, "source": [ "# Multiple graphics on a figure\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "725f13f6", "metadata": { "id": "725f13f6" }, "source": [ "Seaborn permet une représentation visuelle facile de différents types de graphiques sur une même figure. Par exemple, on a le jointplot pour tracer une figure en deux dimensions, comme une KDE 2D, avec les KDE unidimensionnelles correspondantes sur chaque axe. La deuxième partie du code permet de tracer les points de données." ] }, { "cell_type": "code", "execution_count": null, "id": "27a7919a", "metadata": { "id": "27a7919a" }, "outputs": [], "source": [ "g=sns.jointplot(data=data, x=\"bill_length_mm\", y=\"bill_depth_mm\",\n", " kind=\"kde\", hue=\"species\")\n", "\n", "for species in data[\"species\"].unique():\n", " subset = data[data[\"species\"] == species]\n", " g.ax_joint.scatter(\n", " subset[\"bill_length_mm\"],\n", " subset[\"bill_depth_mm\"],\n", " s=subset[\"body_mass_g\"]/500,\n", " label=species,\n", " alpha=0.7)" ] }, { "cell_type": "markdown", "id": "050fac76", "metadata": { "id": "050fac76" }, "source": [ "JointGrid permet de faire les mêmes choses que JointPair, mais avec un contrôle plus poussé sur la figure. On peut par exemple choisir différents types de graphiques pour le tracé 2D et les tracés 1D. À noter que l’on peut utiliser les paramètres propres au type de graphique choisi, comme fill=True pour un kdeplot." ] }, { "cell_type": "code", "execution_count": null, "id": "3bdd9b16", "metadata": { "id": "3bdd9b16" }, "outputs": [], "source": [ "g5 = sns.JointGrid(data=data, x=\"bill_length_mm\", y=\"bill_depth_mm\",\n", " hue=\"species\")\n", "g5.plot_joint(sns.scatterplot)\n", "g5.plot_marginals(sns.kdeplot, fill=True)" ] }, { "cell_type": "markdown", "id": "8c2153cc", "metadata": { "id": "8c2153cc" }, "source": [ "Un autre type de représentation utile est le pairplot. Il permet de créer une figure contenant des graphiques correspondant à toutes les combinaisons de variables du jeu de données. Le paramètre kind permet de choisir les graphiques marginaux, et diag_kind ceux de la diagonale." ] }, { "cell_type": "code", "execution_count": null, "id": "09092554", "metadata": { "id": "09092554" }, "outputs": [], "source": [ "data=sns.load_dataset(\"penguins\")\n", "sns.pairplot(data=data, hue=\"species\",kind=\"kde\",diag_kind=\"hist\")" ] }, { "cell_type": "markdown", "id": "3b6f885c", "metadata": { "id": "3b6f885c" }, "source": [ "Comme JointGrid, PairGrid permet de faire la même chose que PairPlot, mais avec davantage de contrôle. On peut par exemple choisir le type de graphiques que l’on souhaite pour la diagonale, la partie inférieure et la partie supérieure de la figure." ] }, { "cell_type": "code", "execution_count": null, "id": "6648da1a", "metadata": { "id": "6648da1a" }, "outputs": [], "source": [ "g = sns.PairGrid(data, hue=\"species\")\n", "g.map_upper(sns.histplot)\n", "g.map_lower(sns.kdeplot, fill=True)\n", "g.map_diag(sns.histplot, kde=True)" ] }, { "cell_type": "markdown", "id": "abd0154e", "metadata": { "id": "abd0154e" }, "source": [ "Le FacetGrid permet un excellent contrôle de la figure. On peut créer différents graphiques et modifier des graphiques spécifiques de la figure en utilisant les différentes valeurs d’une variable." ] }, { "cell_type": "code", "execution_count": null, "id": "f68cd3cd", "metadata": { "id": "f68cd3cd" }, "outputs": [], "source": [ "tips = sns.load_dataset(\"tips\")\n", "g = sns.FacetGrid(tips,col=\"sex\",row=\"time\",margin_titles=True,\n", " despine=False,sharex=False)\n", "g.figure.subplots_adjust(wspace=0.05, hspace=0.2)\n", "for (row_val, col_val), ax in g.axes_dict.items():\n", " subset = tips[(tips[\"time\"] == row_val) & (tips[\"sex\"] == col_val)]\n", " if row_val == \"Lunch\" and col_val == \"Female\":\n", " subset = subset[subset[\"tip\"] > 2]\n", " sns.scatterplot(data=subset,x=\"total_bill\",y=\"tip\",hue=\"smoker\",\n", " ax=ax)\n", " ax.set_facecolor(\".3\")\n", " ax.set_xlim(0,20)\n", " ax.set_ylim(0,30)\n", " ax.set_xticks([0, 5, 15])\n", " ax.set_xlabel(\"tip>2\")\n", " ax.grid(True, color=\"gray\", linestyle=\"-\", linewidth=0.5)\n", " ax.spines[\"top\"].set_color(\"red\")\n", " ax.spines[\"right\"].set_color(\"red\")\n", " ax.spines[\"bottom\"].set_color(\"red\")\n", " ax.spines[\"left\"].set_color(\"red\")\n", " ax.tick_params(axis=\"x\", colors=\"blue\")\n", " else:\n", " ax.set_facecolor((0, 0, 0, 0))\n", " sns.scatterplot(data=subset,x=\"total_bill\",y=\"tip\",hue=\"smoker\",\n", " ax=ax)\n" ] }, { "cell_type": "markdown", "id": "0c31fad8", "metadata": { "id": "0c31fad8" }, "source": [ "Vous pouvez soit enregistrer depuis la fenêtre qui s’ouvre lorsque vous affichez votre figure à l’aide du bouton, soit sauvegarder directement sur votre ordinateur avec la fonction savefig, qui permet de choisir la résolution de la figure via le dpi, ainsi que de définir si l’arrière-plan doit être transparent ou non, par exemple pour l’intégrer à un site web." ] }, { "cell_type": "code", "execution_count": null, "id": "5bfbc1c5", "metadata": { "id": "5bfbc1c5" }, "outputs": [], "source": [ "g.savefig(\"img\",dpi=200,transparent=True)\n" ] }, { "cell_type": "markdown", "id": "FOSBnBTd-hB9", "metadata": { "id": "FOSBnBTd-hB9" }, "source": [ "# Seaborn Objects\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "03f55bda", "metadata": { "id": "03f55bda" }, "source": [ "Un autre paradigme a été ajouté à Seaborn en 2022 : la représentation par objets, inspirée de ggplot2. Elle permet de construire des figures d’une manière différente et plus séquentielle. On commence par choisir les données que l’on souhaite représenter, puis le type de graphique que l’on veut, par exemple :" ] }, { "cell_type": "code", "execution_count": null, "id": "c58f2a69", "metadata": { "id": "c58f2a69" }, "outputs": [], "source": [ "so.Plot(tips,x=\"total_bill\").add(so.Bar(),so.Hist()).show()\n" ] }, { "cell_type": "markdown", "id": "d06cc890", "metadata": { "id": "d06cc890" }, "source": [ "Nous avons accès à différentes options selon les graphiques. Pour les scatterplots avec so.Dot(), on dispose par exemple de Jitter() pour éviter le chevauchement des points. Le paramètre color est en pratique l’équivalent de hue dans le paradigme précédent, et marker permet à nouveau de représenter d’autres variables." ] }, { "cell_type": "code", "execution_count": null, "id": "01ac7697", "metadata": { "id": "01ac7697" }, "outputs": [], "source": [ "so.Plot(tips,x=\"smoker\",y=\"tip\").add(so.Dot(),so.Jitter(),color=\"day\",\n", "marker=\"time\").facet(\"sex\").limit(y=(4,11)).show()\n" ] }, { "cell_type": "markdown", "id": "e61cf6ed", "metadata": { "id": "e61cf6ed" }, "source": [ "Dans le cas des scatterplots, on peut ajouter une régression linéaire en utilisant Line() et Polyfit(). Il existe différents types de lignes et pas uniquement des modèles Polyfit." ] }, { "cell_type": "code", "execution_count": null, "id": "41ce2fb6", "metadata": { "id": "41ce2fb6" }, "outputs": [], "source": [ "so.Plot(tips, x=\"total_bill\", y=\"tip\").add(so.Dot(), color=\"time\", marker=\"day\").facet(\"sex\").add(so.Line(), so.PolyFit(), color=\"time\").show()" ] }, { "cell_type": "markdown", "id": "ac7b0a53", "metadata": { "id": "ac7b0a53" }, "source": [ "Il est également possible d'effectuer des requêtes sur les données elles-mêmes grâce à la fonction query. Elles fonctionnent avec une logique classique utilisant des opérateurs and et or, != et ==. On utilise ensuite la méthode pipe afin d'ajouter le graphique souhaité aux données filtrées. On peut alors enrichir la figure comme on le souhaite. Ici, on ajoute une ligne d'agrégation et une estimation de l'erreur avec Band et Est." ] }, { "cell_type": "code", "execution_count": null, "id": "f06afe1e", "metadata": { "id": "f06afe1e" }, "outputs": [], "source": [ "diamonds=sns.load_dataset(\"diamonds\")\n", "diamonds.query(\"cut == 'Ideal' and (color == 'D' or color == 'F')\").pipe(so.Plot, \"depth\", \"price\",linestyle=\"color\").add(so.Line(color=\".1\",linewidth=1),so.Agg()).add(so.Band(), so.Est(),group=\"color\",color=\"color\").show()\n" ] }, { "cell_type": "markdown", "id": "d1e43255", "metadata": { "id": "d1e43255" }, "source": [ "Path() est une alternative à Line() quand vous souhaitez que le graphique suive strictement l'ordre des points de données. C'est utile lorsque vous voulez tracer une trajectoire." ] }, { "cell_type": "code", "execution_count": null, "id": "5911ac6f", "metadata": { "id": "5911ac6f" }, "outputs": [], "source": [ "healthexp=sns.load_dataset(\"healthexp\")\n", "p = so.Plot(healthexp, \"Spending_USD\", \"Life_Expectancy\", color=\"Country\").add(so.Path()).show()\n" ] }, { "cell_type": "markdown", "id": "1f91ae65", "metadata": { "id": "1f91ae65" }, "source": [ "La méthode facet permet de créer des figures avec plusieurs graphiques correspondant à différentes valeurs d'une variable, wrap contrôle le nombre de graphiques par ligne. Area() remplit la surface sous la ligne que formeraient les données." ] }, { "cell_type": "code", "execution_count": null, "id": "2fae7bc9", "metadata": { "id": "2fae7bc9" }, "outputs": [], "source": [ "so.Plot(healthexp,\"Year\",\"Spending_USD\").facet(\"Country\",wrap=3).add(so.Area(),color=\"Country\",legend=False).show()\n" ] }, { "cell_type": "markdown", "id": "abf0d5d3", "metadata": { "id": "abf0d5d3" }, "source": [ "La méthode Stack() empilera simplement toutes les graphiques sur le même." ] }, { "cell_type": "code", "execution_count": null, "id": "2ac5ed60", "metadata": { "id": "2ac5ed60" }, "outputs": [], "source": [ "so.Plot(healthexp,\"Year\",\"Spending_USD\",color=\"Country\").add(so.Area(),\n", "so.Stack()).show()\n" ] }, { "cell_type": "markdown", "id": "9236b753", "metadata": { "id": "9236b753" }, "source": [ "Ici, nous utilisons Agg() pour agréger toutes les valeurs en un point, ce qui revient essentiellement à tracer la moyenne de la variable, et Range() et Est() représentent l’incertitude de cette valeur, que nous pouvons contrôler puisque nous pouvons choisir le nombre d’écarts-types utilisés." ] }, { "cell_type": "code", "execution_count": null, "id": "ovoqPswDF_Oe", "metadata": { "id": "ovoqPswDF_Oe" }, "outputs": [], "source": [ "df = pd.DataFrame({\n", " \"x\": [1, 2, 3],\n", " \"y\": [10, 15, 20],\n", " \"ymin\": [8, 12, 17],\n", " \"ymax\": [12, 18, 23]\n", "})\n", "(\n", " so.Plot(df, x=\"x\", y=\"y\")\n", " .add(so.Range(), ymin=\"ymin\", ymax=\"ymax\")\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "d6466d66", "metadata": { "id": "d6466d66" }, "outputs": [], "source": [ "so.Plot(data,x=\"sex\",y=\"flipper_length_mm\",linestyle=\"species\").facet(\"species\").add(so.Line(marker=\"o\"), so.Agg()).add(so.Range(), so.Est(errorbar=(\"sd\",1))).show()\n" ] }, { "cell_type": "markdown", "id": "d979836b", "metadata": { "id": "d979836b" }, "source": [ "Exemple de différents types de graphiques sur le même graphique, grâce à un double .add()." ] }, { "cell_type": "code", "execution_count": null, "id": "c5389698", "metadata": { "id": "c5389698" }, "outputs": [], "source": [ "so.Plot(tips,x=\"total_bill\").facet(row=\"time\",col=\"sex\").add(so.Bar(),so.Hist(stat=\"density\")).add(so.Line(color=\"red\"),so.KDE()).show()\n" ] }, { "cell_type": "markdown", "id": "60846eb9", "metadata": { "id": "60846eb9" }, "source": [ "La méthode Dodge() a le même rôle que le paramètre dodge du paradigme précédent." ] }, { "cell_type": "code", "execution_count": null, "id": "eb8559f0", "metadata": { "id": "eb8559f0" }, "outputs": [], "source": [ "so.Plot(tips, \"total_bill\", \"smoker\", color=\"sex\").add(so.Bar(alpha=.5), so.Agg(), so.Dodge()).add(so.Range(), so.Est(errorbar=\"sd\"), so.Dodge()).show()\n" ] }, { "cell_type": "markdown", "id": "6d27008e", "metadata": { "id": "6d27008e" }, "source": [ "La méthode Count() fait quelque chose de différent de Agg() : comme son nom l’indique, elle compte les occurrences d’une certaine variable, ici le fait que la personne soit fumeuse ou non." ] }, { "cell_type": "code", "execution_count": null, "id": "c25d5366", "metadata": { "id": "c25d5366" }, "outputs": [], "source": [ "so.Plot(tips,y=\"day\",color=\"smoker\").add(so.Bar(),so.Count(),so.Stack()).show()\n" ] }, { "cell_type": "markdown", "id": "f95a52c7", "metadata": { "id": "f95a52c7" }, "source": [ "On peut également représenter les percentiles avec les objets Seaborn. On peut fournir une liste à Perc() pour faire apparaître précisément les percentiles souhaités. Si on ne le fait pas et qu’on ne passe rien, il affiche automatiquement les percentiles 20, 40, 60, 80 et 100." ] }, { "cell_type": "code", "execution_count": null, "id": "862c96e1", "metadata": { "id": "862c96e1" }, "outputs": [], "source": [ "so.Plot(tips,\"smoker\",\"total_bill\").add(so.Dot(marker=\"s\"),so.Perc([10,50,90])).show()\n" ] }, { "cell_type": "markdown", "id": "63a13551", "metadata": { "id": "63a13551" }, "source": [ "Voici un exemple de Dots() qui permet de tracer un grand nombre de points avec de bonnes performances. Le paramètre Jitter crée une illusion de barre. Nous traçons ensuite les percentiles de 0 à 25 et de 75 à 100. Le Shift() sur l’axe y permet de placer le visuel en dessous des points. Avec .scale, on peut choisir l’échelle d’un axe spécifique, ici l’axe x." ] }, { "cell_type": "code", "execution_count": null, "id": "f50bd0ac", "metadata": { "id": "f50bd0ac" }, "outputs": [], "source": [ "so.Plot(diamonds, \"price\", \"cut\").add(so.Dots(pointsize=1, alpha=.2), so.Jitter(.3)).add(so.Range(color=\"k\"), so.Perc([0, 25]), so.Shift(y=.2)).add(so.Range(color=\"k\"), so.Perc([75, 100]), so.Shift(y=.2)).scale(x=\"log\").show()\n" ] }, { "cell_type": "markdown", "id": "6bed1d4e", "metadata": { "id": "6bed1d4e" }, "source": [ "On peut créer des graphiques en choisissant une base, par exemple avec Norm, et une condition pour cette base avec where. Ici, on prend comme base x.min(), qui correspond au plus ancien année dont nous disposons." ] }, { "cell_type": "code", "execution_count": null, "id": "692a4167", "metadata": { "id": "692a4167" }, "outputs": [], "source": [ "so.Plot(healthexp, x=\"Year\", y=\"Spending_USD\", color=\"Country\").add(so.Lines(), so.Norm(where=\"x == x.min()\",percent=True)).label(y=\"Percent change in spending from 1970 baseline\").show()\n" ] }, { "cell_type": "markdown", "id": "1abe31f5", "metadata": { "id": "1abe31f5" }, "source": [ "Ici, nous utilisons Norm() avec percent pour montrer la variation au fil des années." ] }, { "cell_type": "code", "execution_count": null, "id": "2bc7b257", "metadata": { "id": "2bc7b257" }, "outputs": [], "source": [ "mpg=sns.load_dataset(\"mpg\")\n", "so.Plot(mpg,\"model_year\",\"horsepower\").add(so.Line(),so.Agg(),so.Norm(percent=True),color=\"origin\").show()\n" ] }, { "cell_type": "markdown", "id": "fXGsGzLPCrkV", "metadata": { "id": "fXGsGzLPCrkV" }, "source": [ "Il existe des variantes de la plupart des objets avec un s ; ces versions sont mieux adaptées pour tracer de grandes quantités de données." ] }, { "cell_type": "code", "execution_count": null, "id": "sDom0hjWCHph", "metadata": { "id": "sDom0hjWCHph" }, "outputs": [], "source": [ "diamonds = sns.load_dataset(\"diamonds\")\n", "so.Plot(diamonds,\"price\",color=\"cut\").add(so.Bars(),so.Hist(bins=50)).scale(x=\"log\")" ] }, { "cell_type": "code", "execution_count": null, "id": "DbvYbfO8BBIn", "metadata": { "id": "DbvYbfO8BBIn" }, "outputs": [], "source": [ "diamonds = sns.load_dataset(\"diamonds\")\n", "so.Plot(diamonds,\"price\",color=\"cut\").add(so.Bar(),so.Hist(bins=50)).scale(x=\"log\")" ] }, { "cell_type": "code", "execution_count": null, "id": "0d84c0b5", "metadata": { "id": "0d84c0b5" }, "outputs": [], "source": [ "\n", "so.Plot(tips,x=\"total_bill\",y=\"tip\").add(so.Dots(),so.Jitter(0.5),color=\"day\",marker=\"time\").facet(\"sex\").scale(x=so.Continuous(trans=\"log10\"),y=so.Continuous(trans=\"sqrt\")).show()\n", "\n" ] }, { "cell_type": "markdown", "id": "T6SEKBuycDOj", "metadata": { "id": "T6SEKBuycDOj" }, "source": [ "On peut également contrôler l’apparence de ses graphiques, par exemple en utilisant des types de marqueurs spécifiques pour les nuages de points." ] }, { "cell_type": "code", "execution_count": null, "id": "NcqAdH9HSJpx", "metadata": { "id": "NcqAdH9HSJpx" }, "outputs": [], "source": [ "tips=sns.load_dataset(\"tips\")\n", "so.Plot(tips, x=\"total_bill\", y=\"tip\") \\\n", " .add(so.Dots(), so.Jitter(0.5),\n", " color=\"day\", marker=\"time\") \\\n", " .scale(marker={\n", " \"Lunch\": \"o\",\n", " \"Dinner\": \"1\"\n", " }) \\\n", " .show()\n", "\n", "so.Plot(tips, x=\"total_bill\", y=\"tip\") \\\n", " .add(so.Dots(marker=\"x\"), so.Jitter(0.5)) \\\n", " .show()" ] }, { "cell_type": "markdown", "id": "Tirsrbrodsez", "metadata": { "id": "Tirsrbrodsez" }, "source": [ "On peut également choisir le type de lignes." ] }, { "cell_type": "code", "execution_count": null, "id": "M7YuXg5zdv7s", "metadata": { "id": "M7YuXg5zdv7s" }, "outputs": [], "source": [ "so.Plot(tips,\"total_bill\",\"tip\").add(so.Lines(linestyle='--'))" ] }, { "cell_type": "markdown", "id": "eL8eZKzvgCZP", "metadata": { "id": "eL8eZKzvgCZP" }, "source": [ "Et on peut également choisir les couleurs manuellement :" ] }, { "cell_type": "code", "execution_count": null, "id": "tRgvD0LKgFGU", "metadata": { "id": "tRgvD0LKgFGU" }, "outputs": [], "source": [ "so.Plot(tips, \"total_bill\", \"tip\",\n", " color=\"sex\", linestyle=\"sex\").add(so.Lines()).scale(color={\"Male\": \"blue\",\"Female\": \"red\"},\n", " linestyle={\"Male\": \"--\",\"Female\": (4,4)}\n", " ).show()" ] }, { "cell_type": "code", "execution_count": null, "id": "k2RauHVkjVe_", "metadata": { "id": "k2RauHVkjVe_" }, "outputs": [], "source": [ "so.Plot(healthexp, x=\"Year\", y=\"Spending_USD\", color=\"Country\").add(so.Lines(), so.Norm(where=\"x == x.min()\", percent=True)).scale(color=\"rocket\") \\\n", " .label(y=\"Percent change in spending from 1970 baseline\")" ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "venv (3.12.3)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }