From c45c6e9f2dfc2aa13ab311d673b019e3049e8442 Mon Sep 17 00:00:00 2001 From: Steve Kossouho Date: Mon, 27 Oct 2025 21:20:17 +0100 Subject: [PATCH] 2025.44 changes --- documentation/02.2-eda-plotly.md | 280 ++++++++++++++++-- .../images/eda-plotly-colors-continuous.svg | 1 + .../images/eda-plotly-colors-qualitative.svg | 1 + .../images/eda-plotly-colors-sequential.svg | 1 + .../eda-plotly-express-bar-colors-custom.png | Bin 0 -> 92824 bytes ...a-plotly-express-bar-colors-predefined.png | Bin 0 -> 97191 bytes ...a-plotly-express-pie-colors-predefined.png | Bin 0 -> 73612 bytes .../assets/images/eda-plotly-subplot-base.png | Bin 0 -> 91256 bytes .../eda-plotly-subplot-widths-heights.png | Bin 0 -> 92230 bytes .../assets/images/eda-plotly-trace-hrect.png | Bin 0 -> 38049 bytes .../assets/images/eda-plotly-trace-image.png | Bin 0 -> 65835 bytes .../charts/eda-plotly-colors-continuous.svg | 1 + .../charts/eda-plotly-colors-qualitative.svg | 1 + .../charts/eda-plotly-colors-sequential.svg | 1 + .../plotting/charts/images/astral-python.png | Bin 0 -> 1018 bytes .../charts/images/python-logo-square.png | Bin 0 -> 90167 bytes source/plotting/charts/images/svelte.webp | Bin 0 -> 12438 bytes source/plotting/charts/plotly_bar_colors.py | 17 ++ .../charts/plotly_bar_colors_custom.py | 17 ++ source/plotting/charts/plotly_pie_colors.py | 14 + source/plotting/charts/plotly_subplot_base.py | 19 ++ .../plotting/charts/plotly_subplot_widths.py | 14 + source/plotting/charts/plotly_swatches.py | 55 ++++ source/plotting/charts/plotly_trace_image.py | 30 ++ .../plotting/charts/plotly_trace_rectangle.py | 20 ++ 25 files changed, 446 insertions(+), 26 deletions(-) create mode 100644 documentation/assets/images/eda-plotly-colors-continuous.svg create mode 100644 documentation/assets/images/eda-plotly-colors-qualitative.svg create mode 100644 documentation/assets/images/eda-plotly-colors-sequential.svg create mode 100644 documentation/assets/images/eda-plotly-express-bar-colors-custom.png create mode 100644 documentation/assets/images/eda-plotly-express-bar-colors-predefined.png create mode 100644 documentation/assets/images/eda-plotly-express-pie-colors-predefined.png create mode 100644 documentation/assets/images/eda-plotly-subplot-base.png create mode 100644 documentation/assets/images/eda-plotly-subplot-widths-heights.png create mode 100644 documentation/assets/images/eda-plotly-trace-hrect.png create mode 100644 documentation/assets/images/eda-plotly-trace-image.png create mode 100644 source/plotting/charts/eda-plotly-colors-continuous.svg create mode 100644 source/plotting/charts/eda-plotly-colors-qualitative.svg create mode 100644 source/plotting/charts/eda-plotly-colors-sequential.svg create mode 100644 source/plotting/charts/images/astral-python.png create mode 100644 source/plotting/charts/images/python-logo-square.png create mode 100644 source/plotting/charts/images/svelte.webp create mode 100644 source/plotting/charts/plotly_bar_colors.py create mode 100644 source/plotting/charts/plotly_bar_colors_custom.py create mode 100644 source/plotting/charts/plotly_pie_colors.py create mode 100644 source/plotting/charts/plotly_subplot_base.py create mode 100644 source/plotting/charts/plotly_subplot_widths.py create mode 100644 source/plotting/charts/plotly_swatches.py create mode 100644 source/plotting/charts/plotly_trace_image.py create mode 100644 source/plotting/charts/plotly_trace_rectangle.py diff --git a/documentation/02.2-eda-plotly.md b/documentation/02.2-eda-plotly.md index 0a65161..d8114aa 100644 --- a/documentation/02.2-eda-plotly.md +++ b/documentation/02.2-eda-plotly.md @@ -542,52 +542,280 @@ 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={ - "product": ["pomme", "poire", "banane", "pêche"], - "price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200] + "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="product", title="Prix", color_discrete_sequence=["red", "orange", "yellow", "#8F0"]) -figure.layout.update({"template": "seaborn", "title": "Prix au kilo", "font": {"family": "Cabin", "size": 13}}) -figure.show() +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") ``` -Plotly Express fournit des séquences ou dégradés de couleurs, dont la référence est disponible ci-dessous : +---- -[Couleurs et séquences de couleurs](https://plotly.com/python/discrete-color/) +![Rendu avec choix de couleurs par secteur](assets/images/eda-plotly-express-pie-colors-predefined.png) ---- -![Rendu avec choix de couleurs par secteur](assets/images/eda-plotly-express-pie-colors.png) +### Gradients de couleurs ----- - -### Couleur dépendante de la valeur - -Vous pouvez sur certains graphiques définir un gradient à appliquer aux éléments du dessin -selon une valeur qui leur est associée. Ici, nous avons un graphique en barres, où la couleur -de chaque barre dépend de la valeur de la colonne `price`. +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 -data = pd.DataFrame(data={ - "product": ["pomme", "poire", "banane", "pêche"], - "price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200] + +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] }) -figure = px.bar(data, y="price", x="product", title="Prix", color="price", color_continuous_scale=["red", "orange", "yellow", "#8F0"]) -figure.layout.update({"template": "seaborn", "title": "Prix au kilo", "font": {"family": "Cabin", "size": 13}}) -figure.show() +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() ``` -Ici, l'argument `color` permet d'indiquer sur les valeurs de quelle colonne colorier les barres. -L'argument `color_continuous_scale` permet de définir les couleurs d'un dégradé à utiliser pour -colorier les barres. - ---- -![Rendu avec gradient de couleurs](assets/images/eda-plotly-express-bar-gradient.png) +![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. | ---- diff --git a/documentation/assets/images/eda-plotly-colors-continuous.svg b/documentation/assets/images/eda-plotly-colors-continuous.svg new file mode 100644 index 0000000..843066f --- /dev/null +++ b/documentation/assets/images/eda-plotly-colors-continuous.svg @@ -0,0 +1 @@ +Brwnyl Agsunset Sunsetdark Magenta Sunset Purpor Purp Tealgrn Teal Bluyl Aggrnyl Emrld Darkmint Blugrn Mint Pinkyl Peach Oryel Redor Burgyl Burg tempo amp speed matter algae dense deep gray ice solar haline thermal turbid YlOrRd YlOrBr YlGnBu YlGn Reds RdPu RdBu Purples PuRd PuBuGn PuBu Oranges OrRd Greys Greens GnBu BuPu BuGn Blues Rainbow Jet Hot Electric Bluered Blackbody Turbo Plasma Magma Inferno Cividis Viridis Plotly3 Palette de couleurs continues Plotly Sequential \ No newline at end of file diff --git a/documentation/assets/images/eda-plotly-colors-qualitative.svg b/documentation/assets/images/eda-plotly-colors-qualitative.svg new file mode 100644 index 0000000..10da0f7 --- /dev/null +++ b/documentation/assets/images/eda-plotly-colors-qualitative.svg @@ -0,0 +1 @@ +Vivid Safe Prism Pastel Bold Antique Set3 Pastel2 Set2 Dark2 Pastel1 Set1 Light24 Dark24 Alphabet T10 G10 D3 Plotly Palette de couleurs qualitatives Plotly Qualitative \ No newline at end of file diff --git a/documentation/assets/images/eda-plotly-colors-sequential.svg b/documentation/assets/images/eda-plotly-colors-sequential.svg new file mode 100644 index 0000000..7900748 --- /dev/null +++ b/documentation/assets/images/eda-plotly-colors-sequential.svg @@ -0,0 +1 @@ +Brwnyl Agsunset Sunsetdark Magenta Sunset Purpor Purp Tealgrn Teal Bluyl Aggrnyl Emrld Darkmint Blugrn Mint Pinkyl Peach Oryel Redor Burgyl Burg tempo amp speed matter algae dense deep gray ice solar haline thermal turbid YlOrRd YlOrBr YlGnBu YlGn Reds RdPu RdBu Purples PuRd PuBuGn PuBu Oranges OrRd Greys Greens GnBu BuPu BuGn Blues Rainbow Jet Hot Electric Bluered Blackbody Turbo Plasma Magma Inferno Cividis Viridis Plotly3 Palette de couleurs séquentielles Plotly Sequential \ No newline at end of file diff --git a/documentation/assets/images/eda-plotly-express-bar-colors-custom.png b/documentation/assets/images/eda-plotly-express-bar-colors-custom.png new file mode 100644 index 0000000000000000000000000000000000000000..7156a894d7a0e88251d953509d0a9b327dbf38e5 GIT binary patch literal 92824 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
  • @nq-Xe&5`pCGb!!`ZAFlIA={zLLs#7f^Q4Q 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 X&62rm1sClFI)lN})z4*}Q$iB}$s@O5 literal 0 HcmV?d00001 diff --git a/source/plotting/charts/images/svelte.webp b/source/plotting/charts/images/svelte.webp new file mode 100644 index 0000000000000000000000000000000000000000..70589d0f65bf20a9d423e9fb049a0ea1ce887f9b GIT binary patch literal 12438 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 literal 0 HcmV?d00001 diff --git a/source/plotting/charts/plotly_bar_colors.py b/source/plotting/charts/plotly_bar_colors.py new file mode 100644 index 0000000..9b2386d --- /dev/null +++ b/source/plotting/charts/plotly_bar_colors.py @@ -0,0 +1,17 @@ +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() diff --git a/source/plotting/charts/plotly_bar_colors_custom.py b/source/plotting/charts/plotly_bar_colors_custom.py new file mode 100644 index 0000000..a88a102 --- /dev/null +++ b/source/plotting/charts/plotly_bar_colors_custom.py @@ -0,0 +1,17 @@ +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() diff --git a/source/plotting/charts/plotly_pie_colors.py b/source/plotting/charts/plotly_pie_colors.py new file mode 100644 index 0000000..cec95c0 --- /dev/null +++ b/source/plotting/charts/plotly_pie_colors.py @@ -0,0 +1,14 @@ +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, 279.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", color_discrete_sequence=qualitative.Bold) +figure.layout.update({"template": "seaborn", "title": "Prix à l'unité", "font": {"family": "Cabin", "size": 13}, "width": 1080, "height": 720}) +figure.update_traces(textposition="inside", textinfo="percent+label", texttemplate="%{label}
    %{value}€ (%{percent:.2%})") +figure.show() diff --git a/source/plotting/charts/plotly_subplot_base.py b/source/plotting/charts/plotly_subplot_base.py new file mode 100644 index 0000000..1e93647 --- /dev/null +++ b/source/plotting/charts/plotly_subplot_base.py @@ -0,0 +1,19 @@ +import pandas as pd +from plotly._subplots import SubplotXY +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=3, subplot_titles=("Prix", "Poids unitaires")) +subplot = figure.get_subplot(row=1, col=2) +subplot.xaxis["domain"] = [0.3555555, 1.0] +print(subplot, dir(subplot)) +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.update_traces(row=1, col=2, specs=2) +figure.show(renderer="browser") diff --git a/source/plotting/charts/plotly_subplot_widths.py b/source/plotting/charts/plotly_subplot_widths.py new file mode 100644 index 0000000..4db480a --- /dev/null +++ b/source/plotting/charts/plotly_subplot_widths.py @@ -0,0 +1,14 @@ +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() diff --git a/source/plotting/charts/plotly_swatches.py b/source/plotting/charts/plotly_swatches.py new file mode 100644 index 0000000..22c857f --- /dev/null +++ b/source/plotting/charts/plotly_swatches.py @@ -0,0 +1,55 @@ +import plotly.express as px +from plotly.graph_objects import Figure, Scatter + +COLS: int = 3 +fig: Figure = px.colors.sequential.swatches_continuous() +fig3: Figure = px.colors.qualitative.swatches() +figb: Figure = px.colors.sequential.swatches() + +fig2 = Figure(layout={ + "title": "Palette de couleurs continues Plotly Sequential", + "font": {"family": "Cabin", "size": 13}, + "xaxis": {"visible": False, "showticklabels": False}, + "yaxis": {"visible": False, "showticklabels": False}, + "legend": {"visible": False}, + "width": 1400, +}).set_subplots(rows=22, cols=COLS) +for i, p in enumerate(fig.select_traces()): #type: int, Scatter + fig2.add_trace(p, row= (i // COLS) + 1, col=(i % COLS) + 1) +fig2.update_xaxes({"visible": False, "showticklabels": False, "showgrid": False}) +fig2.update_yaxes({"visible": True, "showticklabels": True, "showgrid": False}) +fig2.update_yaxes(tickfont={"size": 11}, ticksuffix=" ") +fig2.write_image("eda-plotly-colors-continuous.svg") +# fig2.show(renderer="browser") + +fig4 = Figure(layout={ + "title": "Palette de couleurs séquentielles Plotly Sequential", + "font": {"family": "Cabin", "size": 13}, + "xaxis": {"visible": False, "showticklabels": False}, + "yaxis": {"visible": False, "showticklabels": False}, + "legend": {"visible": False}, + "width": 1400, + "margin": {"t": 100, "b": 50, "l": 60, "r": 50}, +}).set_subplots(rows=22, cols=COLS) +for i, p in enumerate(figb.select_traces()): #type: int, Scatter + fig4.add_trace(p, row= (i // COLS) + 1, col=(i % COLS) + 1) +fig4.update_xaxes({"visible": False, "showticklabels": False, "showgrid": False}) +fig4.update_yaxes({"visible": True, "showticklabels": True, "showgrid": False}) +fig4.update_yaxes(tickfont={"size": 11}, ticksuffix=" ") +fig4.write_image("eda-plotly-colors-sequential.svg") + +fig3.update_layout({ + "title": "Palette de couleurs qualitatives Plotly Qualitative", + "font": {"family": "Cabin", "size": 13}, + "xaxis": {"visible": False, "showticklabels": False}, + "yaxis": {"visible": False, "showticklabels": False}, + "legend": {"visible": False}, + "width": 1200, + "margin": {"t": 100, "b": 50, "l": 60, "r": 50}, +}) +fig3.update_xaxes({"visible": False, "showticklabels": False, "showgrid": False}) +fig3.update_yaxes({"visible": True, "showticklabels": True, "showgrid": False}) +fig3.update_yaxes(tickfont={"size": 11}, ticksuffix=" ") +fig3.write_image("eda-plotly-colors-qualitative.svg") + + diff --git a/source/plotting/charts/plotly_trace_image.py b/source/plotting/charts/plotly_trace_image.py new file mode 100644 index 0000000..b551a14 --- /dev/null +++ b/source/plotting/charts/plotly_trace_image.py @@ -0,0 +1,30 @@ +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") diff --git a/source/plotting/charts/plotly_trace_rectangle.py b/source/plotting/charts/plotly_trace_rectangle.py new file mode 100644 index 0000000..70c6d4b --- /dev/null +++ b/source/plotting/charts/plotly_trace_rectangle.py @@ -0,0 +1,20 @@ +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")