diff --git a/README.md b/README.md index f282e3264e8ad44e09fbf07a87cae2c52d3b1d38..48de65db2ce4f89595c6a1a911d67f0bd7d7d266 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ # Streamlit Projet -Lien en ligne du logiciel : https://app-project-gem6konsqjctcv2zfkc54v.streamlit.app/ \ No newline at end of file +Arborescance de l'application : +- data : le répertoire contient les données nécessaires au bon fonctionnement du logiciel +- onglets : contient les différents types de graphiques (bar horizontale, etc.) +- utils : contient l'ensemble des fonctions nécessaires au bon fonctionnement de l'application + +Ce logiciel a été mis en ligne via Github et accessible à partir de ce lien : https://app-project-gem6konsqjctcv2zfkc54v.streamlit.app/ + +Une barre de sélection avec un entier correspond au nombre de lignes qu'on affiche dans le graphique à partir des données (compter à partir de la première ligne des données). + +Pour pouvoir mettre une couleur de légende, il faut sélectionner la colonne "numero_color" des données de test, qui correspond à l'index des couleurs de chaque barre horizontale. De plus, on peut saisir manuellement le nom de la couleur. + + + + diff --git a/app.py b/app.py index 4b4edb57a2524540673bfb4ec6f7bedf7355e67b..8ee249a2cae03507866ece6de4b6527f28c98843 100644 --- a/app.py +++ b/app.py @@ -5,138 +5,14 @@ from matplotlib.colors import LinearSegmentedColormap, ListedColormap, to_hex import matplotlib.patches as mpatches from io import BytesIO -import utils_graph -from utils_graph import plot_graph +import utils.utils_graph as utils_graph +from utils.utils_graph import plot_graph -st.title('Logiciel cartographique') - -upload_file = st.file_uploader('Charger vos données en format .csv ou .xlsx.') - -if upload_file is not None : - - # chargement des données - filename = upload_file.name - - # vérifie la forme des données - if filename.endswith('.csv'): - df = pd.read_csv(upload_file) - st.success("Fichier CSV chargé avec succès.") - - elif filename.endswith('.xlsx') or filename.endswith('.xls'): - df = pd.read_excel(upload_file) - st.success("Fichier Excel chargé avec succès.") - - else: - st.error("Format de fichier non supporté. Veuillez charger un .csv ou un .xlsx.") - - # visualisation des données - st.header('Visualisation des données :') - st.write(df.head(5)) # pour 5 lignes - - # bloc sur les infos du dataframe - st.subheader('Information sur les données :') - with st.expander("📊 Aperçu du DataFrame"): - st.markdown(f"**Dimensions :** {df.shape[0]} lignes × {df.shape[1]} colonnes") - st.markdown("**Colonnes disponibles :**") - st.write(list(df.columns)) - st.markdown("**Types de données :**") - st.write(df.dtypes) - - st.subheader('Choix d\'option :') - if df.shape[0]>12 : - nb_line = st.number_input( - "Nombre de lignes à afficher", - min_value=1, - max_value=len(df), - value=5, - step=1, - format="%d" # ↠force l'affichage et le retour d'un entier - ) - - # choix des colonnes à tracer - columns = df.columns.tolist() - - col_x = st.selectbox('Choisir la colonne des valeurs (x)', columns) - col_y = st.selectbox('Choisir la colonne des catégories (y)', columns) - - title_choice = st.checkbox("Voulez-vous mettre un titre au graphique ?") - if title_choice: - title = st.text_input("Entrez le titre du graphique :", key="title_input") - else: - title = None +from onglets import onglet1 - x_choice = st.checkbox("Voulez-vous nommer l'axe des abscisses ?") - if x_choice: - xlabel = st.text_input("Entrez le nom de l'axe des abscisses :", key="xlabel_input") - else: - xlabel = None - - y_choice = st.checkbox("Voulez-vous nommer l'axe des ordonnées ?") - if y_choice: - ylabel = st.text_input("Entrez le nom de l'axe des ordonnées :", key="ylabel_input") - else: - ylabel = None - - model_graph = utils_graph.plot_graph(df = df.loc[:nb_line-1, :], x = col_x, y = col_y) - legend_choice = st.checkbox('Voulez-vous mettre une légende de couleurs ?') - - if legend_choice: - col_color = st.selectbox('Choisir la colonne des numéros de couleurs', columns) - - try : - # Premier tracé pour générer list_colors - model_graph.barh_subplot(colors=col_color, show=False, title= title, xlabel= xlabel, ylabel=ylabel) - colors_rgba = model_graph.list_colors - - custom_colors = {} - legend_labels = [] - legend_indices = [] - - st.markdown("Personnalisation des couleurs et des légendes :") - - for i, rgba in enumerate(colors_rgba): - hex_color = to_hex(rgba) - col1, col2 = st.columns(2) - with col1: - picked_color = st.color_picker(f"Couleur {i+1}", hex_color) - with col2: - label = st.text_input(f"Légende {i+1}", key=f"legend_{i}") - - if label.strip(): # légende non vide - legend_labels.append(label) - legend_indices.append(i) - custom_colors[i] = {"color": picked_color, "label": label} - - # Retracer avec légendes non vides - barh = model_graph.barh_subplot( - colors=col_color, - legend_list=legend_labels, - title_legend="Légende", - legend_indices=legend_indices, - title= title, - xlabel= xlabel, - ylabel= ylabel - ) - - st.pyplot(barh) - - except Exception as e: - st.warning("âš ï¸ Cette colonne ne semble pas contenir des numéros de couleurs valides.") - - else: - # Tracer sans légende - barh = model_graph.barh_subplot(title= title, xlabel= xlabel, ylabel= ylabel) - st.pyplot(barh) +st.title('Logiciel cartographique') - # Sauvegarde du graphique dans un buffer en mémoire - img_buffer = BytesIO() - barh.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight') - img_buffer.seek(0) # Revenir au début du buffer +option = st.sidebar.selectbox("Choisir le format du graphique :", ("Graphique en barre horizontale","Histogramme")) - # Bouton de téléchargement - st.download_button( - label="📥 Télécharger le graphique", - data=img_buffer, - file_name="mon_graphique.png", - mime="image/png" - ) +if option == "Graphique en barre horizontale" : + onglet1.display() \ No newline at end of file diff --git a/onglets/__pycache__/onglet1.cpython-312.pyc b/onglets/__pycache__/onglet1.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ff1334974f64fdca5dd440f8446d4991fcbb0ae Binary files /dev/null and b/onglets/__pycache__/onglet1.cpython-312.pyc differ diff --git a/onglets/onglet1.py b/onglets/onglet1.py new file mode 100644 index 0000000000000000000000000000000000000000..199e248287160c207f201e3a47a6da83d23b9f0f --- /dev/null +++ b/onglets/onglet1.py @@ -0,0 +1,147 @@ +import streamlit as st +import pandas as pd +from matplotlib.colors import to_hex +from io import BytesIO +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'utils'))) + +import utils.utils_graph as utils_graph + + +def display() : + upload_file = st.file_uploader('Charger vos données en format .csv ou .xlsx.') + + if upload_file is not None : + + # chargement des données + filename = upload_file.name + + # vérifie la forme des données + if filename.endswith('.csv'): + df = pd.read_csv(upload_file) + st.success("Fichier CSV chargé avec succès.") + + elif filename.endswith('.xlsx') or filename.endswith('.xls'): + df = pd.read_excel(upload_file) + st.success("Fichier Excel chargé avec succès.") + + else: + st.error("Format de fichier non supporté. Veuillez charger un .csv ou un .xlsx.") + + # visualisation des données + st.header('Visualisation des données :') + st.write(df.head(5)) # pour 5 lignes + + # bloc sur les infos du dataframe + st.subheader('Information sur les données :') + with st.expander("📊 Aperçu du DataFrame"): + st.markdown(f"**Dimensions :** {df.shape[0]} lignes × {df.shape[1]} colonnes") + st.markdown("**Colonnes disponibles :**") + st.write(list(df.columns)) + st.markdown("**Types de données :**") + st.write(df.dtypes) + + st.subheader('Choix d\'option :') + if df.shape[0]>12 : + nb_line = st.number_input( + "Nombre de lignes à afficher", + min_value=1, + max_value=len(df), + value=5, + step=1, + format="%d" # ↠force l'affichage et le retour d'un entier + ) + + # choix des colonnes à tracer + columns = df.columns.tolist() + + col_x = st.selectbox('Choisir la colonne des valeurs (x)', columns) + col_y = st.selectbox('Choisir la colonne des catégories (y)', columns) + + title_choice = st.checkbox("Voulez-vous mettre un titre au graphique ?") + if title_choice: + title = st.text_input("Entrez le titre du graphique :", key="title_input") + else: + title = None + + x_choice = st.checkbox("Voulez-vous nommer l'axe des abscisses ?") + if x_choice: + xlabel = st.text_input("Entrez le nom de l'axe des abscisses :", key="xlabel_input") + else: + xlabel = None + + y_choice = st.checkbox("Voulez-vous nommer l'axe des ordonnées ?") + if y_choice: + ylabel = st.text_input("Entrez le nom de l'axe des ordonnées :", key="ylabel_input") + else: + ylabel = None + + model_graph = utils_graph.plot_graph(df = df.loc[:nb_line-1, :], x = col_x, y = col_y) + legend_choice = st.checkbox('Voulez-vous mettre une légende de couleurs ?') + + #annotation = st.checkbox('Voulez-cous mettre une annotation ?') + #if annotation : + # col_nombre = st.selectbox('Colonne des valeurs absolues', columns) + + if legend_choice: + col_color = st.selectbox('Choisir la colonne des numéros de couleurs', columns) + + try : + # Premier tracé pour générer list_colors + model_graph.barh_subplot(colors=col_color, show=False, title= title, xlabel= xlabel, ylabel=ylabel) + colors_rgba = model_graph.list_colors + + custom_colors = {} + legend_labels = [] + legend_indices = [] + + st.markdown("Personnalisation des couleurs et des légendes :") + + for i, rgba in enumerate(colors_rgba): + hex_color = to_hex(rgba) + col1, col2 = st.columns(2) + with col1: + picked_color = st.color_picker(f"Couleur {i+1}", hex_color) + with col2: + label = st.text_input(f"Légende {i+1}", key=f"legend_{i}") + + if label.strip(): # légende non vide + legend_labels.append(label) + legend_indices.append(i) + custom_colors[i] = {"color": picked_color, "label": label} + + # Retracer avec légendes non vides + barh = model_graph.barh_subplot( + colors=col_color, + legend_list=legend_labels, + title_legend="Légende", + legend_indices=legend_indices, + title= title, + xlabel= xlabel, + ylabel= ylabel + ) + + st.pyplot(barh) + + except Exception as e: + st.warning("âš ï¸ Cette colonne ne semble pas contenir des numéros de couleurs valides.") + + else: + # Tracer sans légende + barh = model_graph.barh_subplot(title= title, xlabel= xlabel, ylabel= ylabel) + st.pyplot(barh) + + # Sauvegarde du graphique dans un buffer en mémoire + img_buffer = BytesIO() + barh.savefig(img_buffer, format='png', dpi=300, bbox_inches='tight') + img_buffer.seek(0) # Revenir au début du buffer + + # Bouton de téléchargement + st.download_button( + label="📥 Télécharger le graphique", + data=img_buffer, + file_name="mon_graphique.png", + mime="image/png" + ) diff --git a/onglets/onglet2.py b/onglets/onglet2.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/utils/__pycache__/utils_graph.cpython-312.pyc b/utils/__pycache__/utils_graph.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea4c79ac17785b3e3b8ee181f5d9b7f84ff1dd50 Binary files /dev/null and b/utils/__pycache__/utils_graph.cpython-312.pyc differ diff --git a/utils/test_notebook.ipynb b/utils/test_notebook.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..47eb8a79157e17d0a88addede9d1084011b2c651 --- /dev/null +++ b/utils/test_notebook.ipynb @@ -0,0 +1,84 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from utils_graph import plot_graph" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(r'../data/df_cfa_anonyme.xlsx')\n", + "df = df.loc[:12,:]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "model = plot_graph(df = df, x = 'count', y = 'denomination_cfa')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "<Figure size 1000x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "graph = model.barh_subplot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/utils_graph.py b/utils/utils_graph.py similarity index 63% rename from utils_graph.py rename to utils/utils_graph.py index c97694ee34db567bb906553580c87d76568288e0..588399ab4a9ca4644fb751f79b0f9cfdf32ca591 100644 --- a/utils_graph.py +++ b/utils/utils_graph.py @@ -41,7 +41,7 @@ class plot_graph() : if self.ax is None or self.fig is None or force_new_fig: self.fig, self.ax = plt.subplots(figsize=self.figsize) - bars = self.ax.barh(self.y, self.x, color = colors_bars, hatch = hatches) + self.bars = self.ax.barh(self.y, self.x, color = colors_bars, hatch = hatches) if legend_list and colors is not None: legend_elements = [] @@ -86,53 +86,29 @@ class plot_graph() : return self.fig # partie à revoir selon les besoins des missions - def annotation(self) : + def annotation(self, pourcentage = None, Nombre = None) : - """ # Ajouter des annotations sur les barres - if pourcentage_list == False : - for n, bar in enumerate(bars): + if pourcentage and not Nombre : + for n, bar in enumerate(self.bars) : width = bar.get_width() - if np.isnan(width): - # Gérer le cas où la largeur est NaN - text = "N/A" - elif nombre and slash : - text = f"{round(width)}/{self.df.loc[n,slash]}" - elif nombre and slash == False : - text = f"{round(width)}" - else: - if pourcentage and self.df.shape[0]<10: - text = f"{round((width / self.df['count'].sum()) * 100, 1)}% ({int(width)})" - elif pourcentage and self.df.shape[0]>=10: - text = f"{round((width / total) * 100, 1)}% ({int(width)})" - else : - text = f"{round(width)}%" - - if width == 0 : - ax.text(2 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, - text,va='center', ha='left', color='gray', fontsize=9) - else : - ax.text(width * 1.01 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, + text = self.df.loc[n,pourcentage] + self.ax.text(width * 1.01 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, text, va='center', ha='left', color='gray', fontsize=9) - - elif pourcentage_list != False: - for n,bar in enumerate(bars): + + elif Nombre and not pourcentage : + for n, bar in enumerate(self.bars) : width = bar.get_width() - if np.isnan(width): - # Gérer le cas où la largeur est NaN - text = "N/A" - elif inverse : - text = f"{width}% ({self.df.loc[n,pourcentage_list]})" - - else : - text = f"{self.df.loc[n,pourcentage_list]}% ({width})" - if width == 0 : - ax.text(2 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, - text,va='center', ha='left', color='gray', fontsize=9) - else : - ax.text(width * 1.01 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, - text, va='center', ha='left', color='gray', fontsize=9)""" + text = self.df.loc[n,Nombre] + self.ax.text(width * 1.01 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, + text, va='center', ha='left', color='gray', fontsize=9) - pass + elif Nombre and pourcentage : + for n, bar in enumerate(self.bars) : + width = bar.get_width() + text = f'{self.df.loc[n,Nombre]} ({self.df.loc[n,pourcentage]} %)' + self.ax.text(width * 1.01 if not np.isnan(width) else 0 , bar.get_y() + bar.get_height() / 2, + text, va='center', ha='left', color='gray', fontsize=9) + def encadrer(self) :