From 54fb5f75673c6fccd4abed159977d9cf1d0564b1 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Fri, 21 Mar 2025 17:29:32 +0100 Subject: [PATCH 01/22] code for nadaraya watson --- rlberry/manager/plotting.py | 90 ++++++++++++++----------------------- 1 file changed, 33 insertions(+), 57 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 89d6bfb0b..9c8cd6654 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -3,21 +3,15 @@ from itertools import cycle import numbers from scipy.stats import norm +from scipy.ndimage import gaussian_filter1d +from scipy.spatial.distance import pdist + import pandas as pd from rlberry.manager import read_writer_data -try: - from skfda.representation.grid import FDataGrid - from skfda.misc.hat_matrix import NadarayaWatsonHatMatrix - from skfda.preprocessing.smoothing import KernelSmoother - from skfda.preprocessing.smoothing.validation import SmoothingParameterSearch - - SKFDA_INSTALLED = True -except Exception as ex: - SKFDA_INSTALLED = False - import rlberry +import time logger = rlberry.logger @@ -305,9 +299,7 @@ def plot_smoothed_curves( [2] scikit-fda, Carlos Ramos Carreño, hzzhyj, mellamansanchez, Pablo Marcos, pedrorponga, David del Val, Pablo, David García Fernández, Martín, Miguel Carbajo Berrocal, ElenaPetrunina, Pablo Cuesta Sierra, Rafa Hidalgo, Clément Lejeune, amandaher, dSerna4, ego-thales, pedrog99, Jorge Duque, … Álvaro Castillo. (2023). GAA-UAM/scikit-fda: Version 0.9 (0.9). Zenodo. https://doi.org/10.5281/zenodo.10016930 """ - assert ( - SKFDA_INSTALLED - ), "please install scikit-fda to use the smoothing functionality in rlberry" + xlabel = x ylabel = y x_values = data[xlabel].values @@ -329,58 +321,25 @@ def process(df): Change shape and smooth the curves contained in the dataset df if necessary. """ # Nadaraya-Watson kernel smoothing - # with cross validation bandwidth selection - if not isinstance(smoothing_bandwidth, numbers.Number): - if smoothing_bandwidth is None: - bandwidth = np.linspace( - min_bandwidth_x, max((max_x - min_x) / 100, min_bandwidth_x * 3), 10 - ) - else: - bandwidth = smoothing_bandwidth - nw = SmoothingParameterSearch( - KernelSmoother( - kernel_estimator=NadarayaWatsonHatMatrix(), output_points=xplot - ), - bandwidth, - param_name="kernel_estimator__bandwidth", - ) - bw = False - else: - nw = KernelSmoother( - kernel_estimator=NadarayaWatsonHatMatrix(bandwidth=smoothing_bandwidth), - output_points=xplot, - ) - bw = smoothing_bandwidth - - Xhat = np.zeros([n_tot_simu, len(xplot)]) + Yhat = np.zeros([n_tot_simu, len(xplot)]) + bw = smoothing_bandwidth for f in range(n_tot_simu): - X = df_name.loc[df["n_simu"] == f, ylabel].values + Y = df_name.loc[df["n_simu"] == f, ylabel].values try: - np.isfinite(X) + np.isfinite(Y) except: raise ValueError("non-finite (or non float) data detected.") - if not np.all(np.isfinite(X)): + + if not np.all(np.isfinite(Y)): logger.warning( "Some of the values are not finite. Not plotting the associated curves." ) - Xhat[f] = np.nan + Yhat[f] = np.nan else: - X_grid = df_name.loc[df["n_simu"] == f, xlabel].values.astype(float) - fd = FDataGrid([X], X_grid, domain_range=((min_x, max_x),)) - - if bw is False: # Find the smoothing bandwidth once - nw.fit(fd) - bw = nw.best_params_[ - "kernel_estimator__bandwidth" - ] # don't search for bandwidth in futur run, reuse - else: # after the first one, just apply smoothing with the given smoothing - nw = KernelSmoother( - kernel_estimator=NadarayaWatsonHatMatrix(bandwidth=bw), - output_points=xplot, - ) - nw.fit(fd) - Xhat[f] = nw.transform(fd).data_matrix.ravel() # apply smoothing - return Xhat + X = df_name.loc[df["n_simu"] == f, xlabel].values.astype(float) + nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) + Yhat[f] = nw.get_y_smoothed(Y) + return Yhat names = np.unique(data["name"]) @@ -648,3 +607,20 @@ def _prepare_ax(data, ax, linestyles): cmap = [plt.cm.gist_rainbow(i / len(names)) for i in range(len(names))] return ax, styles, cmap + +class Smoothed_curve_NW(): + def __init__(self, X, xref, bandwidth=None): + self.kernel = lambda x: np.exp(-x**2/2) + self.bandwidth = bandwidth + self.Hmatrix = self.H(X, xref) + + def H(self, xi, xref): + D = (xi[:,None]-xref).T + bandwidth = float(np.percentile(D.ravel()[D.ravel()>0], 25)) if self.bandwidth is None else self.bandwidth + numerator = self.kernel(D / bandwidth) + + return numerator / np.sum(numerator, axis=1)[:,np.newaxis] + + def get_y_smoothed(self, y): + return self.Hmatrix.dot(y) + From e9c907c6cee816874ebe4c5b93e29509d4363c3b Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Fri, 21 Mar 2025 17:31:47 +0100 Subject: [PATCH 02/22] remove dependency scikit-fda --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 63653be8c..011dbae1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ stable-baselines3 = {version=">=2.4.1", optional=true} tensorboard = {version="*", optional=true} torch = {version=">=2.3", optional=true} pandas = "*" -scikit-fda = {git = "https://github.com/GAA-UAM/scikit-fda.git", branch = "develop", optional=true} nox = {version="*", optional=true} sphinx = {version="6.2.1", optional=true} sphinx-gallery = { version= "^0.14.0", optional=true} From d30e4b0582ba0c4bd27b87d3c70dd6cf38aad2b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:32:07 +0000 Subject: [PATCH 03/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/plotting.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 9c8cd6654..14b094fa7 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -337,7 +337,7 @@ def process(df): Yhat[f] = np.nan else: X = df_name.loc[df["n_simu"] == f, xlabel].values.astype(float) - nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) + nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) Yhat[f] = nw.get_y_smoothed(Y) return Yhat @@ -608,19 +608,23 @@ def _prepare_ax(data, ax, linestyles): return ax, styles, cmap -class Smoothed_curve_NW(): - def __init__(self, X, xref, bandwidth=None): - self.kernel = lambda x: np.exp(-x**2/2) + +class Smoothed_curve_NW: + def __init__(self, X, xref, bandwidth=None): + self.kernel = lambda x: np.exp(-(x**2) / 2) self.bandwidth = bandwidth self.Hmatrix = self.H(X, xref) def H(self, xi, xref): - D = (xi[:,None]-xref).T - bandwidth = float(np.percentile(D.ravel()[D.ravel()>0], 25)) if self.bandwidth is None else self.bandwidth + D = (xi[:, None] - xref).T + bandwidth = ( + float(np.percentile(D.ravel()[D.ravel() > 0], 25)) + if self.bandwidth is None + else self.bandwidth + ) numerator = self.kernel(D / bandwidth) - return numerator / np.sum(numerator, axis=1)[:,np.newaxis] - + return numerator / np.sum(numerator, axis=1)[:, np.newaxis] + def get_y_smoothed(self, y): return self.Hmatrix.dot(y) - From e36da55daeffc5564dfd36f38b6cece19044b47e Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Fri, 21 Mar 2025 17:32:53 +0100 Subject: [PATCH 04/22] remove unused deps --- rlberry/manager/plotting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 9c8cd6654..f7b026eee 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -11,7 +11,6 @@ from rlberry.manager import read_writer_data import rlberry -import time logger = rlberry.logger From dd4f0c4a4feae7b62f754620db9b104e90500609 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Sun, 23 Mar 2025 14:45:48 +0100 Subject: [PATCH 05/22] fix bandwidth heuristic --- rlberry/manager/plotting.py | 68 +++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 0966cffcf..5bd40c918 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -73,7 +73,7 @@ def plot_writer_data( ax: matplotlib axis or None, default=None Matplotlib axis on which we plot. If None, create one. Can be used to customize the plot. - error_representation: str in {"cb", "raw_curves", "ci", "pi"} + error_representation: str in {"cb", "raw_curves", "ci", "pi", "none"} How to represent multiple simulations. The "ci" and "pi" do not take into account the need for simultaneous inference, it is then harder to draw conclusion from them than with "cb" and "pb" but they are the most widely used. - "cb" is a confidence band on the mean curve using functional data analysis (band in which the mean curve is with probability larger than 1-level). @@ -83,6 +83,7 @@ def plot_writer_data( - "pi" is a plot of a non-simultaneous prediction interval with gaussian model around the mean smoothed curve (e.g. we do curve plus/minus gaussian quantile times std). - "ci" is a confidence interval with gaussian model around the mean smoothed curve (e.g. we do curve plus/minus gaussian quantile times std divided by sqrt of number of seeds). + - "none" don't represent the error, only plot the mean smoothed curve. n_boot: int, default=500, Number of bootstrap evaluations used for confidence interval estimation. @@ -259,7 +260,7 @@ def plot_smoothed_curves( ax: matplotlib axis or None, default=None Matplotlib axis on which we plot. If None, create one. Can be used to customize the plot. - error_representation: str in {"cb", "raw_curves", "ci", "pi"} + error_representation: str in {"cb", "raw_curves", "ci", "pi", "none"} How to represent multiple simulations. The "ci" and "pi" do not take into account the need for simultaneous inference, it is then harder to draw conclusion from them than with "cb" but they are the most widely used. - "cb" is a confidence band on the mean curve using functional data analysis (band in which the mean curve is with probability larger than 1-level). Method from [1], using scikit-fda [2] library. @@ -269,6 +270,7 @@ def plot_smoothed_curves( - "pi" is a plot of a non-simultaneous prediction interval with gaussian model around the mean smoothed curve (e.g. we do curve plus/minus gaussian quantile times std). - "ci" is a confidence interval with gaussian model around the mean smoothed curve (e.g. we do curve plus/minus gaussian quantile times std divided by sqrt of number of seeds). + - "none" don't represent the error, only plot the mean smoothed curve. n_boot: int, default=2500, Number of bootstrap evaluations used for confidence interval estimation. @@ -336,8 +338,11 @@ def process(df): Yhat[f] = np.nan else: X = df_name.loc[df["n_simu"] == f, xlabel].values.astype(float) - nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) - Yhat[f] = nw.get_y_smoothed(Y) + if len(X) != 0: + nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) + Yhat[f] = nw.get_y_smoothed(Y) + else: + Yhat[f] = np.nan*np.ones(len(xplot)) return Yhat names = np.unique(data["name"]) @@ -408,21 +413,27 @@ def process(df): logger.warning( "The variance of the curve was 0, the confidence bound is very biased" ) - + elif error_representation == "none": + pass else: raise ValueError("error_representation not implemented") - - ax.fill_between( - xplot[id_plot], - mu.ravel()[id_plot] - y_err[id_plot], - mu.ravel()[id_plot] + y_err[id_plot], - alpha=0.25, - color=cmap[id_c], - ) + if error_representation != "none": + ax.fill_between( + xplot[id_plot], + mu.ravel()[id_plot] - y_err[id_plot], + mu.ravel()[id_plot] + y_err[id_plot], + alpha=0.25, + color=cmap[id_c], + ) ax.set_ylabel(ylabel) ax.set_xlabel(xlabel) - plt.legend() + # Shrink current axis by 20% + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) + + # Put a legend to the right of the current axis + ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if show: plt.show() @@ -466,7 +477,7 @@ def plot_synchronized_curves( ax: matplotlib axis or None, default=None Matplotlib axis on which we plot. If None, create one. Can be used to customize the plot. - error_representation: str in {"raw_curves", "ci", "pi"}, default="pi" + error_representation: str in {"raw_curves", "ci", "pi", "none"}, default="pi" How to represent multiple simulations. - "raw curves" is a plot of the raw curves. @@ -474,6 +485,7 @@ def plot_synchronized_curves( - "pi" is a plot of a non-simultaneous prediction interval with gaussian model around the mean curve (e.g. we do curve plus/minus gaussian quantile times std). - "ci" is a confidence interval on the prediction interval with gaussian model around the mean curve (e.g. we do curve plus/minus gaussian quantile times std divided by sqrt of number of seeds). + - "none" don't represent the error, only plot the mean smoothed curve. level: float, default=0.95, Level of the confidence (or prediction) interval. Only used if error_representation is not "raw_curves". @@ -564,6 +576,8 @@ def plot_synchronized_curves( ax.plot(x_simu, y, alpha=0.2, color=cmap[id_c]) else: ax.plot(x_simu, y, alpha=0.25, color=cmap[id_c]) + elif error_representation == "none": + pass else: raise ValueError( "Error representation {} not known for non-smoothed plots".format( @@ -573,7 +587,13 @@ def plot_synchronized_curves( ax.set_ylabel(ylabel) ax.set_xlabel(xlabel) - plt.legend() + # Shrink current axis by 20% + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) + + # Put a legend to the right of the current axis + ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + if show: plt.show() @@ -615,12 +635,16 @@ def __init__(self, X, xref, bandwidth=None): self.Hmatrix = self.H(X, xref) def H(self, xi, xref): - D = (xi[:, None] - xref).T - bandwidth = ( - float(np.percentile(D.ravel()[D.ravel() > 0], 25)) - if self.bandwidth is None - else self.bandwidth - ) + D = np.abs((xi[:, None] - xref).T) + nonzero_distances = D.ravel()[D.ravel() > 0] + if len(nonzero_distances) == 0: + bandwidth = (np.max(xi)-np.min(x_i))/100 + else: + bandwidth = ( + float(np.percentile(nonzero_distances, 10)) + if self.bandwidth is None + else self.bandwidth + ) numerator = self.kernel(D / bandwidth) return numerator / np.sum(numerator, axis=1)[:, np.newaxis] From ad079b2da0cdab39b51062385e93cd20a3f25179 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 23 Mar 2025 13:45:50 +0000 Subject: [PATCH 06/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/plotting.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 5bd40c918..6337bd1ae 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -342,7 +342,7 @@ def process(df): nw = Smoothed_curve_NW(X, xplot, bandwidth=bw) Yhat[f] = nw.get_y_smoothed(Y) else: - Yhat[f] = np.nan*np.ones(len(xplot)) + Yhat[f] = np.nan * np.ones(len(xplot)) return Yhat names = np.unique(data["name"]) @@ -433,7 +433,7 @@ def process(df): ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) # Put a legend to the right of the current axis - ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + ax.legend(loc="center left", bbox_to_anchor=(1, 0.5)) if show: plt.show() @@ -592,8 +592,7 @@ def plot_synchronized_curves( ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) # Put a legend to the right of the current axis - ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) - + ax.legend(loc="center left", bbox_to_anchor=(1, 0.5)) if show: plt.show() @@ -638,7 +637,7 @@ def H(self, xi, xref): D = np.abs((xi[:, None] - xref).T) nonzero_distances = D.ravel()[D.ravel() > 0] if len(nonzero_distances) == 0: - bandwidth = (np.max(xi)-np.min(x_i))/100 + bandwidth = (np.max(xi) - np.min(x_i)) / 100 else: bandwidth = ( float(np.percentile(nonzero_distances, 10)) From 025caef262e26cc04b1dc32e37070194a11f610c Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Sun, 23 Mar 2025 14:50:59 +0100 Subject: [PATCH 07/22] remove unused import --- rlberry/manager/plotting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 5bd40c918..21fa25d21 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -3,9 +3,6 @@ from itertools import cycle import numbers from scipy.stats import norm -from scipy.ndimage import gaussian_filter1d -from scipy.spatial.distance import pdist - import pandas as pd from rlberry.manager import read_writer_data From 31c45bf1ee4753b0c13766a76de5974b8796cbde Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Mon, 24 Mar 2025 14:23:19 +0100 Subject: [PATCH 08/22] return smoothed data --- rlberry/manager/plotting.py | 59 ++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 656f913e5..11bf1bf43 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -29,6 +29,7 @@ def plot_writer_data( title=None, savefig_fname=None, linestyles=False, + return_smoothed_curves=False, ): """ Given a list of ExperimentManager or a folder, plot data (corresponding to info) obtained in each episode. @@ -100,6 +101,9 @@ def plot_writer_data( savefig_fname: str (Optional) Name of the figure in which the plot is saved with figure.savefig. If None, the figure is not saved. + return_smoothed_curves: boolean, default=False + Whether to return a dataframe containing the smoothed curves. If True, + returns the tuple (data_preprocessed, data_smoothed). linestyles: boolean, default=False Whether to use different linestyles for each curve. Returns @@ -180,7 +184,7 @@ def plot_writer_data( if ax is None: figure, ax = plt.subplots(1, 1) if smooth: - plot_smoothed_curves( + data_smoothed = plot_smoothed_curves( data[["name", xtag, "value", "n_simu"]], xtag, "value", @@ -194,7 +198,7 @@ def plot_writer_data( linestyles, ) else: - plot_synchronized_curves( + data_smoothed = plot_synchronized_curves( data[["name", xtag, "value", "n_simu"]], xtag, "value", @@ -213,7 +217,10 @@ def plot_writer_data( plt.gcf().savefig(savefig_fname) if show: plt.show() - return data + if return_smoothed_curves: + return data, data_smoothed + else: + return data def plot_smoothed_curves( @@ -302,23 +309,16 @@ def plot_smoothed_curves( ylabel = y x_values = data[xlabel].values min_x, max_x = x_values.min(), x_values.max() - n_tot_simu = int(data["n_simu"].max()) + 1 - - if not isinstance(smoothing_bandwidth, numbers.Number): - sorted_x = np.sort(np.unique(x_values)) - if len(sorted_x) > 200: - min_bandwidth_x = (sorted_x[1] - sorted_x[0]) * 3 - else: - min_bandwidth_x = sorted_x[1] - sorted_x[0] xplot = np.linspace(min_x, max_x, 500, endpoint=True) ax, styles, cmap = _prepare_ax(data, ax, linestyles) def process(df): """ - Change shape and smooth the curves contained in the dataset df if necessary. + Nadaraya-Watson kernel smoothing """ - # Nadaraya-Watson kernel smoothing + n_tot_simu = int(data["n_simu"].max()) + 1 + Yhat = np.zeros([n_tot_simu, len(xplot)]) bw = smoothing_bandwidth for f in range(n_tot_simu): @@ -343,9 +343,11 @@ def process(df): return Yhat names = np.unique(data["name"]) + data_smoothed = pd.DataFrame() for id_c, name in enumerate(names): df_name = data.loc[data["name"] == name] + n_tot_simu = int(df_name["n_simu"].max()) + 1 Xhat = process(df_name) mu = np.mean(Xhat, axis=0) id_plot = xplot <= np.max(df_name[xlabel]) @@ -357,6 +359,11 @@ def process(df): color=cmap[id_c], linestyle=(0, styles[id_c]), ) + data_smoothed = pd.concat([data_smoothed, + pd.DataFrame({"name": [name]*len(id_plot), + "x": xplot[id_plot], + "y": mu[id_plot]}) + ], ignore_index=True) if (error_representation == "raw_curves") and (n_tot_simu > 1): for n_simu in range(n_tot_simu): @@ -437,7 +444,7 @@ def process(df): if savefig_fname is not None: plt.gcf().savefig(savefig_fname) - return data + return data_smoothed def plot_synchronized_curves( @@ -527,6 +534,7 @@ def plot_synchronized_curves( ax, styles, cmap = _prepare_ax(data, ax, linestyles) names = np.unique(data["name"]) + data_smoothed = pd.DataFrame() for id_c, name in enumerate(names): df_name = data.loc[data["name"] == name, [xlabel, ylabel, "n_simu"]] x_plot = df_name.loc[df_name["n_simu"] == 0, xlabel].values.astype(float) @@ -548,6 +556,8 @@ def plot_synchronized_curves( quantile = norm.ppf(1 - (1 - level) / 2) ax.plot(x_plot, y_mean, color=cmap[id_c], label=name) + data_smoothed = pd.concat([data_smoothed,pd.DataFrame({"name":[name]*len(x_plot), + "x":x_plot,"y":y_mean})],ignore_index=True) if error_representation in ["ci", "pi"]: if error_representation == "pi": @@ -597,7 +607,7 @@ def plot_synchronized_curves( if savefig_fname is not None: plt.gcf().savefig(savefig_fname) - return data + return data_smoothed def _prepare_ax(data, ax, linestyles): @@ -614,7 +624,6 @@ def _prepare_ax(data, ax, linestyles): else: styles = [() for _ in range(data["name"].unique().size)] - n_tot_simu = int(data["n_simu"].max()) names = data["name"].unique() if len(names) <= 10: cmap = plt.cm.tab10.colors[: len(names)] @@ -625,6 +634,22 @@ def _prepare_ax(data, ax, linestyles): class Smoothed_curve_NW: + """ + Nadaraya-Watson kernel smoothing + + Parameters + ---------- + + X: array of floats + Observed x-axis coordinates, usually either global_step or time. + xref: array of floats + x values at which we want to compute the smoothed curve + bandwidth: float or None, default=None + Bandwidth parameter which corresponds to the width of a window on which to smooth for Gaussian kernel, + if None, use the 10th percentile of the nonzero distances between all X[i] + + """ + def __init__(self, X, xref, bandwidth=None): self.kernel = lambda x: np.exp(-(x**2) / 2) self.bandwidth = bandwidth @@ -634,7 +659,7 @@ def H(self, xi, xref): D = np.abs((xi[:, None] - xref).T) nonzero_distances = D.ravel()[D.ravel() > 0] if len(nonzero_distances) == 0: - bandwidth = (np.max(xi) - np.min(x_i)) / 100 + bandwidth = (np.max(xi) - np.min(xi)) / 100 else: bandwidth = ( float(np.percentile(nonzero_distances, 10)) From 6886167196ae1d7392150cfbfbdc9ed158b22671 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 13:23:52 +0000 Subject: [PATCH 09/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/plotting.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 11bf1bf43..e9c105dbd 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -102,7 +102,7 @@ def plot_writer_data( Name of the figure in which the plot is saved with figure.savefig. If None, the figure is not saved. return_smoothed_curves: boolean, default=False - Whether to return a dataframe containing the smoothed curves. If True, + Whether to return a dataframe containing the smoothed curves. If True, returns the tuple (data_preprocessed, data_smoothed). linestyles: boolean, default=False Whether to use different linestyles for each curve. @@ -359,11 +359,19 @@ def process(df): color=cmap[id_c], linestyle=(0, styles[id_c]), ) - data_smoothed = pd.concat([data_smoothed, - pd.DataFrame({"name": [name]*len(id_plot), - "x": xplot[id_plot], - "y": mu[id_plot]}) - ], ignore_index=True) + data_smoothed = pd.concat( + [ + data_smoothed, + pd.DataFrame( + { + "name": [name] * len(id_plot), + "x": xplot[id_plot], + "y": mu[id_plot], + } + ), + ], + ignore_index=True, + ) if (error_representation == "raw_curves") and (n_tot_simu > 1): for n_simu in range(n_tot_simu): @@ -556,8 +564,13 @@ def plot_synchronized_curves( quantile = norm.ppf(1 - (1 - level) / 2) ax.plot(x_plot, y_mean, color=cmap[id_c], label=name) - data_smoothed = pd.concat([data_smoothed,pd.DataFrame({"name":[name]*len(x_plot), - "x":x_plot,"y":y_mean})],ignore_index=True) + data_smoothed = pd.concat( + [ + data_smoothed, + pd.DataFrame({"name": [name] * len(x_plot), "x": x_plot, "y": y_mean}), + ], + ignore_index=True, + ) if error_representation in ["ci", "pi"]: if error_representation == "pi": From 4731fafc559795b434a9741a1018c5804b2f9abd Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Mon, 24 Mar 2025 14:30:14 +0100 Subject: [PATCH 10/22] fix flake8 --- rlberry/manager/plotting.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index e9c105dbd..41c5137a8 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -1,7 +1,6 @@ import matplotlib.pyplot as plt import numpy as np from itertools import cycle -import numbers from scipy.stats import norm import pandas as pd @@ -61,11 +60,10 @@ def plot_writer_data( smooth : boolean, default=False Whether to smooth the curve with a Nadaraya-Watson Kernel smoothing. Remark that this also allow for an xtag which is not synchronized on all the simulations (e.g. time for instance). - smoothing_bandwidth: float or array of floats or None + smoothing_bandwidth: float or None How to choose the bandwidth parameter. If float, then smoothing_bandwidth is used directly as a bandwidth. - If is an array, a parameter search using smoothing_bandwidth is used. - If None, a parameter search from a range of 20 possible values choosen by heuristics is performed. + If None, a heuristic based on the 10th percentile of nonzero distances in x is used. id_agent : int or None, default=None id of the agent to plot, if not None plot only the results for the agent whose id is id_agent. ax: matplotlib axis or None, default=None @@ -256,11 +254,10 @@ def plot_smoothed_curves( - y column is named according to y parameter and contain values to have in y axis. - - smoothing_bandwidth: float or array of floats or None - How to choose the bandwidth parameter. If float, then smoothing_bandwidth is used - directly as a bandwidth and if is an array, a parameter search using smoothing_bandwidth is - used if None, a parameter search from a range of 20 possible values choosen by heuristics is performed. + smoothing_bandwidth: float or None + How to choose the bandwidth parameter. + If float, then smoothing_bandwidth is used directly as a bandwidth. + If None, a heuristic based on the 10th percentile of nonzero distances in x is used. ax: matplotlib axis or None, default=None Matplotlib axis on which we plot. If None, create one. Can be used to customize the plot. @@ -652,7 +649,6 @@ class Smoothed_curve_NW: Parameters ---------- - X: array of floats Observed x-axis coordinates, usually either global_step or time. xref: array of floats From 0478f7c657af5c8d70615331626685974e083800 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Mon, 24 Mar 2025 15:02:08 +0100 Subject: [PATCH 11/22] test more --- rlberry/manager/tests/test_plot.py | 37 ++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index a207dcbfe..b20376ae1 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -78,7 +78,7 @@ def test_plot_writer_data_with_manager_input(outdir_id_style): assert len(output) > 1 -@pytest.mark.parametrize("error_representation", ["ci", "pi", "cb", "raw_curves"]) +@pytest.mark.parametrize("error_representation", ["ci", "pi", "cb", "raw_curves","none"]) def test_smooth_ci(error_representation): with tempfile.TemporaryDirectory() as tmpdirname: output_dir = tmpdirname + "/rlberry_data" @@ -123,7 +123,7 @@ def test_smooth_ci(error_representation): assert len(output) > 1 -@pytest.mark.parametrize("error_representation", ["ci", "pi", "raw_curves"]) +@pytest.mark.parametrize("error_representation", ["ci", "pi", "raw_curves", "none"]) def test_non_smooth_ci(error_representation): with tempfile.TemporaryDirectory() as tmpdirname: output_dir = tmpdirname + "/rlberry_data" @@ -159,6 +159,39 @@ def test_without_rlberry(): plot_synchronized_curves( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) + + +def test_edge_cases(): + # Nan + df = pd.DataFrame( + {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.nan], "n_simu": [0, 0, 0]} + ) + with tempfile.TemporaryDirectory() as tmpdirname: + with plt.ion(): # do not block on plt.show + plot_smoothed_curves(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_synchronized_curves( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) + # Inf + df = pd.DataFrame( + {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.inf], "n_simu": [0, 0, 0]} + ) + with tempfile.TemporaryDirectory() as tmpdirname: + with plt.ion(): # do not block on plt.show + plot_smoothed_curves(df, "x", "y", smoothing_bandwidth=1, savefig_fname=tmpdirname + "/test.png") + plot_synchronized_curves( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) + # constant + df = pd.DataFrame( + {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 3, 3], "n_simu": [0, 0, 0]} + ) + with tempfile.TemporaryDirectory() as tmpdirname: + with plt.ion(): # do not block on plt.show + plot_smoothed_curves(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_synchronized_curves( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) def test_warning_error_rep(): From 96f127fd4223cc6d3ad1320c4ce0d5eebc876c4a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:02:41 +0000 Subject: [PATCH 12/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/tests/test_plot.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index b20376ae1..3acf22388 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -78,7 +78,9 @@ def test_plot_writer_data_with_manager_input(outdir_id_style): assert len(output) > 1 -@pytest.mark.parametrize("error_representation", ["ci", "pi", "cb", "raw_curves","none"]) +@pytest.mark.parametrize( + "error_representation", ["ci", "pi", "cb", "raw_curves", "none"] +) def test_smooth_ci(error_representation): with tempfile.TemporaryDirectory() as tmpdirname: output_dir = tmpdirname + "/rlberry_data" @@ -159,12 +161,17 @@ def test_without_rlberry(): plot_synchronized_curves( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) - + def test_edge_cases(): # Nan df = pd.DataFrame( - {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.nan], "n_simu": [0, 0, 0]} + { + "name": ["a", "a", "a"], + "x": [1, 2, 3], + "y": [3, 4, np.nan], + "n_simu": [0, 0, 0], + } ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show @@ -174,11 +181,22 @@ def test_edge_cases(): ) # Inf df = pd.DataFrame( - {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.inf], "n_simu": [0, 0, 0]} + { + "name": ["a", "a", "a"], + "x": [1, 2, 3], + "y": [3, 4, np.inf], + "n_simu": [0, 0, 0], + } ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_smoothed_curves(df, "x", "y", smoothing_bandwidth=1, savefig_fname=tmpdirname + "/test.png") + plot_smoothed_curves( + df, + "x", + "y", + smoothing_bandwidth=1, + savefig_fname=tmpdirname + "/test.png", + ) plot_synchronized_curves( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) From faf599817dfb447c42544ae3fcedc331cc18a6d2 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Wed, 26 Mar 2025 16:15:12 +0100 Subject: [PATCH 13/22] fix typo handling data df --- rlberry/manager/plotting.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 41c5137a8..ee417b0e8 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -314,12 +314,13 @@ def process(df): """ Nadaraya-Watson kernel smoothing """ - n_tot_simu = int(data["n_simu"].max()) + 1 + n_tot_simu = int(df["n_simu"].max()) + 1 Yhat = np.zeros([n_tot_simu, len(xplot)]) bw = smoothing_bandwidth for f in range(n_tot_simu): Y = df_name.loc[df["n_simu"] == f, ylabel].values + try: np.isfinite(Y) except: @@ -337,6 +338,7 @@ def process(df): Yhat[f] = nw.get_y_smoothed(Y) else: Yhat[f] = np.nan * np.ones(len(xplot)) + return Yhat names = np.unique(data["name"]) @@ -346,7 +348,7 @@ def process(df): df_name = data.loc[data["name"] == name] n_tot_simu = int(df_name["n_simu"].max()) + 1 Xhat = process(df_name) - mu = np.mean(Xhat, axis=0) + mu = np.nanmean(Xhat, axis=0) id_plot = xplot <= np.max(df_name[xlabel]) ax.plot( @@ -676,7 +678,6 @@ def H(self, xi, xref): else self.bandwidth ) numerator = self.kernel(D / bandwidth) - return numerator / np.sum(numerator, axis=1)[:, np.newaxis] def get_y_smoothed(self, y): From f0fdfdd62285419337692adbd981796f07d6ab22 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Tue, 29 Apr 2025 11:50:22 +0200 Subject: [PATCH 14/22] change plot function names and remove ref to scikit-fda --- docs/api.rst | 4 ++-- docs/basics/quick_start_rl/quickstart.md | 2 +- rlberry/manager/__init__.py | 2 +- rlberry/manager/plotting.py | 14 ++++++-------- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index d655ecc78..f2c48ec38 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -34,8 +34,8 @@ Evaluation and plot manager.evaluate_agents manager.read_writer_data manager.plot_writer_data - manager.plot_smoothed_curves - manager.plot_synchronized_curves + manager.plot_curves_smoothed_NW + manager.plot_curves_with_same_x manager.compare_agents manager.tensorboard_to_dataframe diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 52775aca7..a0ab36b9f 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -270,7 +270,7 @@ iteration, the environment takes 100 steps (`horizon`) times the -Finally, we plot the reward. Here you can see the mean value over the 10 fitted agent, with 2 options (raw and smoothed). Note that, to be able to see the smoothed version, you must have installed the extra package `scikit-fda`, (For more information, you can check the options on the [install page](../../installation.md#options)). +Finally, we plot the reward. Here you can see the mean value over the 10 fitted agent, with 2 options (raw and smoothed). ```python # Plot of the reward. diff --git a/rlberry/manager/__init__.py b/rlberry/manager/__init__.py index 3d559c163..fa4fbfc32 100644 --- a/rlberry/manager/__init__.py +++ b/rlberry/manager/__init__.py @@ -3,7 +3,7 @@ from .multiple_managers import MultipleManagers from .evaluation import evaluate_agents, read_writer_data from .comparison import compare_agents, AdastopComparator -from .plotting import plot_smoothed_curves, plot_writer_data, plot_synchronized_curves +from .plotting import plot_curves_smoothed_NW, plot_writer_data, plot_curves_with_same_x from .env_tools import with_venv, run_venv_xp from .utils import tensorboard_to_dataframe diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 41c5137a8..04201cca5 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -182,7 +182,7 @@ def plot_writer_data( if ax is None: figure, ax = plt.subplots(1, 1) if smooth: - data_smoothed = plot_smoothed_curves( + data_smoothed = plot_curves_smoothed_NW( data[["name", xtag, "value", "n_simu"]], xtag, "value", @@ -196,7 +196,7 @@ def plot_writer_data( linestyles, ) else: - data_smoothed = plot_synchronized_curves( + data_smoothed = plot_curves_with_same_x( data[["name", xtag, "value", "n_simu"]], xtag, "value", @@ -221,7 +221,7 @@ def plot_writer_data( return data -def plot_smoothed_curves( +def plot_curves_smoothed_NW( data, x, y, @@ -237,7 +237,7 @@ def plot_smoothed_curves( """ Plot the performances contained in the data (see data parameter to learn what format it should be). - If there are several simulations, a confidence interval is plotted. + If there are several simulations, an error band is plotted. In all cases a smoothing is performed. @@ -264,7 +264,7 @@ def plot_smoothed_curves( error_representation: str in {"cb", "raw_curves", "ci", "pi", "none"} How to represent multiple simulations. The "ci" and "pi" do not take into account the need for simultaneous inference, it is then harder to draw conclusion from them than with "cb" but they are the most widely used. - - "cb" is a confidence band on the mean curve using functional data analysis (band in which the mean curve is with probability larger than 1-level). Method from [1], using scikit-fda [2] library. + - "cb" is a confidence band on the mean curve using functional data analysis (band in which the mean curve is with probability larger than 1-level). Method from [1]. - "raw curves" is a plot of the raw curves. @@ -298,7 +298,6 @@ def plot_smoothed_curves( References ---------- [1] Degras, D. (2017). Simultaneous confidence bands for the mean of functional data. Wiley Interdisciplinary Reviews: Computational Statistics, 9(3), e1397. - [2] scikit-fda, Carlos Ramos Carreño, hzzhyj, mellamansanchez, Pablo Marcos, pedrorponga, David del Val, Pablo, David García Fernández, Martín, Miguel Carbajo Berrocal, ElenaPetrunina, Pablo Cuesta Sierra, Rafa Hidalgo, Clément Lejeune, amandaher, dSerna4, ego-thales, pedrog99, Jorge Duque, … Álvaro Castillo. (2023). GAA-UAM/scikit-fda: Version 0.9 (0.9). Zenodo. https://doi.org/10.5281/zenodo.10016930 """ @@ -452,7 +451,7 @@ def process(df): return data_smoothed -def plot_synchronized_curves( +def plot_curves_with_same_x( data, x, y, @@ -509,7 +508,6 @@ def plot_synchronized_curves( References ---------- [1] Degras, D. (2017). Simultaneous confidence bands for the mean of functional data. Wiley Interdisciplinary Reviews: Computational Statistics, 9(3), e1397. - [2] scikit-fda, Carlos Ramos Carreño, hzzhyj, mellamansanchez, Pablo Marcos, pedrorponga, David del Val, Pablo, David García Fernández, Martín, Miguel Carbajo Berrocal, ElenaPetrunina, Pablo Cuesta Sierra, Rafa Hidalgo, Clément Lejeune, amandaher, dSerna4, ego-thales, pedrog99, Jorge Duque, … Álvaro Castillo. (2023). GAA-UAM/scikit-fda: Version 0.9 (0.9). Zenodo. https://doi.org/10.5281/zenodo.10016930 """ xlabel = x From cf58449692e0d43f9f4959224acc9bc46da109c6 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Tue, 29 Apr 2025 14:13:26 +0200 Subject: [PATCH 15/22] fix test plots --- rlberry/manager/tests/test_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index 3acf22388..c648c5546 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -9,7 +9,7 @@ from rlberry_scool.envs import Chain from rlberry.manager import plot_writer_data, ExperimentManager, read_writer_data -from rlberry.manager.plotting import plot_smoothed_curves, plot_synchronized_curves +from rlberry.manager.plotting import plot_curves_smoothed_NW, plot_writer_data, plot_curves_with_same_x from rlberry.agents import AgentWithSimplePolicy # np.random.seed(42) From df661ec2929c02c08f47f7ced93424c81fe3a1aa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:14:03 +0000 Subject: [PATCH 16/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/tests/test_plot.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index c648c5546..566d4fe75 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -9,7 +9,11 @@ from rlberry_scool.envs import Chain from rlberry.manager import plot_writer_data, ExperimentManager, read_writer_data -from rlberry.manager.plotting import plot_curves_smoothed_NW, plot_writer_data, plot_curves_with_same_x +from rlberry.manager.plotting import ( + plot_curves_smoothed_NW, + plot_writer_data, + plot_curves_with_same_x, +) from rlberry.agents import AgentWithSimplePolicy # np.random.seed(42) From fccb79bdf0d16e6bd30ae9a2d91121910fd0fe80 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Tue, 29 Apr 2025 14:34:15 +0200 Subject: [PATCH 17/22] fix tests --- rlberry/manager/plotting.py | 4 ++-- rlberry/manager/tests/test_plot.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 0ec478e36..2f0ac08f8 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -289,11 +289,11 @@ def plot_curves_smoothed_NW( Examples -------- >>> import pandas as pd - >>> from rlberry.manager import plot_smoothed_curve + >>> from rlberry.manager import plot_curves_smoothed_NW >>> df = pd.DataFrame( {"name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, 5], "n_simu": [0, 0, 0]} ) - >>> plot_smoothed_curve(df, "x", "y") + >>> plot_curves_smoothed_NW(df, "x", "y") References ---------- diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index c648c5546..a01471461 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -157,8 +157,8 @@ def test_without_rlberry(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_smoothed_curves(df, "x", "y", savefig_fname=tmpdirname + "/test.png") - plot_synchronized_curves( + plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) @@ -175,8 +175,8 @@ def test_edge_cases(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_smoothed_curves(df, "x", "y", savefig_fname=tmpdirname + "/test.png") - plot_synchronized_curves( + plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) # Inf @@ -190,14 +190,14 @@ def test_edge_cases(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_smoothed_curves( + plot_curves_smoothed_NW( df, "x", "y", smoothing_bandwidth=1, savefig_fname=tmpdirname + "/test.png", ) - plot_synchronized_curves( + plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) # constant @@ -206,8 +206,8 @@ def test_edge_cases(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_smoothed_curves(df, "x", "y", savefig_fname=tmpdirname + "/test.png") - plot_synchronized_curves( + plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) From f685f279aec77978b1c463881f95bf025f578c4d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:35:08 +0000 Subject: [PATCH 18/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/tests/test_plot.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index 3b9a78226..627ffcb90 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -161,7 +161,9 @@ def test_without_rlberry(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_smoothed_NW( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) @@ -179,7 +181,9 @@ def test_edge_cases(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_smoothed_NW( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) @@ -210,7 +214,9 @@ def test_edge_cases(): ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show - plot_curves_smoothed_NW(df, "x", "y", savefig_fname=tmpdirname + "/test.png") + plot_curves_smoothed_NW( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) plot_curves_with_same_x( df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) From d10476c7de2ed7e0e4004b4bd3d885779fead787 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Wed, 30 Apr 2025 15:20:42 +0200 Subject: [PATCH 19/22] fix n_simu non sequential bug --- rlberry/manager/plotting.py | 13 +++++++++++++ rlberry/manager/tests/test_plot.py | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index 2f0ac08f8..f6da95ee3 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -303,6 +303,12 @@ def plot_curves_smoothed_NW( xlabel = x ylabel = y + + data_temp = data.copy() + for n, n_simu in enumerate(data_temp["n_simu"].unique()): + data.loc[data["n_simu"] == n_simu, "n_simu"] = n + del data_temp + x_values = data[xlabel].values min_x, max_x = x_values.min(), x_values.max() xplot = np.linspace(min_x, max_x, 500, endpoint=True) @@ -514,7 +520,14 @@ def plot_curves_with_same_x( """ xlabel = x ylabel = y + assert len(data) > 0, "dataset is empty" + + data_temp = data.copy() + for n, n_simu in enumerate(data_temp["n_simu"].unique()): + data.loc[data["n_simu"] == n_simu, "n_simu"] = n + del data_temp + n_tot_simu = int(data["n_simu"].max()) # check that every simulation have the same xs or truncate diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index 3b9a78226..e959181a8 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -174,7 +174,7 @@ def test_edge_cases(): "name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.nan], - "n_simu": [0, 0, 0], + "n_simu": [1, 1, 1], } ) with tempfile.TemporaryDirectory() as tmpdirname: @@ -189,7 +189,7 @@ def test_edge_cases(): "name": ["a", "a", "a"], "x": [1, 2, 3], "y": [3, 4, np.inf], - "n_simu": [0, 0, 0], + "n_simu": [3, 3, 3], } ) with tempfile.TemporaryDirectory() as tmpdirname: From 9dd4a653fca89f79ec7c615ecf17a6974e72fb3e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:21:43 +0000 Subject: [PATCH 20/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/plotting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index f6da95ee3..4eaecdc21 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -303,7 +303,7 @@ def plot_curves_smoothed_NW( xlabel = x ylabel = y - + data_temp = data.copy() for n, n_simu in enumerate(data_temp["n_simu"].unique()): data.loc[data["n_simu"] == n_simu, "n_simu"] = n From 9ff65dd73cea455789d4f2cc21d7e5b97c472485 Mon Sep 17 00:00:00 2001 From: TimotheeMathieu Date: Wed, 30 Apr 2025 15:45:10 +0200 Subject: [PATCH 21/22] fix bug not same size --- rlberry/manager/plotting.py | 2 +- rlberry/manager/tests/test_plot.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rlberry/manager/plotting.py b/rlberry/manager/plotting.py index f6da95ee3..d42fff8d6 100644 --- a/rlberry/manager/plotting.py +++ b/rlberry/manager/plotting.py @@ -368,7 +368,7 @@ def process(df): data_smoothed, pd.DataFrame( { - "name": [name] * len(id_plot), + "name": [name] * np.sum(id_plot), "x": xplot[id_plot], "y": mu[id_plot], } diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index e61debaf6..0e8112a52 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -221,6 +221,17 @@ def test_edge_cases(): df, "x", "y", savefig_fname=tmpdirname + "/test.png" ) + # Not same length + df = pd.DataFrame( + {"name": ["a", "a", "a","b","b"], "x": [1, 2, 3,1,2], "y": [3, 3, 3,4,3], "n_simu": [0, 0, 0,1,1]} + ) + with tempfile.TemporaryDirectory() as tmpdirname: + with plt.ion(): # do not block on plt.show + plot_curves_smoothed_NW( + df, "x", "y", savefig_fname=tmpdirname + "/test.png" + ) + + def test_warning_error_rep(): msg = "error_representation not implemented" From 447bed06b5e68e671ad672a19c5de02a734fc83e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:47:01 +0000 Subject: [PATCH 22/22] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/tests/test_plot.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index 0e8112a52..15b89a664 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -223,7 +223,12 @@ def test_edge_cases(): # Not same length df = pd.DataFrame( - {"name": ["a", "a", "a","b","b"], "x": [1, 2, 3,1,2], "y": [3, 3, 3,4,3], "n_simu": [0, 0, 0,1,1]} + { + "name": ["a", "a", "a", "b", "b"], + "x": [1, 2, 3, 1, 2], + "y": [3, 3, 3, 4, 3], + "n_simu": [0, 0, 0, 1, 1], + } ) with tempfile.TemporaryDirectory() as tmpdirname: with plt.ion(): # do not block on plt.show @@ -232,7 +237,6 @@ def test_edge_cases(): ) - def test_warning_error_rep(): msg = "error_representation not implemented" with tempfile.TemporaryDirectory() as tmpdirname: