--- title: Plotly Express author: Steve Kossouho --- # Rendu de graphiques avec Plotly ---- ## Qu'est-ce que Plotly ? Selon le site de Plotly : La bibliothèque graphique Python Plotly crée des graphiques interactifs de qualité propre à la publication. ![Logo de Plotly](assets/images/eda-plotly-logo.png) ---- ## Comment fonctionne Plotly ? Plotly est une bibliothèque Python compatible avec les `DataFrame`{.python} Pandas, qui permet de créer des graphiques interactifs, et cela grâce aux technologies web (HTML, CSS et JS). Un navigateur suffit à afficher le contenu d'un graphique généré avec Plotly. La bibliothèque est relativement facile à prendre en main et bien documentée, de sorte qu'il est simple de faire des choses simples, et abordable de produire des choses plus complexes. [Documentation de Plotly pour Python](https://plotly.com/python/) ---- ## Plotly Express Plotly express est une bibliothèque de Plotly proposant très simplement de créer des graphiques, depuis des `DataFrame`{.python} Pandas. Elle propose toute la variété de graphiques générables avec Plotly, via des fonctions prêtes à l'emploi prenant en argument un `DataFrame`{.python}. ---- ### Installer Plotly Express ```bash {.numberLines} pip install plotly ``` Plotly contient un package `express` proposant des fonctions simples de rendu. ---- ### Graphiques Plotly Express Nous allons passer en revue quelques graphiques réalisables avec Express. ---- #### `plotly.express.bar` Générer un graphique en barres est assez simple avec Plotly, et fonctionne de manière relativement satisfaisante par défaut (ex. texte en blanc sur fond sombre) ```python {.numberLines} import pandas as pd from plotly import express data = pd.DataFrame(data={ "product": ["pomme", "poire", "banane", "pêche"], "price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200] }) # Générer un graphique avec deux colonnes par valeur de "product" figure = express.bar(data, x="product", y=["price", "wpu"], barmode="group", title="Prix et poids unitaires") figure.show(renderer="browser") # Le renderer peut être obligatoire, ex. avec Spyder ``` [Documentation de `bar`](https://plotly.com/python-api-reference/generated/plotly.express.bar.html) ---- ![Rendu de base en barres](assets/images/eda-plotly-express-bar-default.png) ---- #### `plotly.express.bar` (`Series`) Vous pouvez également générer un graphique en partant d'un objet de type `Series`{.python}, même si l'objet ne contient en lui-même qu'une seule colonne. Les valeurs d'index peuvent également servir sur un axe; il suffit d'utiliser la valeur `None`{.python} pour indiquer que les valeurs d'index doivent être utilisées sur l'axe des X. ```python {.numberLines} import pandas as pd from plotly import express values = pd.Series( data=[1.99, 2.49, 2.99, 3.49], index=["pomme", "poire", "banane", "peche"], name="price" ) # Générer un graphique figure = express.bar(values, x=None, y="price") figure.show(renderer="browser") ``` L'axe des Y pourra utiliser le nom associé à l'objet `Series` (`values.name`{.python}) ---- #### Personnalisation Quelques personnalisations sont possibles, notamment via la notion de `template` (thème), que nous reverrons avec Plotly. ```python {.numberLines} import pandas as pd from plotly import express data = pd.DataFrame(data={ "product": ["pomme", "poire", "banane", "pêche"], "price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200] }) # Générer un graphique. Plotly express ne prend en charge qu'un seul graphique par figure figure = express.bar(data, x="product", y="price", title="Prix", template="seaborn", labels={"price": "Prix", "product": "Produit"}) figure.show(renderer="browser") ``` ---- ![Rendu personnalisé en barres](assets/images/eda-plotly-express-bar-themed.png) ---- ![Rendu personnalisé en barres 2](assets/images/eda-plotly-express-bar-custom.png) ---- #### `plotly.express.sunburst` (anneaux concentriques) Le graphique [sunburst]{.naming} permet d'afficher des secteurs, et de les découper en sous-catégories dans des anneaux concentriques. Ici, nous avons un `DataFrame`{.python} avec des ventes par ville, chaque ville appartenant à un pays. ```python {.numberLines} import pandas as pd import plotly from plotly.express import sunburst if __name__ == '__main__': df = pd.DataFrame(data={ "country": ["France", "France", "Spain", "Spain", "England", "England", "England"], "city": ["Montpellier", "Bordeaux", "Madrid", "Valencia", "London", "Manchester", "Bristol"], "sales": [150_000, 127_000, 97_200, 137_250, 200_000, 180_000, 150_000] }) plot = sunburst(df, path=["country", "city"], values="sales", title="Sales by country and city", template="ggplot2", color_discrete_sequence=plotly.colors.qualitative.Dark2) plot.layout.update({"font": {"family": "Cabin", "size": 13}}) plot.show() ``` [Documentation de `sunburst`](https://plotly.com/python-api-reference/generated/plotly.express.sunburst.html) ---- ![Rendu personnalisé en [sunburst]{.naming}](assets/images/eda-plotly-express-sunburst-themed.png) ---- #### `plotly.express.scatter` (nuages de points) Les nuages de points ([scatter plot]{.naming}) sont un moyen pratique de mettre en regard deux valeurs d'une même observation afin d'essayer de déduire une tendance ou une corrélation. Ils se présentent en 2 dimensions, mais deux autres axes peuvent être représentés via la taille ou la couleur des points du graphique. ```python {.numberLines} import pandas as pd from plotly import express as px # Charger le dataset Iris data = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data", header=None, names=["sepal-length", "sepal-width", "petal-length", "petal-width", "class"]) plot = px.scatter(data, x="sepal-length", y="sepal-width", size="petal-width", color="class", template="seaborn", title="Iris flowers dataset", labels={"sepal-length": "Sepal length", "sepal-width": "Sepal width", "petal-width": "Petal width", "class": "Class"}) plot.show(renderer="browser") ``` [Documentation de `scatter`](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html) ---- ![Rendu personnalisé en [scatter]{.naming}](assets/images/eda-plotly-express-scatter-themed.png) ---- ## Plotly Cette section permet de creuser plus loin en utilisant les outils fondamentaux proposés par Plotly, eux aussi relativement simples mais riches. ---- ### Notions Plotly propose nombre d'outils classés dans certains thèmes pour vous permettre de personnaliser vos graphiques. Les thèmes que nous allons aborder sont les suivants : | Thème | Description en français | |:----------------------------------|-----------------------------------------------------| | `templates` | Thèmes pour personnaliser les graphiques | | `layout` et `figure` | Mises en page pour les graphiques | | `axes` | Axes pour les graphiques | | `texttemplates` | Textes pour les éléments de graphiques | | `palettes de couleurs` | Sélections de couleurs pour les graphiques | | `séquences et cartes de couleurs` | Séquences et cartes de couleurs pour les graphiques | | `traces` | Tracés pour les graphiques | | `sous-graphiques` | Sous-graphiques pour les rendus | ---- ### Templates Les [templates]{.naming} dans Plotly sont des objets contenant un ensemble de configurations pour le rendu d'éléments de graphiques. Les options individuelles personnalisables sont extrêmement nombreuses (des milliers), ainsi Plotly fournit des thèmes prêts à l'emploi pour vous permettre de personnaliser l'apparence de vos graphiques. Voici une liste des noms possibles fournis par Plotly pour appliquer un `template`{.python} à un rendu : | Template | Description | Template | Description | |----------------|--------------------------------------|----------------|---------------------------------------------------| | `plotly` | Thème par défaut de **Plotly** | `ggplot2` | Thème par défaut de **GGPlot2** pour [R]{.naming} | | `seaborn` | Thème par défaut de **Seaborn** | `plotly_white` | Thème blanc avec des grilles | | `plotly_dark` | Thème sombre | `presentation` | Style optimisé pour les présentations | | `xgridoff` | Désactive la grille en X | `ygridoff` | Désactive la grille en Y | | `gridon` | Active les grilles sur les deux axes | `none` | Désactive tous les styles par défaut | ---- #### Associer un template ```python {.numberLines} from plotly.express import bar import pandas as pd data = pd.DataFrame({ "product": ["stylo", "clavier", "souris", "écran"], "price": [1.99, 15.99, 8.99, 129.99], }) figure = bar(data, x="product", y="price", title="Prix", template="seaborn") figure.show(renderer="browser") ``` Ce code génère un graphique en barres, en utilisant le template `seaborn`{.python}. [Documentation sur les templates](https://plotly.com/python/templates/) ---- ![Barres rendues avec le template seaborn](assets/images/eda-plotly-template-select-base.png) ---- #### Définir un template Vous pouvez définir vos propres templates dans Plotly en définissant des objets héritant de la classe `plotly.graph_objs.layout.Template`{.python}. Ces objets sont créés avec un dictionnaire contenant les configurations des éléments de graphiques que vous souhaitez personnaliser. ```python {.numberLines} from plotly.graph_objs.layout import Template my_template = Template(layout={ "hoverlabel": {"bgcolor": "#333333", "bordercolor": "black", "font": { "family": "Roboto", "size": 12, "color": "white", "weight": "bold" }}, "font": {"family": "Roboto", "size": 15}, "margin": {"pad": 20}, "title": {"font": {"size": 36, "weight": "bold"}} }) ``` ---- #### Enregistrer le template Pour enregistrer votre template afin de le désigner simplement par un nom, vous devez l'ajouter au dictionnaire des templates disponibles dans Plotly. ```python {.numberLines} from plotly.graph_objs.layout import Template from plotly.io import templates my_template = Template(layout={ "hoverlabel": { "bgcolor": "#333333", "bordercolor": "black", "font": {"family": "Roboto", "size": 12, "color": "white", "weight": "bold"} }, "font": {"family": "Roboto", "size": 15}, "margin": {"pad": 20}, "title": {"font": {"size": 36, "weight": "bold"}} }) # Enregistrer le template templates["my_template"] = my_template ``` Vous pourrez ensuite le sélectionner en précisant son nom seul, ou via une addition `template="other_template+my_template"`{.python} afin de superposer les configurations des deux templates. ---- ### Layout et Figure Les objets de type `plotly.graph_objs.Layout`{.python} peuvent être renseignés sous forme de dictionnaires et comprennent plusieurs options pour personnaliser le rendu des graphiques. Les options disponibles sont nombreuses et varient en fonction du type de graphique que vous souhaitez afficher. Elles sont exactement les mêmes que celles des templates. [Documentation sur les options de layout](https://plotly.com/python/reference/layout/) ---- #### Appliquer un layout (Express) ```python {.numberLines} import pandas as pd import plotly from plotly.graph_objs import Figure from plotly.express import sunburst df = pd.DataFrame(data={ "country": ["France", "France", "Spain", "Spain", "England", "England", "England"], "city": ["Montpellier", "Bordeaux", "Madrid", "Valencia", "London", "Manchester", "Bristol"], "sales": [150_000, 127_000, 97_200, 137_250, 200_000, 180_000, 150_000] }) plot: Figure = sunburst(df, path=["country", "city"], values="sales", title="Sales by country and city", template="ggplot2") plot.layout.update({"font": {"family": "Cabin", "size": 13}, "showlegend": True}) plot.show(renderer="browser") ``` Les objets de type `plotly.graph_objs.Figure`{.python} possèdent un attribut `layout`{.python} de type `plotly.graph_objs.Layout`{.python}, qui fonctionne comme un dictionnaire et permet de personnaliser le rendu des graphiques. Ici, on a personnalisé la police et l'affichage des légendes. ---- #### Appliquer un layout (Plotly) ```python {.numberLines} import pandas as pd from plotly.graph_objs import Figure, Bar df = pd.DataFrame(data={"label": ["Citron", "Pomme", "Mangue"], "price": [1.99, 3.97, 6.8]}) figure = Figure( data=[Bar(x=df["label"], y=df["price"])], layout={ "font": {"family": "Cabin", "size": 20}, "title": {"text": "Prix au kilo"}, } ) figure.show(renderer="browser") ``` Ici, on crée un objet `Figure`{.python} manuellement, en lui associant une ou plusieurs [traces]{.naming}. L'initialisation accepte un argument `layout: dict`{.python} pour personnaliser le rendu des graphiques. ---- #### Exemples d'options de layout | Option | Type / valeur possible | Description / notes | | ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | | `title.automargin` | booléen | Ajuste automatiquement les marges pour éviter le chevauchement du titre. | | `title.font` | dict | Définit la police du texte du titre. | | `title.font.color` | color | Couleur du texte du titre. | | `title.font.family` | string | Famille de police (ex. `"Arial, sans-serif"`). | | `title.font.lineposition` | flaglist / string | Décoration du texte : `"under"`, `"over"`, `"through"`, ou `"none"`. | | `title.font.shadow` | string | Définit l’ombre du texte, `"auto"` ou une valeur personnalisée. | | `title.font.size` | nombre | Taille de la police (>= 1). | | `title.font.style` | `"normal"` / `"italic"` | Style du texte (normal ou italique). | 1/4 ---- | Option | Type / valeur possible | Description / notes | | ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | | `title.font.textcase` | `"normal"` / `"word caps"` / `"upper"` / `"lower"` | Définit la casse du texte. | | `title.font.variant` | `"normal"` / `"small-caps"` / `"all-small-caps"` | Variante typographique. | | `title.font.weight` | nombre ou `"normal"` / `"bold"` | Épaisseur de la police (1–1000). | | `title.pad` | dict | Définit les marges internes autour du titre. | | `title.pad.b` | nombre | Marge interne inférieure (px). | | `title.pad.l` | nombre | Marge interne gauche (px). | | `title.pad.r` | nombre | Marge interne droite (px). | | `title.pad.t` | nombre | Marge interne supérieure (px). | 2/4 ---- | Option | Type / valeur possible | Description / notes | | ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | | `title.subtitle` | dict | Définit le sous-titre du graphique. | | `title.subtitle.text` | string | Texte du sous-titre. | | `title.subtitle.font` | dict | Police du sous-titre (mêmes propriétés que `title.font`). | | `title.text` | string | Texte du titre principal. | | `title.x` | nombre ∈ [0, 1] | Position horizontale du titre (relative à `title.xref`). | | `title.xanchor` | `"auto"` / `"left"` / `"center"` / `"right"` | Alignement horizontal du texte selon `x`. | | `title.xref` | `"container"` / `"paper"` | Référence horizontale du titre. | | `title.y` | nombre ∈ [0, 1] ou `"auto"` | Position verticale du titre (relative à `title.yref`). | 3/4 ---- | Option | Type / valeur possible | Description / notes | | ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | | `title.yanchor` | `"auto"` / `"top"` / `"middle"` / `"bottom"` | Alignement vertical du texte selon `y`. | | `title.yref` | `"container"` / `"paper"` | Référence verticale du titre. | 4/4 Toutes les options sont disponibles dans la [documentation officielle](https://plotly.com/python/reference/layout/) de Plotly. ---- #### Layouts à axes multiples Par défaut, Plotly Express ne génère pas deux axes Y distincts lorsque vous affichez un graphique avec deux colonnes pour l'axe Y. Si leurs plages de valeurs sont différentes, les barres partageront toutefois la même échelle. Pour définir deux axes distincts en Y (ou 3), nous devons utiliser Plotly manuellement. ```python {.numberLines} from plotly.graph_objs import Figure, Bar import pandas as pd data = pd.DataFrame(data={ "product": ["pomme", "poire", "banane", "pêche"], "price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200] }) figure = Figure( data=[ Bar(name="Prix", x=data["product"], y=data["price"], yaxis="y1", offsetgroup=1), Bar(name="Poids", x=data["product"], y=data["wpu"], yaxis="y2", offsetgroup=2), ], layout={ "template": "seaborn", "title": "Prix et poids unitaires", "font": {"family": "Cabin", "size": 13}, "yaxis1": {"title": "Prix (€)", "color": "red", "side": "left"}, "yaxis2": {"title": "Poids (g)", "overlaying": "y1", "side": "right"} } ) figure.show(renderer="browser") ``` ---- #### Nomenclature des axes Plotly gère dynamiquement la définition de plusieurs axes dans un graphique. Lorsque vous définissez par exemple un axe Y pour un tracé orthogonal 2D, vous le définissez via un argument nommé `yaxis`{.python}. La valeur de cet attribut est généralement un nom tel que `y`, `y1`, `y2`, etc. Notez que le nom `y`{.python} est un raccourci pour `y0`{.python}. Les informations de mise en page pour cet axe sont ensuite définies dans le layout avec un nom similaire, par exemple `yaxis1`{.python} pour `y1`{.python}. ---- ![Rendu avec deux axes Y](assets/images/eda-plotly-compose-2axes.png) ---- ### Texte personnalisé dans les éléments Par défaut, les secteurs de graphique camembert ([pie]{.naming}) affichent la taille d'un secteur en pourcents du total. De façon moins évidente, le texte des barres est masqué par défaut. L'affichage ou non d'une étiquette, et la personnalisation du texte des étiquettes est possible, via un ensemble d'arguments définis dans le tableau suivant. | Option | Type / valeur possible | Description / notes | | ------------------------- |-------------------------------------------------| ------------------------------------------------------------------------ | | `textinfo` | `"label"` / `"value"` / `"percent"` ou addition | Définit le texte à afficher dans chaque secteur. | | `texttemplate` | string | Format du texte à afficher dans chaque secteur. | | `textposition` | `"inside"` / `"outside"` / `"auto"` / `"middle"` | Position du texte par rapport au secteur. | ---- #### Texte de secteurs de camembert ```python {.numberLines} import pandas as pd from plotly.graph_objs import Figure, Pie from plotly.colors import qualitative data = pd.DataFrame(data={ "product": ["oignon", "carotte", "pomme", "poire", "radis", "tomate"], "category": ["légume", "légume", "fruit", "fruit", "légume", "fruit"], "origin": ["Espagne", "France", "France", "France", "France", "Espagne"], "price": [1.69, 2.49, 2.99, 1.79, 1.29, 2.99] }) figure = Figure( data=[Pie( values=data["price"], labels=data["product"].str.title(), customdata=data[["category", "origin"]], # 2 colonnes title="Prix", textinfo="label+value", texttemplate="%{label}
%{value:.2f}€
%{customdata[0]}
%{customdata[1]}", insidetextorientation="tangential") ], layout={ "template": "seaborn", "title": "Prix au kilo", "font": {"family": "Cabin", "size": 13}, "piecolorway": qualitative.Prism }) figure.show(renderer="browser") ``` [Personnalisation des camemberts](https://plotly.com/python/pie-charts/) ---- ![Personnalisation du texte des secteurs](assets/images/eda-plotly-texttemplate-pie.png) ---- ### Choix de couleurs Vous pouvez définir votre propre choix de couleurs pour certains graphiques, avec certains arguments. L'argument `color_discrete_sequence`{.python} permet de définir une liste de couleurs à appliquer en tourniquet aux éléments du dessin. ```python {.numberLines} import pandas as pd from plotly import express as px from plotly.colors import qualitative data = pd.DataFrame(data={ "name": ["headphones", "microphone", "speaker", "powerbank", "tablet", "laptop"], "price": [99.99, 49.99, 149.99, 29.99, 199.99, 499.99], "merchant": ["amazon", "amazon", "bestbuy", "amazon", "newegg", "amazon"], "color": ["black", "silver", "white", "red", "gray", "silver"] }) figure = px.pie(data, values="price", names="name", title="Prix", texttemplate="", color_discrete_sequence=qualitative.Bold) figure.layout.update({"template": "seaborn", "title": "Prix à l'unité", "font": {"family": "Cabin", "size": 13}}) figure.show(renderer="browser") ``` ---- ![Rendu avec choix de couleurs par secteur](assets/images/eda-plotly-express-pie-colors-predefined.png) ---- ### Gradients de couleurs Vous pouvez appliquer des couleurs prédéfinies ou continues à vos graphiques. Vous pouvez utiliser une palette servant de dégradé pour colorier les éléments du dessin selon une valeur associée. ```python {.numberLines} import pandas as pd from plotly import express as px from plotly.colors import sequential, qualitative df = pd.DataFrame(data={ "month": [f"2005-{i:02d}" for i in range(1, 13)], "temperature": [4.4, 6.8, 9.2, 11.5, 13.8, 16.3, 19.1, 21.4, 22.9, 20.5, 17.2, 13.9] }) plot = px.bar( df, x="month", y="temperature", color="temperature", template="seaborn", title="Temperatures mensuelles de 2005", color_continuous_scale=sequential.Turbo, labels={"month": "Mois", "temperature": "Température (°C)"} ) plot.layout.update({"font": {"family": "Cabin", "size": 13}}) plot.show() ``` ---- ![Rendu avec choix de couleurs par valeur](assets/images/eda-plotly-express-bar-colors-predefined.png) ---- ### Palettes de couleurs personnalisées Les palettes utilisées dans les exemples précédents sont simplement des listes de couleurs prédéfinies par Plotly, mais vous pouvez définir vos propres palettes de couleurs via des listes composées de couleurs sous plusieurs formats : | Format de couleur | Exemple(s) | Description / notes | | ------------------------ | -------------------------------- | ------------------------------------------------ | | Nom de couleur CSS | `"red"`, `"blue"`, `"green"` | Noms de couleurs standards en CSS | | Code hexadécimal | `"#FF5733"`, `"#33FF57"` | Codes hexadécimaux RGB | | Code RGB | `"rgb(255,0,0)"`, `"rgb(0,255,0)"` | Codes RGB avec valeurs décimales (0-255) | | Code RGBA | `"rgba(255,0,0,0.5)"` | Codes RGBA avec valeurs décimales (0-255) et alpha (0-1) | ---- Ici on définit manuellement une suite de couleurs à utiliser pour colorier les barres, allant du rouge au jaune. ```python {.numberLines} import pandas as pd from plotly import express as px from plotly.colors import sequential, qualitative df = pd.DataFrame(data={ "month": [f"2005-{i:02d}" for i in range(1, 13)], "temperature": [4.4, 6.8, 9.2, 11.5, 13.8, 16.3, 19.1, 21.4, 22.9, 20.5, 17.2, 13.9] }) plot = px.bar( df, x="month", y="temperature", color="temperature", template="seaborn", title="Temperatures mensuelles de 2005", color_continuous_scale=["#FF0020", "rgb(255,165,0)", "rgba(255,255,0,0.8)"], labels={"month": "Mois", "temperature": "Température (°C)"} ) plot.layout.update({"font": {"family": "Cabin", "size": 13}}) plot.show() ``` ---- ![Rendu avec choix de couleurs par valeur](assets/images/eda-plotly-express-bar-colors-custom.png) ---- [Couleurs et séquences de couleurs](https://plotly.com/python/discrete-color/) ![Couleurs Qualitatives](assets/images/eda-plotly-colors-qualitative.svg) ---- [Couleurs et séquences de couleurs](https://plotly.com/python/discrete-color/) ![Séquences de Couleurs](assets/images/eda-plotly-colors-sequential.svg) ---- [Couleurs continues](https://plotly.com/python/builtin-colorscales/#builtin-sequential-color-scales) ![Couleurs continues](assets/images/eda-plotly-colors-continuous.svg) ---- ### Sous-graphiques ([subplots]{.naming}) Plotly propose un module `plotly.subplots` permettant de créer des figures composées de plusieurs sous-graphiques. Vous pouvez définir la mise en page de vos sous-graphiques, en précisant le nombre de lignes et de colonnes, ainsi que la taille de chaque sous-graphe. ```python {.numberLines} import pandas as pd from plotly.subplots import make_subplots from plotly.graph_objs import Figure, Bar data = pd.DataFrame(data={ "product": ["tarte", "gâteau", "biscuit", "mille-feuille", "éclair", "brownie"], "price": [2.99, 3.49, 1.99, 4.99, 5.99, 6.99], "weight": [250, 300, 200, 400, 500, 600] }) figure: Figure = make_subplots(rows=1, cols=2, subplot_titles=("Prix", "Poids unitaires")) figure.add_trace(Bar(name="Prix", x=data["product"], y=data["price"]), row=1, col=1) figure.add_trace(Bar(name="Poids", x=data["product"], y=data["weight"]), row=1, col=2) figure.update_layout(template="seaborn", title="Prix et poids unitaires", font={"family": "Cabin", "size": 13}) figure.show(renderer="browser") ``` Vous pouvez également créer un objet `Figure`{.python} normalement, et exécuter la méthode `figure.set_subplots`{.python} pour obtenir le même objet. ---- ![Sous-graphiques](assets/images/eda-plotly-subplot-base.png) ---- #### Propriétés des colonnes et lignes Vous pouvez définir les dimensions relatives des colonnes et lignes lors de la création de sous-graphiques. ```python {.numberLines} import pandas as pd from plotly.subplots import make_subplots from plotly.graph_objs import Figure, Bar data = pd.DataFrame(data={ "product": ["tarte", "gâteau", "biscuit", "mille-feuille", "éclair", "brownie"], "price": [2.99, 3.49, 1.99, 4.99, 5.99, 6.99], "weight": [250, 300, 200, 400, 500, 600] }) figure: Figure = make_subplots(rows=1, cols=2, column_widths=[0.6, 0.4], row_heights=[1.0]) figure.add_trace(Bar(name="Prix", x=data["product"], y=data["price"]), row=1, col=1) figure.add_trace(Bar(name="Poids", x=data["product"], y=data["weight"]), row=1, col=2) figure.update_layout(template="seaborn", title="Prix et poids unitaires", font={"family": "Cabin", "size": 13}) figure.show(renderer="browser") ``` Ici les colonnes 1 et 2 représentent respectivement 60% et 40% de la largeur totale. ---- ![Sous-graphiques avec largeurs de colonnes](assets/images/eda-plotly-subplot-widths-heights.png) ---- ### Éléments graphiques Vous pouvez agrémenter manuellement vos graphiques d'éléments visuels; les objets `Figure`{.python} possèdent de nombreuses méthodes pour ajouter des éléments visuels (_images_, _rectangles_, autres…) ---- #### Ajouter une image ```python {.numberLines} import pandas as pd from plotly.graph_objs import Figure, Bar from PIL import Image data = pd.DataFrame(data={ "product": ["tarte", "gâteau", "biscuit", "mille-feuille", "éclair", "brownie"], "price": [2.99, 3.49, 1.99, 4.99, 5.99, 6.99], "weight": [250, 300, 200, 400, 500, 600] }) figure: Figure = Figure(data=[Bar(name="Prix", x=data["product"], y=data["price"])]) figure.add_layout_image( layer="above", x=0, y=1.02, xref="paper", yref="paper", sizex=1, sizey=0.075, xanchor="left", yanchor="bottom", source=Image.open("images/python-logo-square.png") ) figure.update_layout(template="seaborn", title="Prix et poids unitaires", font={"family": "Cabin", "size": 13}) figure.show(renderer="browser") ``` **Note** : Nécessite une image valide. ---- ![Ajout d'une image de Logo](assets/images/eda-plotly-trace-image.png) ---- #### Options de taille, d'échelle et d'alignement | Argument | Type / valeur possible | Description / notes | |-----------|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `xref` | `"paper"` / `"pixel"` / `"x"` | Référence horizontale de l'image. Lorsque `xref` vaut `"paper"`, `x` est relative à la largeur totale du graphique. Lorsque `xref` vaut `"pixel"`, `x` est en pixels. | | `yref` | `"paper"` / `"pixel"` / `"y"` | Référence verticale de l'image. Lorsque `yref` vaut `"paper"`, `y` est relative à la hauteur totale du graphique. Lorsque `yref` vaut `"pixel"`, `y` est en pixels. | | `xanchor` | `"auto"` / `"left"` / `"center"` / `"right"` | Alignement horizontal de l'image selon `x`. | | `yanchor` | `"auto"` / `"top"` / `"middle"` / `"bottom"` | Alignement vertical de l'image selon `y`. | | `x` | nombre | Position horizontale de l'image (relative à `xref`). | | `y` | nombre | Position verticale de l'image (relative à `yref`). | | `sizex` | nombre ∈ [0, 1] | Largeur relative de l'image selon l'axe des X. | | `sizey` | nombre ∈ [0, 1] | Hauteur relative de l'image selon l'axe des Y. | | `layer` | `"above"` / `"below"` / `"between"` | Couche de l'image par rapport aux autres éléments du graphique. | | `source` | `PIL.Image` | Image à afficher. | ---- #### Ajouter un rectangle horizontal ```python {.numberLines} import pandas as pd from plotly.graph_objs import Figure, Bar, Scatter data = pd.DataFrame( data={ "product": ["tarte", "gâteau", "biscuit", "mille-feuille", "éclair", "brownie"], "price": [2.99, 3.49, 1.99, 4.99, 5.99, 6.99], "weight": [250, 300, 200, 400, 500, 600], } ) figure: Figure = Figure(data=[Bar(name="Prix", x=data["product"], y=data["price"])]) figure.add_hrect(y0=2.75, y1=4.5, fillcolor="gray", opacity=0.25, layer="below") figure.update_layout( template="seaborn", title="Prix et poids unitaires", font={"family": "Cabin", "size": 13}, xaxis={"title": "Produit", "showgrid": False}, yaxis={"title": "Prix (€)", "showgrid": False} ) figure.show(renderer="browser") ``` ---- ![Ajout d'un rectangle horizontal](assets/images/eda-plotly-trace-hrect.png) ---- #### Options de rectangle | Argument | Type / valeur possible | Description / notes | |-------------|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `y0` | nombre | Position verticale de la ligne en bas (relative à `yref`). | | `y1` | nombre | Position verticale de la ligne en haut (relative à `yref`). | | `yref` | `"paper"` / `"pixel"` / `"y"` | Référence verticale de la ligne. Lorsque `yref` vaut `"paper"`, `y` est relative à la hauteur totale du graphique. Lorsque `yref` vaut `"pixel"`, `y` est en pixels. | | `fillcolor` | `str` (couleur HTML) | Couleur de remplissage de la ligne. | | `line` | `dict` | Dictionnaire des propriétés de la ligne (voir la documentation de Plotly). | | `opacity` | `float` ∈ [0, 1] | Opacité de la ligne. | | `layer` | `"above"` / `"below"` / `"between"` | Couche de la ligne par rapport aux autres éléments du graphique. | ---- ### Tracer une ligne ou une courbe de régression Pour analyser la tendance générale de la disposition des points d'un jeu de données, il est souvent intéressant de tracer des courbes (polynômes) ou des lignes. Numpy propose une fonction de régression pour des points 2D, capable de générer les coefficients d'une fonction polynômiale du `n`ième degré : `np.polyfit()`{.python} ---- ```python {.numberLines} import pandas as pd import numpy as np from plotly.graph_objs import Figure, Scatter from scipy.ndimage import gaussian_filter # Créer une courbe aléatoire lissée df = pd.DataFrame(data={"col1": gaussian_filter(np.random.random(size=200) * 79.0 + 1.0, sigma=1.5)}) # Calculer les coefficients d'une régression de degré 2 pour col1 c2, c1, c0 = np.polyfit(df.index, df["col1"], 2) df["reg1"] = df.index ** 2 * c2 + df.index * c1 + c0 # Créer une image avec deux lignes figure = Figure([ Scatter(name="values", x=df.index, y=df["col1"], line={"color": "black", "width": 2}, marker={"symbol": "circle"}, mode="lines+markers"), Scatter(name="regression", x=df.index, y=df["reg1"], line={"color": "red", "width": 4, "dash": "dot"}, mode="lines") ]) figure.layout.update({"template": "seaborn", "xaxis1": {"title": "time"}, "title": "Test de régression", "font": {"family": "Cabin", "size": 13}, "yaxis1": {"title": "value"}}) figure.show(renderer="browser") ``` Calcul et tracé d'une courbe sur un graphique avec `scipy` et `Plotly` ---- ![Rendu courbe de régression polynômiale du second degré](assets/images/eda-plotly-regression-curve.png)