import os # Définissez un répertoire accessible en écriture pour le cache de Matplotlib os.environ['MPLCONFIGDIR'] = '/path/to/writable/directory' import numpy as np import matplotlib.pyplot as plt import plotly.graph_objs as go import plotly.express as px import io from io import StringIO import plotly.graph_objects as go from plotly.subplots import make_subplots from sklearn.model_selection import cross_val_score from sklearn.linear_model import LinearRegression from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline import hvplot.pandas import panel as pn import param import pandas as pd from sklearn.base import BaseEstimator, RegressorMixin from scipy.optimize import curve_fit from sklearn.metrics import r2_score from sklearn.model_selection import train_test_split import math # Activer les extensions KaTeX et MathJax pn.extension('katex', 'mathjax', 'plotly') # Modèles de régression def lewis(t, k): return np.exp(-k * t) def henderson_pabis(t, a, k): return a * np.exp(-k * t) def page(t, k, n): return np.exp(-k * t**n) def modified_page(t, k, n): return np.exp(-(k * t)**n) def logarithmic(t, a, k, c): return a * np.exp(-k * t) + c def two_term(t, a, k0, b, k1): return a * np.exp(-k0 * t) + b * np.exp(-k1 * t) def two_term_exponential(t, a, k): return a * np.exp(-k * t) + (1 - a) * np.exp(-k*a * t) def approximation_diffusion(t, a, k, b): return a * np.exp(-k * t) + (1 - a) * np.exp(-k*b * t) def verma_et_al(t, a, k, g): return a * np.exp(-k * t) + (1 - a) * np.exp(-g * t) def midilli_et_al(t, a, k, b, n): return a * np.exp(-k * (t)**n) + b * t # Liste des modèles models = [ lewis, henderson_pabis, page, modified_page, logarithmic, two_term, two_term_exponential, approximation_diffusion, verma_et_al, midilli_et_al ] #--------------------------------------------------------- # Expressions LaTeX r_squared_formula = pn.pane.LaTeX(r""" $R^2 = \frac{\sum_{i=1}^{n}(X_{\text{pred},i} - \overline{X}_{\text{pred}})^2}{\sum_{i=1}^{n}(X_{\text{exp},i} - \overline{X}_{\text{exp}})^2}$ """, styles={'font-size': '16pt'}) chi_square_formula = pn.pane.LaTeX(object=r""" $\chi^2 = \frac{\sum_{i=1}^{n}(X_{\text{exp},i} - X_{\text{pred},i})^2}{N-n}$ """, styles={'font-size': '16pt'}) text_01 = pn.pane.LaTeX(r""" $Xr_{\text{pred},i} $: la i-ème teneur en eau prédite selon le modèle """) text_02 = pn.pane.LaTeX(r""" $Xr_{\text{exp},i} $: la i-ème teneur en eau réduite expérimentale """) text_03 = pn.pane.LaTeX(r""" $N $: le nombre de points expérimentaux """) text_04 = pn.pane.LaTeX(r""" $n$ : le nombre de constantes de chaque modèle """) # Les modèles de fonctions mathématiques Lewis = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = e^{-kt}$""", styles={'font-size': '16pt'}) Henderson_and_Pabis = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{-kt}$""", styles={'font-size': '16pt'}) Page = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{-k(t)^{n}} $""", styles={'font-size': '16pt'}) Logarithmique = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{-kt} + c$""", styles={'font-size': '16pt'}) Two_term = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{(-k_{0}t)} + be^{(-k_{1}t)} $""", styles={'font-size': '16pt'}) Two_term_exponential = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{(-kt)} + (1-a)e^{(-kta)} $""", styles={'font-size': '16pt'}) Approximation_of_diffusion = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{(-kt)} + (1-a)e^{(-ktb)} $""", styles={'font-size': '16pt'}) Verma_et_al = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{(-kt)} + (1-a)e^{(-tg)} $""", styles={'font-size': '16pt'}) Midilli_et_al = pn.pane.LaTeX(object=r""" $\checkmark X_{r} = ae^{-k(t)^{n}} + bt$""", styles={'font-size': '16pt'}) #Liste Informatif pour le choix de la variete des donnees a saisir def afficher_varietes_oignons(varietes): dropdown = pn.widgets.Select(options=varietes) def on_dropdown_change(event): selected_variety = dropdown.value print(f"Variété sélectionnée : {selected_variety}") dropdown.param.watch(on_dropdown_change, 'value') layout = pn.Column( pn.Row(pn.panel("Sélectionnez la variété d'oignons :", align="center"), align="center"), dropdown ) return layout # Liste des variétés d'oignons varietes_oignons = ['Safari', 'Galmin ','Gandiol F1', 'Orient F1'] afficher_varietes_oignons(varietes_oignons) # Créer un panneau pour les expressions LaTeX et les résultats left_panel = pn.Column( pn.Row(afficher_varietes_oignons(varietes_oignons)), pn.pane.Markdown("## Formules Mathématiques"), r_squared_formula, chi_square_formula, text_01, text_02, text_03, text_04, pn.pane.Markdown("# Liste des Modeles : "), pn.pane.Markdown("## Lewis : "), Lewis, pn.pane.Markdown("## Henderson and Pabis: "), Henderson_and_Pabis, pn.pane.Markdown("## Page: "), Page, pn.pane.Markdown("## Logarithmique: "), Logarithmique, pn.pane.Markdown("## Two-term: "), Two_term, pn.pane.Markdown("## Two-term exponential: "), Two_term_exponential, pn.pane.Markdown("## Approximation of diffusion: "), Approximation_of_diffusion, pn.pane.Markdown("## Verma et al.: "), Verma_et_al, pn.pane.Markdown("## Midilli et al.: "), Midilli_et_al, width=450, # Ajustez la largeur selon vos préférences height=1500 # Ajustez la hauteur selon vos préférences ) #__________________________________________________________ # Classe pour la régression non linéaire class NonLinearRegression(BaseEstimator, RegressorMixin): def __init__(self, model): self.model = model self.params = None def fit(self, X, y, maxfev=1000, bounds=(-np.inf, np.inf)): t = X.flatten() self.params, _ = curve_fit(self.model, t, y, maxfev=maxfev, bounds=bounds) return self def predict(self, X): t = X.flatten() return self.model(t, *self.params) def score(self, X, y): y_pred = self.predict(X) r2 = r2_score(y, y_pred) # Calculer X² (Somme des carrés des résidus) ssr = np.sum((y - y_pred)**2) return r2, ssr # Classe pour la visionneuse CSV class CSVViewer(param.Parameterized): file = param.FileSelector() file_watch = pn.widgets.FileInput(name='Upload CSV', accept='.csv') df = param.DataFrame(precedence=1) file_loaded = param.Boolean(default=False) error_message_pane = pn.pane.Alert( alert_type="danger", visible=False, width=242) regression_executed = param.Boolean(default=False) best_results_updated = param.Boolean(default=False) line_chart_pane = pn.pane.HoloViews() bar_chart_pane = pn.pane.HoloViews() plot_drying_negliger_eq_pane = pn.pane.Plotly() merged_df_pane = pn.Column() #Phase 04 file_input = pn.widgets.FileInput(accept='.csv') plot_pane = pn.pane.Plotly() data_table = pn.Column() # Use pn.Column to hold the non-editable DataFrame view stats_table = pn.Column() # Use pn.Column for statistics # C.C.S upload = pn.widgets.FileInput(name='Upload CSV') execute_button = pn.widgets.Button(name='Exécuter la C.C.S', button_type='primary') degree = pn.widgets.IntInput(name= "Entrez le degré du polynôme pour l'ajustement (par exemple, 1, 2, 3, etc.) : ", start=1, end=30, value=3) results_pane = pn.pane.DataFrame() # Utilisation de pn.pane.DataFrame pour un affichage non éditable plot_ccs_pane = pn.pane.Plotly() message_pane = pn.pane.Markdown("") # C.C.S separement sep_execute_button = pn.widgets.Button(name='Exécuter la C.C.S', button_type='primary') sep_degree = pn.widgets.IntInput(name="Entrez le degré du polynôme pour l'ajustement (par exemple, 1, 2, 3, etc.) : ", start=1, end=30, value=3) sep_results_pane = pn.pane.DataFrame() # Utilisation de pn.pane.DataFrame pour un affichage non éditable sep_plot_ccs_pane = pn.pane.Plotly() sep_message_pane = pn.pane.Markdown("") def __init__(self, **params): super().__init__(**params) self.file_watch = pn.widgets.FileInput() self.file_watch.param.watch(self._load_file, "value") self.line_chart_pane = pn.pane.HoloViews() self.bar_chart_pane = pn.pane.HoloViews() self.regression_table_pane = pn.pane.DataFrame(width=1600, height=500) self.threshold_r2_slider = pn.widgets.FloatSlider(name="Seuil R2", start=0, end=1, step=0.01, width=200) self.threshold_x2_slider = pn.widgets.FloatSlider(name="Seuil X2", start=0, end=1, step=0.01, width=200) self.run_regression_button = pn.widgets.Button(name="Exécuter la Régression", button_type="primary", width=200) self.update_best_results_button = pn.widgets.Button(name="Mettre à jour les Meilleurs Résultats", button_type="primary", width=200) self.best_results_table_pane = pn.pane.DataFrame(width=1000, height=200) #Phase 04 self.file_input.param.watch(self._file_upload_callback, 'value') # C.C.S self.file_watch.param.watch(self._load_file, 'value') self.execute_button.on_click(self.execute_cin) # self.sep_execute_button.on_click(self.execute_cin_separement) # C.C.S Separement def _load_file(self, event): # Utiliser io.BytesIO avec les données binaires du fichier pour créer un objet similaire à un fichier if event.new: # Vérifier si de nouvelles données de fichier ont été chargées # Validation de l'extension du fichier if not self.file_watch.filename.endswith('.csv'): self.error_message_pane.object = "Erreur : Le fichier n'est pas un fichier CSV." self.error_message_pane.visible = True return try: # Lire le fichier CSV à partir de l'objet BytesIO self.df = pd.read_csv(io.BytesIO(event.new)) # Nettoyer les noms des colonnes en supprimant les espaces self.df.columns = [col.strip().replace(' ', '_') for col in self.df.columns] self.file_loaded = True self.error_message_pane.visible = False # Cacher le message d'erreur si tout va bien self.update_views() # Appeler toutes les fonctions nécessaires pour mettre à jour l'UI ici self.line_chart_pane.object = self.line_chart() self.bar_chart_pane.object = self.bar_chart() # Assurez-vous de réinitialiser ou de mettre à jour d'autres parties de l'UI selon les besoins # Par exemple, effacer les anciennes données ou résultats de régression self.regression_table_pane.object = None self.best_results_table_pane.object = None self.regression_executed = False self.best_results_updated = False # Continuez avec les autres mises à jour de l'UI nécessaires après le chargement du fichier self.process_data() self.show_merged_df() self.plot_drying_negliger_eq_pane.object = self.create_plotly_figure() #Phase 04 df = pd.read_csv(StringIO(event.new.decode('utf-8'))) fig, fusion_df = self._process_data_and_create_figure(df) self.plot_pane.object = fig self.data_table.objects = [pn.pane.DataFrame(fusion_df, width=1600, height=400)] self.stats_table.objects = [pn.pane.DataFrame(fusion_df.describe(), width=1600, height=250)] # C.C.S self.message_pane.object = "Fichier CSV chargé avec succès." self.sep_message_pane.object = "Fichier CSV chargé avec succès." except Exception as e: self.error_message_pane.object = f"Erreur lors du chargement du fichier: {e}" self.error_message_pane.visible = True self.message_pane.object = f"Erreur de chargement: {str(e)}" def update_views(self): """Met à jour les graphiques et autres composants de l'UI après le chargement des données.""" self.line_chart_pane.object = self.line_chart() self.bar_chart_pane.object = self.bar_chart() # Réinitialiser les résultats de la régression et autres composants nécessaires self.regression_table_pane.object = None self.best_results_table_pane.object = None def find_temperature_columns(self): """ Trouve et retourne les colonnes qui semblent être des températures. """ return [col for col in self.df.columns if '°C' in col] def line_chart(self): """ Génère un graphique de ligne des températures. """ temp_columns = self.find_temperature_columns() if not temp_columns: return pn.pane.Markdown("Aucune colonne de température trouvée dans les données chargées.") df_temp = self.df.copy() df_temp['Temps(temps)_heure'] = df_temp['Temps(temps)'] / 3600 return df_temp.hvplot.line( x='Temps(temps)_heure', y=temp_columns, ylabel='Température (°C)', title='Graphique de ligne des températures en fonction du temps' ) def bar_chart(self): """ Génère un graphique à barres des températures. """ temp_columns = self.find_temperature_columns() if not temp_columns: return pn.pane.Markdown("Aucune colonne de température trouvée dans les données chargées.") df_temp = self.df.copy() df_temp['Temps(temps)_heure'] = df_temp['Temps(temps)'] / 3600 return df_temp.hvplot.bar( x='Temps(temps)_heure', y=temp_columns, ylabel='Température (°C)', rot=90, title='Graphique à barres des températures en fonction du temps' ) def _regression_results(self): temps = self.df['Temps(temps)'] colonnes_temperature = self.df.columns[1:] results_list = [] for col in colonnes_temperature: t = temps / 3600 y = self.df[col] / 100 t_train, t_test, y_train, y_test = train_test_split(t, y, test_size=0.2, random_state=42) for model in models: model_sklearn = NonLinearRegression(model) model_sklearn.fit(t_train.values.reshape(-1, 1), y_train, maxfev=1000, bounds=(0, np.inf)) r2, ssr = model_sklearn.score(t_test.values.reshape(-1, 1), y_test) model_name = model.__name__ num_params = len(model_sklearn.params) param_names = model_sklearn.model.__code__.co_varnames[1:] results_list.append({ 'Temperature': col, 'Model': model_name, 'Num_Parameters': num_params, 'Parameters': ', '.join([f'{param}={val:.6f}' for param, val in zip(param_names, model_sklearn.params)]), 'X2': ssr, 'R2': r2 }) results_df = pd.DataFrame(results_list) sorted_df = results_df.sort_values(by=['Temperature', 'R2', 'X2'], ascending=[True, False, True]) return sorted_df def _best_results(self, threshold_r2, threshold_x2): best_models = self._regression_results().groupby('Temperature').first().reset_index() return best_models[(best_models['R2'] > threshold_r2) & (best_models['X2'] < threshold_x2)] def _comparison_plots(self): temps = self.df['Temps(temps)'] colonnes_temperature = self.df.columns[1:] # Liste pour stocker les graphiques Bokeh bokeh_plots = [] # Définir le nombre de lignes et de colonnes pour les sous-graphiques num_rows = math.ceil(len(models) / 2) num_cols = 2 # Boucle sur chaque colonne de température for col in colonnes_temperature: # Données spécifiques pour chaque colonne de température t = temps / 3600 # seconde(s) en heure(h) y = self.df[col] / 100 # Diviser les données en ensembles d'entraînement et de test t_train, t_test, y_train, y_test = train_test_split(t, y, test_size=0.2, random_state=42) # Créer des sous-graphiques fig, axes = plt.subplots(num_rows, num_cols, figsize=(15, 5* num_rows) ) fig.suptitle(f"Comparaison de l'ajustement du modèle - Température: {col} ") # Boucle sur tous les modèles for i, model in enumerate(models): # Créer le modèle scikit-learn model_sklearn = NonLinearRegression(model) # Ajuster le modèle aux données d'entraînement model_sklearn.fit(t_train.values.reshape(-1, 1), y_train, maxfev=1000, bounds=(0, np.inf)) # Évaluer le modèle sur les données de test r2, ssr = model_sklearn.score(t_test.values.reshape(-1, 1), y_test) # Tracer les courbes t_range = np.linspace(t.min(), t.max(), 100) y_pred = model_sklearn.predict(t_range.reshape(-1, 1)) # Placer le graphique dans le sous-ensemble approprié row = i // num_cols col = i % num_cols #axes[row, col].scatter(t_test, y_test, label='Données Expérimentales') axes[row, col].scatter(t, y, label='Données Expérimentales') axes[row, col].plot(t_range, y_pred, label='Ajustement du Modèle', color='red') axes[row, col].set_title(f"{model.__name__}") axes[row, col].set_xlabel('Temps (heures)') axes[row, col].set_ylabel('Température') axes[row, col].legend() # Ajouter les informations sur le modèle centrées num_params = len(model_sklearn.params) model_info = f"{model.__name__}\nTempérature: {col}\nNombre de paramètres: {num_params}\n" model_info += ', '.join([f'{param} = {val:.6f}' for param, val in zip(model_sklearn.model.__code__.co_varnames[1:], model_sklearn.params)]) model_info += f"\nR^2 Score: {r2:.6f}\nX² (SSR): {ssr:.6f}" axes[row, col].text(0.5, -0.4, model_info, transform=axes[row, col].transAxes, fontsize=8, va='center', ha='center', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8)) # Ajuster l'espacement entre les sous-graphiques plt.tight_layout(rect=[0, 0.03, 1, 0.95]) pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), # Convertir le graphique Matplotlib en graphique Bokeh # bokeh_plot = pn.pane.Matplotlib(fig) bokeh_plot = pn.pane.Matplotlib(fig, height=2500) bokeh_plots.append(bokeh_plot) return bokeh_plots # Traitement des données : calcul des dérivées et des ratios def process_data(self): dX_dt_df = pd.DataFrame() Xr_df = pd.DataFrame() for col in self.df.columns[1:]: # Assumption: the first column is 'Temps(temps)' dX_dt = -(self.df[col].diff() / self.df['Temps(temps)'].diff()) dX_dt.iloc[0] = -(self.df[col].iloc[1] - self.df[col].iloc[0]) / (self.df['Temps(temps)'].iloc[1] - self.df['Temps(temps)'].iloc[0]) dX_dt_df[f'-dX/dt_{col}'] = dX_dt Xr = self.df[col] / self.df[col][0] Xr_df[f'Xr_{col}'] = Xr self.merged_df = pd.concat([self.df, dX_dt_df, Xr_df], axis=1) # Affiche les DataFrame fusionnées dans Panel def show_merged_df(self): self.merged_df_pane.objects = [ pn.pane.Markdown("## Données Fusionnées :"), pn.pane.DataFrame(self.merged_df, width=1600, height=400), pn.pane.Markdown("## Statistiques descriptives des Données Fusionnées :"), pn.pane.DataFrame(self.merged_df.describe(), width=1600, height=250)] # Crée et configure la figure Plotly def create_plotly_figure(self): fig = make_subplots(rows=2, cols=2, subplot_titles=("Dérivées", "Valeurs de Xr", "Xr=f(-dX/dt)", "-dX/dt = f(Xr)")) dX_dt_df = self.merged_df.filter(regex='^-dX/dt_') Xr_df = self.merged_df.filter(regex='^Xr_') for col in dX_dt_df.columns: fig.add_trace(go.Scatter(x=self.merged_df['Temps(temps)']/3600, y=dX_dt_df[col], mode='lines', name=col), row=1, col=1) for col in Xr_df.columns: fig.add_trace(go.Scatter(x=self.merged_df['Temps(temps)']/3600, y=Xr_df[col], mode='lines', name=col), row=1, col=2) for col in dX_dt_df.columns: x_col = col.replace('-dX/dt_', 'Xr_') fig.add_trace(go.Scatter(x=dX_dt_df[col], y=Xr_df[x_col], mode='lines', name=f'{x_col} = f( {col})'), row=2, col=1) for col in Xr_df.columns: y_col = col.replace('Xr_', '-dX/dt_') fig.add_trace(go.Scatter(x=Xr_df[col], y=dX_dt_df[y_col], mode='lines', name=f'{y_col} = f({col})'), row=2, col=2) fig.update_layout(height=600, width=1600, title_text="Tracés avec Plotly", template="plotly_dark") # Mettre en forme les sous-titres et les étiquettes des axes fig.update_xaxes(title_text="Temps (heures)", row=1, col=1) fig.update_xaxes(title_text="Temps (heures)", row=1, col=2) fig.update_xaxes(title_text="-dX/dt", row=2, col=1) fig.update_xaxes(title_text="Xr", row=2, col=2) fig.update_yaxes(title_text="-dX/dt", row=1, col=1, title_standoff=20) fig.update_yaxes(title_text="Valeur de Xr", row=1, col=2, title_standoff=20) fig.update_yaxes(title_text="Xr", row=2, col=1, title_standoff=20) fig.update_yaxes(title_text="-dX/dt", row=2, col=2, title_standoff=20) return fig # Phase 4 : fusion_df def _process_data_and_create_figure(self, df): Xr_df = pd.DataFrame() dX_dt_df = pd.DataFrame() for col in df.columns[1:]: dX_dt = -(df[col].diff() / df['Temps(temps)'].diff()) dX_dt.iloc[0] = -(df[col].iloc[1] - df[col].iloc[0]) / (df['Temps(temps)'].iloc[1] - df['Temps(temps)'].iloc[0]) dX_dt_df[f'-dX/dt_{col}'] = dX_dt Xr_df[f'Xr_{col}'] = df[col] / df[col][0] dX_dt_df_u_0 = pd.DataFrame() for col in dX_dt_df.columns: dX_dt_df_u_0[f'({col})/u_0'] = dX_dt_df[col] / dX_dt_df[col][0] fusion_df = pd.concat([df, dX_dt_df_u_0, Xr_df], axis=1) fusion_df['Temps(heures)'] = fusion_df['Temps(temps)'] / 3600 temp_columns = df.columns[1:] # # Define the columns to be used for subplots temp_columns = df.columns[1:] # Assume these are the columns after the first column num_rows = len(temp_columns) num_cols = 2 subplot_titles = [] for temp in temp_columns: subplot_titles.append(f"{temp} Xr") subplot_titles.append(f"{temp} -dX/dt/u_0") fig = make_subplots(rows=num_rows, cols=num_cols, subplot_titles=subplot_titles) for i, col in enumerate(df.columns[1:]): fig.add_trace(go.Scatter(x=fusion_df['Temps(heures)'], y=fusion_df[f'Xr_{col}'], name=f'Xr_{col}'), row=i+1, col=1) fig.add_trace(go.Scatter(x=fusion_df['Temps(heures)'], y=fusion_df[f'(-dX/dt_{col})/u_0'], name=f'(-dX/dt_{col})/u_0'), row=i+1, col=2) #fig.update_layout(height=300 * num_rows, title_text="Analyses des caractéristiques de séchage", template="plotly_dark") fig.update_layout(height=1600, width=1600, title_text="Tracés avec Plotly", template="plotly_dark") fig.update_xaxes(title_text="Temps (heures)") fig.update_yaxes(title_text="Xr", col=1) fig.update_yaxes(title_text="(-dX/dt/u_0)", col=2) return fig, fusion_df def _file_upload_callback(self, event): if event.new: if not self.file_input.filename.endswith('.csv'): self.error_message_pane.object = "Error: Not a CSV file." self.error_message_pane.visible = True return try: df = pd.read_csv(StringIO(event.new.decode('utf-8'))) fig, fusion_df = self._process_data_and_create_figure(df) self.plot_pane.object = fig self.data_table.objects = [pn.pane.DataFrame(fusion_df, width=1600, height=600)] self.stats_table.objects = [pn.pane.DataFrame(fusion_df.describe(), width=1600, height=600)] self.error_message_pane.visible = False except Exception as e: self.error_message_pane.object = f"Error loading file: {str(e)}" self.error_message_pane.visible = True ### Courbes C.C.S def execute_cin(self, event=None): df = self.df if df.empty: self.message_pane.object = "Aucune donnée à analyser. Veuillez charger un fichier CSV." return dX_dt_df = self.calculer_dX_dt(df) Xr_df = self.calculer_Xr(df) dX_dt_df_u_0 = self.calculer_Xr_reduite(dX_dt_df) fusion_df = self.fusionner_dataframes(df, dX_dt_df_u_0, Xr_df) temp_columns = df.columns[1:] # assuming temperature columns start from second column results_df, fig = self.afficher_graphiques(temp_columns, fusion_df, self.degree.value) self.results_pane.object = results_df # Mise à jour de results_pane avec un DataFrame non éditable self.plot_ccs_pane.object = fig @staticmethod def calculer_dX_dt(df): dX_dt_df = pd.DataFrame() temps = df['Temps(temps)'] for col in df.columns[1:]: dX_dt = -(df[col].diff() / temps.diff()) dX_dt.iloc[0] = -(df[col].iloc[1] - df[col].iloc[0]) / (temps.iloc[1] - temps.iloc[0]) dX_dt_df[f'-dX/dt_{col}'] = dX_dt return dX_dt_df @staticmethod def calculer_Xr(df): return pd.DataFrame({f'Xr_{col}': df[col] / df[col][0] for col in df.columns[1:]}) @staticmethod def calculer_Xr_reduite(dX_dt_df): return pd.DataFrame({f'({col})/u_0': dX_dt_df[col] / dX_dt_df[col][0] for col in dX_dt_df.columns}) @staticmethod def fusionner_dataframes(df, dX_dt_df_u_0, Xr_df): return pd.concat([df, dX_dt_df_u_0, Xr_df], axis=1) @staticmethod def afficher_graphiques(temp_columns, fusion_df, degree): fig = go.Figure() results = [] for temp in temp_columns: Xr_col = f'Xr_{temp}' u_reduite_col = f'(-dX/dt_{temp})/u_0' Xr = fusion_df[Xr_col].values.reshape(-1, 1) u_reduite = fusion_df[u_reduite_col].values pipeline = make_pipeline(PolynomialFeatures(degree=degree), LinearRegression()) pipeline.fit(Xr, u_reduite) y_pred = pipeline.predict(Xr) r2 = r2_score(u_reduite, y_pred) ssr = np.sum((u_reduite - y_pred) ** 2) cv_rmse = np.mean(np.sqrt(-cross_val_score(pipeline, Xr, u_reduite, cv=5, scoring='neg_mean_squared_error'))) coeffs = pipeline.named_steps['linearregression'].coef_ result = [temp] + coeffs[1:].tolist() + [pipeline.named_steps['linearregression'].intercept_, r2, ssr, cv_rmse] results.append(result) Xr_fit = np.linspace(Xr.min(), Xr.max(), 100).reshape(-1, 1) u_reduite_fit = pipeline.predict(Xr_fit) fig.add_trace(go.Scatter(x=Xr.flatten(), y=u_reduite, mode='markers', name=f'Données expérimentales {temp}')) fig.add_trace(go.Scatter(x=Xr_fit.flatten(), y=u_reduite_fit, mode='lines', name='Ajustement polynomial')) #fig.update_layout(height=1600, width=1600, title_text="Tracés avec Plotly", template="plotly_dark") fig.update_layout(title="Courbe caractéristique de séchage", xaxis_title="Xr", yaxis_title="(-dX/dt)/u_0", legend=dict(x=0, y=1), template="plotly_dark", height=700, width=1000) results_df = pd.DataFrame(results, columns=['Température'] + [f'a_{i}' for i in range(degree, 0, -1)] + ['Intercept', 'R^2', 'SSR', 'CV RMSE']) return results_df, fig #----------------------------- def execute_cin_separement(self, event=None): df = self.df if df.empty: self.sep_message_pane.object = "Aucune donnée à analyser. Veuillez charger un fichier CSV." return dX_dt_df = self.sep_calculer_dX_dt(df) Xr_df = self.sep_calculer_Xr(df) dX_dt_df_u_0 = self.sep_calculer_Xr_reduite(dX_dt_df) fusion_df = self.sep_fusionner_dataframes(df, dX_dt_df_u_0, Xr_df) temp_columns = df.columns[1:] # assuming temperature columns start from second column results_df, fig = self.afficher_graphiques_separement(temp_columns, fusion_df, self.sep_degree.value) self.sep_results_pane.object = results_df # Mise à jour de results_pane avec un DataFrame non éditable self.sep_plot_ccs_pane.object = fig @staticmethod def sep_calculer_dX_dt(df): dX_dt_df = pd.DataFrame() temps = df['Temps(temps)'] for col in df.columns[1:]: dX_dt = -(df[col].diff() / temps.diff()) dX_dt.iloc[0] = -(df[col].iloc[1] - df[col].iloc[0]) / (temps.iloc[1] - temps.iloc[0]) dX_dt_df[f'-dX/dt_{col}'] = dX_dt return dX_dt_df @staticmethod def sep_calculer_Xr(df): return pd.DataFrame({f'Xr_{col}': df[col] / df[col][0] for col in df.columns[1:]}) @staticmethod def sep_calculer_Xr_reduite(dX_dt_df): return pd.DataFrame({f'({col})/u_0': dX_dt_df[col] / dX_dt_df[col][0] for col in dX_dt_df.columns}) @staticmethod def sep_fusionner_dataframes(df, dX_dt_df_u_0, Xr_df): return pd.concat([df, dX_dt_df_u_0, Xr_df], axis=1) @staticmethod def afficher_graphiques_separement(temp_columns, fusion_df, degree): # Create a figure with subplots: two columns per temperature rows = len(temp_columns) cols = 2 # Two columns: one for normal plot and one for inverted axes fig = make_subplots(rows=rows, cols=cols, subplot_titles=[f'Analyse pour {temp}' for temp in temp_columns for _ in range(2)]) results = [] subplot_row = 1 # Start placing subplots at the first row for temp in temp_columns: Xr_col = f'Xr_{temp}' u_reduite_col = f'(-dX/dt_{temp})/u_0' Xr = fusion_df[Xr_col].values.reshape(-1, 1) u_reduite = fusion_df[u_reduite_col].values pipeline = make_pipeline(PolynomialFeatures(degree), LinearRegression()) pipeline.fit(Xr, u_reduite) y_pred = pipeline.predict(Xr) r2 = r2_score(u_reduite, y_pred) ssr = np.sum((u_reduite - y_pred) ** 2) cv_rmse = np.mean(np.sqrt(-cross_val_score(pipeline, Xr, u_reduite, cv=5, scoring='neg_mean_squared_error'))) coeffs = pipeline.named_steps['linearregression'].coef_ result = [temp] + coeffs[1:].tolist() + [pipeline.named_steps['linearregression'].intercept_, r2, ssr, cv_rmse] results.append(result) Xr_fit = np.linspace(Xr.min(), Xr.max(), 100).reshape(-1, 1) u_reduite_fit = pipeline.predict(Xr_fit) # Normal axes plot fig.add_trace(go.Scatter(x=Xr.flatten(), y=u_reduite, mode='markers', name=f'Données Exp {temp}'), row=subplot_row, col=1) fig.add_trace(go.Scatter(x=Xr_fit.flatten(), y=u_reduite_fit, mode='lines', name='Ajuster'), row=subplot_row, col=1) # Inverted axes plot fig.add_trace(go.Scatter(x=u_reduite, y=Xr.flatten(), mode='markers', name=f'Inverser Données {temp}'), row=subplot_row, col=2) fig.add_trace(go.Scatter(x=u_reduite_fit, y=Xr_fit.flatten(), mode='lines', name='Inverser Ajuster'), row=subplot_row, col=2) # Update axes for each subplot fig.update_xaxes(title_text="Xr", row=subplot_row, col=1) fig.update_yaxes(title_text=f"(-dX/dt_{temp})/u_0", row=subplot_row, col=1) fig.update_xaxes(title_text=f"(-dX/dt_{temp})/u_0", row=subplot_row, col=2) fig.update_yaxes(title_text="Xr", row=subplot_row, col=2) subplot_row += 1 # Move to the next row for the next set of subplots fig.update_layout(height=1600, width=1600, title_text="Tracés avec Plotly", template="plotly_dark") #fig.update_layout(height=200 * rows, width=1200, title_text="Courbe caractéristique de séchage", template="plotly_dark") results_df = pd.DataFrame(results, columns=['Temperature'] + [f'a_{i}' for i in range(degree, 0, -1)] + ['Intercept', 'R^2', 'SSR', 'CV RMSE']) return results_df, fig ### Fin CCS def view(self): # Code de la méthode view # Ajustez la largeur et la hauteur du tableau table_pane = pn.pane.DataFrame(self.param.df, width=750, height=600) # Set up tabs tabs = pn.Tabs( ("Graphiques", pn.Row(table_pane, pn.Column(self.line_chart_pane, self.bar_chart_pane, width=800, height=400))), ("Régression", pn.Column( pn.pane.Markdown("## Résultats de la Régression, triés par température, $$R^2$$ décroissant, $$X^2$$ croissant"), self.run_regression_button, # Ajout du bouton "Exécuter la Régression" self.regression_table_pane, pn.pane.Markdown("## Meilleurs Résultats"), self.threshold_r2_slider, self.threshold_x2_slider, self.update_best_results_button, self.best_results_table_pane )), ) # Ajouter la section "Comparaison des Modèles" comparison_plots_button = pn.widgets.Button(name="Afficher les Comparaisons des Modèles", button_type="primary", width=200) comparison_plots_pane = pn.Column() # Callback function to update regression results def update_regression_results(event): if self.file_loaded: self.regression_table_pane.object = self._regression_results() self.regression_executed = True def update_best_results(event): if self.regression_executed: threshold_r2 = self.threshold_r2_slider.value threshold_x2 = self.threshold_x2_slider.value self.best_results_table_pane.object = self._best_results(threshold_r2, threshold_x2) self.best_results_updated = True # Connect the callback functions to the buttons self.run_regression_button.on_click(update_regression_results) self.update_best_results_button.on_click(update_best_results) # Callback function to update comparison plots def update_comparison_plots(event): if self.regression_executed: comparison_plots = self._comparison_plots() comparison_plots_pane.clear() comparison_plots_pane.extend(comparison_plots) # Connect the callback function to the button comparison_plots_button.on_click(update_comparison_plots) # Ajouter les onglets pour la comparaison des modèles tabs.extend([ ("Comparaison des Modèles", pn.Column( pn.pane.Markdown("## Comparaison des Modèles"), comparison_plots_button, comparison_plots_pane, #height = 3500, )), ("Application d'Analyse de Données CSV", pn.Column( pn.pane.Markdown("## CIN"), self.file_watch, self.merged_df_pane, self.plot_drying_negliger_eq_pane )), ("Application d'Analyse de Données sur C.C.S", pn.Column( pn.pane.Markdown("## CIN"), self.file_watch, #self.file_input, #self.error_message_pane, pn.pane.Markdown("## Données Fusionnées | C.C.S"), self.data_table, pn.pane.Markdown("## Statistiques descriptives des Données Fusionnées | C.C.S"), self.stats_table, pn.pane.Markdown("## Visualisation des données | C.C.S"), self.plot_pane, pn.pane.Markdown("## C.C.S Superposées"), self.message_pane, self.degree, self.execute_button, self.results_pane, self.plot_ccs_pane, # pn.pane.Markdown("## Etudes Comparative des C.C.S | (-dX/dt) / u_0 = f (Xr) Vs Xr = f((-dX/dt) / u_0 )"), self.sep_message_pane, self.sep_degree, self.sep_execute_button, self.sep_results_pane, self.sep_plot_ccs_pane, pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), pn.pane.Markdown(""), )), ]) # Création du widget FileInput file_input = pn.widgets.FileInput() # Fonction pour afficher le format requis def afficher_format_requis(): # Création d'un DataFrame Pandas avec le format requis data = { "Temps(temps)": [0, 3600, 7200], "50°C": [0, 84.857, 74.153], "55°C": [89.139, 79.274, 67.838], "60°C": [89.139, 75.273, 60.234], "65°C": [89.139, 69.984, 51.615], "70°C": [89.139, 60.660, 40.757] } df = pd.DataFrame(data) # Convertir le DataFrame en une représentation HTML html_table = df.to_html(index=False) # Afficher la représentation HTML avec Panel return pn.pane.HTML(html_table) # Main layout main_layout = pn.Column( "## USER: Sélectionnez un fichier CSV à afficher ", "### Assurez-vous que le fichier CSV respecte le format requis pour l'entrée de la simulation.", afficher_format_requis, self.file_watch, self.error_message_pane, # S'assurer que le pane des messages d'erreur est inclus tabs, ) # Retourner le layout principal return main_layout # Création d'une instance de CSVViewer csv_viewer = CSVViewer() # Création du tableau de bord template = pn.template.ReactTemplate(title='Progiciel de Simulation Numérique Interactive du PROJET Trans-Val-S | Gestion du Séchage des Oignons ') # Ajouter le logo à gauche logo = pn.pane.PNG('https://github.com/CodingYayaToure/Data/blob/main/Projet_Trans_Val.png?raw=true', width=400, height=100) template.sidebar.append(logo) # Ajouter les expressions LaTeX à gauche template.sidebar.append(left_panel) # Ajouter le contenu principal (graphique interactif et tableau de données) au centre template.main[0, 0] = csv_viewer.view() # Exécuter l'application template.servable()