From 42c629aa1de96ca8c6321027817e71c45c63a1bd Mon Sep 17 00:00:00 2001
From: Polina Lakrisenko
Date: Wed, 16 Apr 2025 19:40:37 +0200
Subject: [PATCH 1/5] add ensemble parameters plot
---
pypesto/visualize/__init__.py | 2 +-
pypesto/visualize/ensemble.py | 51 ++++++++++++++++++++++++++++++++
test/visualize/test_visualize.py | 15 ++++++++++
3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/pypesto/visualize/__init__.py b/pypesto/visualize/__init__.py
index 5a1b12bef..17f624071 100644
--- a/pypesto/visualize/__init__.py
+++ b/pypesto/visualize/__init__.py
@@ -17,7 +17,7 @@
projection_scatter_umap,
projection_scatter_umap_original,
)
-from .ensemble import ensemble_identifiability
+from .ensemble import ensemble_identifiability, ensemble_parameters_plot
from .misc import process_offset_y, process_result_list, process_y_limits
from .observable_mapping import (
plot_linear_observable_mappings_from_pypesto_result,
diff --git a/pypesto/visualize/ensemble.py b/pypesto/visualize/ensemble.py
index 413341223..402c95f70 100644
--- a/pypesto/visualize/ensemble.py
+++ b/pypesto/visualize/ensemble.py
@@ -413,3 +413,54 @@ def _create_patches(
)
return patches_both_hit, patches_lb_hit, patches_ub_hit, patches_none_hit
+
+
+def ensemble_parameters_plot(
+ ensemble: Ensemble,
+ ax: Optional[plt.Axes] = None,
+ size: Optional[tuple[float]] = (12, 6)
+):
+ """
+ Visualize parameter ensemble.
+
+ Parameters
+ ----------
+ ensemble:
+ ensemble of parameter vectors (from pypesto.ensemble)
+ ax:
+ Axes object to use.
+ size:
+ Figure size (width, height) in inches. Is only applied when no ax
+ object is specified.
+
+ Returns
+ -------
+ ax: matplotlib.Axes
+ The plot axes.
+ """
+ import seaborn as sns
+
+ if ax is None:
+ fig, ax = plt.subplots(figsize=size)
+
+ x = -0.4
+ w = 0.8 # rectangle width
+ rectangles = []
+ colors = [c + (0.8,) for c in sns.color_palette("husl", n_colors=ensemble.n_x)]
+
+ sns.stripplot(np.transpose(ensemble.x_vectors), color='dimgrey')
+
+ for i, par_values in enumerate(ensemble.x_vectors):
+ h = np.max(par_values) - np.min(par_values) # rectangle hight
+ rectangles.append(
+ Rectangle((x, np.min(par_values)), w, h))
+ x += w + 0.2
+ ax.add_collection(PatchCollection(rectangles, facecolors=colors, edgecolors='dimgrey'))
+
+ ax.plot(np.arange(ensemble.n_x), ensemble.lower_bound, '--', color='grey')
+ ax.plot(np.arange(ensemble.n_x), ensemble.upper_bound, '--', color='grey')
+ ax.set_ylim(np.min(ensemble.lower_bound) * 1.1, np.max(ensemble.upper_bound) * 1.1)
+ plt.xticks(np.arange(ensemble.n_x), ensemble.x_names, rotation='vertical')
+ plt.tight_layout()
+
+ return ax
diff --git a/test/visualize/test_visualize.py b/test/visualize/test_visualize.py
index 7512b344c..574ea441e 100644
--- a/test/visualize/test_visualize.py
+++ b/test/visualize/test_visualize.py
@@ -636,6 +636,21 @@ def test_ensemble_identifiability():
# test plotting from a collection object
visualize.ensemble_identifiability(my_ensemble)
+@close_fig
+def test_ensemble_parameters_plot():
+ # creates a test problem
+ problem = create_problem(n_parameters=100)
+
+ my_ensemble = [
+ (1 + np.cos(ix) ** 2) * np.random.rand(500) - 1.0 + np.sin(ix)
+ for ix in range(100)
+ ]
+ my_ensemble = ensemble.Ensemble(
+ np.array(my_ensemble), lower_bound=problem.lb, upper_bound=problem.ub
+ )
+
+ visualize.ensemble_parameters_plot(my_ensemble)
+
@close_fig
def test_profiles():
From 61ace8b0ab2ca4b5863deb1672d53ed2985861e7 Mon Sep 17 00:00:00 2001
From: Polina Lakrisenko
Date: Tue, 6 May 2025 14:03:42 +0200
Subject: [PATCH 2/5] change colors
---
pypesto/visualize/ensemble.py | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/pypesto/visualize/ensemble.py b/pypesto/visualize/ensemble.py
index 402c95f70..7f5ce3ad7 100644
--- a/pypesto/visualize/ensemble.py
+++ b/pypesto/visualize/ensemble.py
@@ -3,6 +3,7 @@
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
+from matplotlib import colormaps
from matplotlib.collections import PatchCollection
from matplotlib.patches import Rectangle
@@ -438,7 +439,6 @@ def ensemble_parameters_plot(
ax: matplotlib.Axes
The plot axes.
"""
- import seaborn as sns
if ax is None:
fig, ax = plt.subplots(figsize=size)
@@ -446,16 +446,22 @@ def ensemble_parameters_plot(
x = -0.4
w = 0.8 # rectangle width
rectangles = []
- colors = [c + (0.8,) for c in sns.color_palette("husl", n_colors=ensemble.n_x)]
-
- sns.stripplot(np.transpose(ensemble.x_vectors), color='dimgrey')
+ cmap = colormaps['Greys']
+ colors = np.flip(cmap(np.linspace(0.3, 0.8, (ensemble.n_vectors-1))), axis=0)
+ colors = np.insert(colors, 0, [1. , 0. , 0. , 1. ], axis=0)
for i, par_values in enumerate(ensemble.x_vectors):
- h = np.max(par_values) - np.min(par_values) # rectangle hight
+ h = np.max(par_values) - np.min(par_values) # rectangle height
rectangles.append(
Rectangle((x, np.min(par_values)), w, h))
x += w + 0.2
- ax.add_collection(PatchCollection(rectangles, facecolors=colors, edgecolors='dimgrey'))
+ ax.add_collection(PatchCollection(rectangles, facecolors=[1, 1, 1, 1], edgecolors='dimgrey'))
+
+ for i, v in enumerate(ensemble.x_vectors):
+ ax.scatter(x=[i]*ensemble.n_vectors, y=v, s=40, color=colors, alpha=0.6)
+ # plot the best parameter values
+ ax.scatter(np.arange(ensemble.n_x), ensemble.x_vectors[:, 0], s=40,
+ color=[1. , 0. , 0. , 1. ])
ax.plot(np.arange(ensemble.n_x), ensemble.lower_bound, '--', color='grey')
ax.plot(np.arange(ensemble.n_x), ensemble.upper_bound, '--', color='grey')
From da99c3b432d19cf153afb45d39946991a0d2bd1e Mon Sep 17 00:00:00 2001
From: Polina Lakrisenko
Date: Tue, 6 May 2025 14:53:21 +0200
Subject: [PATCH 3/5] add possibility to plot a subset of parameters
---
pypesto/visualize/ensemble.py | 25 ++++++++++++++++++-------
test/visualize/test_visualize.py | 1 +
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/pypesto/visualize/ensemble.py b/pypesto/visualize/ensemble.py
index 7f5ce3ad7..0fb2315ed 100644
--- a/pypesto/visualize/ensemble.py
+++ b/pypesto/visualize/ensemble.py
@@ -419,6 +419,7 @@ def _create_patches(
def ensemble_parameters_plot(
ensemble: Ensemble,
ax: Optional[plt.Axes] = None,
+ parameter_ids: Optional[list[int]] = None,
size: Optional[tuple[float]] = (12, 6)
):
"""
@@ -427,9 +428,11 @@ def ensemble_parameters_plot(
Parameters
----------
ensemble:
- ensemble of parameter vectors (from pypesto.ensemble)
+ ensemble of parameter vectors (from pypesto.ensemble).
ax:
Axes object to use.
+ parameter_ids:
+ Indices of parameters to plot.
size:
Figure size (width, height) in inches. Is only applied when no ax
object is specified.
@@ -443,6 +446,14 @@ def ensemble_parameters_plot(
if ax is None:
fig, ax = plt.subplots(figsize=size)
+ if parameter_ids:
+ x_vectors = ensemble.x_vectors[parameter_ids]
+ n_x = len(parameter_ids)
+ else:
+ parameter_ids = np.arange(ensemble.n_x)
+ x_vectors = ensemble.x_vectors
+ n_x = ensemble.n_x
+
x = -0.4
w = 0.8 # rectangle width
rectangles = []
@@ -450,23 +461,23 @@ def ensemble_parameters_plot(
colors = np.flip(cmap(np.linspace(0.3, 0.8, (ensemble.n_vectors-1))), axis=0)
colors = np.insert(colors, 0, [1. , 0. , 0. , 1. ], axis=0)
- for i, par_values in enumerate(ensemble.x_vectors):
+ for i, par_values in enumerate(x_vectors):
h = np.max(par_values) - np.min(par_values) # rectangle height
rectangles.append(
Rectangle((x, np.min(par_values)), w, h))
x += w + 0.2
ax.add_collection(PatchCollection(rectangles, facecolors=[1, 1, 1, 1], edgecolors='dimgrey'))
- for i, v in enumerate(ensemble.x_vectors):
+ for i, v in enumerate(x_vectors):
ax.scatter(x=[i]*ensemble.n_vectors, y=v, s=40, color=colors, alpha=0.6)
# plot the best parameter values
- ax.scatter(np.arange(ensemble.n_x), ensemble.x_vectors[:, 0], s=40,
+ ax.scatter(np.arange(n_x), x_vectors[:, 0], s=40,
color=[1. , 0. , 0. , 1. ])
- ax.plot(np.arange(ensemble.n_x), ensemble.lower_bound, '--', color='grey')
- ax.plot(np.arange(ensemble.n_x), ensemble.upper_bound, '--', color='grey')
+ ax.plot(np.arange(n_x), ensemble.lower_bound[parameter_ids], '--', color='grey')
+ ax.plot(np.arange(n_x), ensemble.upper_bound[parameter_ids], '--', color='grey')
ax.set_ylim(np.min(ensemble.lower_bound) * 1.1, np.max(ensemble.upper_bound) * 1.1)
- plt.xticks(np.arange(ensemble.n_x), ensemble.x_names, rotation='vertical')
+ plt.xticks(np.arange(n_x), np.asarray(ensemble.x_names)[parameter_ids], rotation='vertical')
plt.tight_layout()
return ax
diff --git a/test/visualize/test_visualize.py b/test/visualize/test_visualize.py
index 574ea441e..800e8c25c 100644
--- a/test/visualize/test_visualize.py
+++ b/test/visualize/test_visualize.py
@@ -650,6 +650,7 @@ def test_ensemble_parameters_plot():
)
visualize.ensemble_parameters_plot(my_ensemble)
+ visualize.ensemble_parameters_plot(my_ensemble, parameter_ids=[0,5,8,13,17,33,45,76,82,88,90])
@close_fig
From a4d9dd99dddb3dcac7b68d8fb70f33f0eb400816 Mon Sep 17 00:00:00 2001
From: Polina Lakrisenko
Date: Tue, 6 May 2025 16:55:23 +0200
Subject: [PATCH 4/5] change to vertical
---
pypesto/visualize/ensemble.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/pypesto/visualize/ensemble.py b/pypesto/visualize/ensemble.py
index 0fb2315ed..b0e67e753 100644
--- a/pypesto/visualize/ensemble.py
+++ b/pypesto/visualize/ensemble.py
@@ -420,7 +420,7 @@ def ensemble_parameters_plot(
ensemble: Ensemble,
ax: Optional[plt.Axes] = None,
parameter_ids: Optional[list[int]] = None,
- size: Optional[tuple[float]] = (12, 6)
+ size: Optional[tuple[float]] = (6, 12)
):
"""
Visualize parameter ensemble.
@@ -454,30 +454,30 @@ def ensemble_parameters_plot(
x_vectors = ensemble.x_vectors
n_x = ensemble.n_x
- x = -0.4
- w = 0.8 # rectangle width
+ y_rect = -0.4
+ h_rect = 0.8 # rectangle height
rectangles = []
cmap = colormaps['Greys']
colors = np.flip(cmap(np.linspace(0.3, 0.8, (ensemble.n_vectors-1))), axis=0)
colors = np.insert(colors, 0, [1. , 0. , 0. , 1. ], axis=0)
for i, par_values in enumerate(x_vectors):
- h = np.max(par_values) - np.min(par_values) # rectangle height
+ w_rect = np.max(par_values) - np.min(par_values) # rectangle width
rectangles.append(
- Rectangle((x, np.min(par_values)), w, h))
- x += w + 0.2
+ Rectangle((np.min(par_values), y_rect), w_rect, h_rect))
+ y_rect += h_rect + 0.2
ax.add_collection(PatchCollection(rectangles, facecolors=[1, 1, 1, 1], edgecolors='dimgrey'))
for i, v in enumerate(x_vectors):
- ax.scatter(x=[i]*ensemble.n_vectors, y=v, s=40, color=colors, alpha=0.6)
+ ax.scatter(x=v, y=[i]*ensemble.n_vectors, s=40, color=colors, alpha=0.6)
# plot the best parameter values
- ax.scatter(np.arange(n_x), x_vectors[:, 0], s=40,
+ ax.scatter(x_vectors[:, 0], np.arange(n_x), s=40,
color=[1. , 0. , 0. , 1. ])
- ax.plot(np.arange(n_x), ensemble.lower_bound[parameter_ids], '--', color='grey')
- ax.plot(np.arange(n_x), ensemble.upper_bound[parameter_ids], '--', color='grey')
- ax.set_ylim(np.min(ensemble.lower_bound) * 1.1, np.max(ensemble.upper_bound) * 1.1)
- plt.xticks(np.arange(n_x), np.asarray(ensemble.x_names)[parameter_ids], rotation='vertical')
+ ax.plot(ensemble.lower_bound[parameter_ids], np.arange(n_x), '--', color='grey')
+ ax.plot(ensemble.upper_bound[parameter_ids], np.arange(n_x), '--', color='grey')
+ ax.set_xlim(np.min(ensemble.lower_bound) * 1.1, np.max(ensemble.upper_bound) * 1.1)
+ plt.yticks(np.arange(n_x), np.asarray(ensemble.x_names)[parameter_ids])
plt.tight_layout()
return ax
From f5691c974bfec37ada645b53b455ffe01c71b38f Mon Sep 17 00:00:00 2001
From: Polina Lakrisenko
Date: Tue, 6 May 2025 16:59:09 +0200
Subject: [PATCH 5/5] fix white spaces
---
pypesto/visualize/ensemble.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pypesto/visualize/ensemble.py b/pypesto/visualize/ensemble.py
index b0e67e753..fb2922dfe 100644
--- a/pypesto/visualize/ensemble.py
+++ b/pypesto/visualize/ensemble.py
@@ -459,20 +459,20 @@ def ensemble_parameters_plot(
rectangles = []
cmap = colormaps['Greys']
colors = np.flip(cmap(np.linspace(0.3, 0.8, (ensemble.n_vectors-1))), axis=0)
- colors = np.insert(colors, 0, [1. , 0. , 0. , 1. ], axis=0)
+ colors = np.insert(colors, 0, [1., 0., 0., 1.], axis=0)
for i, par_values in enumerate(x_vectors):
w_rect = np.max(par_values) - np.min(par_values) # rectangle width
rectangles.append(
Rectangle((np.min(par_values), y_rect), w_rect, h_rect))
y_rect += h_rect + 0.2
- ax.add_collection(PatchCollection(rectangles, facecolors=[1, 1, 1, 1], edgecolors='dimgrey'))
+ ax.add_collection(PatchCollection(rectangles, facecolors=[1., 1., 1., 1.], edgecolors='dimgrey'))
for i, v in enumerate(x_vectors):
ax.scatter(x=v, y=[i]*ensemble.n_vectors, s=40, color=colors, alpha=0.6)
# plot the best parameter values
ax.scatter(x_vectors[:, 0], np.arange(n_x), s=40,
- color=[1. , 0. , 0. , 1. ])
+ color=[1., 0., 0., 1.])
ax.plot(ensemble.lower_bound[parameter_ids], np.arange(n_x), '--', color='grey')
ax.plot(ensemble.upper_bound[parameter_ids], np.arange(n_x), '--', color='grey')