Skip to content

Commit 46d6569

Browse files
committed
Create generic boxplot
Created a new shared plot, to reduce duplication in code
1 parent 20a63c4 commit 46d6569

3 files changed

Lines changed: 214 additions & 275 deletions

File tree

src/ert/gui/plotting/ert_plots/cesp.py

Lines changed: 25 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
import numpy as np
77
import pandas as pd
8-
from matplotlib.lines import Line2D
98
from natsort import natsorted
109

1110
from ert.gui.plotting.plot_api import EnsembleObject, PlotApiKeyDefinition
11+
from ert.gui.plotting.shared_plots.generic_boxplot_with_scatter import (
12+
generate_legend_items,
13+
generate_plots,
14+
)
1215
from ert.gui.plotting.utils import ConditionalAxisFormatter, PlotTools
1316
from ert.gui.plotting.utils.plot_context import PlotType
1417
from ert.gui.utils import truncate_experiment_name, truncate_string
@@ -42,10 +45,6 @@ def plot(
4245
config = plot_context.plotConfig()
4346
axes = figure.add_subplot(111)
4447
plot_context.plot_type = PlotType.BOX
45-
outlier = plot_context.outliers
46-
scatter = plot_context.scatter_plot
47-
box = plot_context.box_plot
48-
mean = plot_context.mean
4948
plot_context.deactivate_date_support()
5049

5150
plot_context.y_axis = plot_context.VALUE_AXIS
@@ -93,141 +92,29 @@ def plot(
9392
numeric_data = _assert_numeric(data)
9493
if numeric_data is None:
9594
continue
96-
if box:
97-
axes.boxplot(
98-
numeric_data,
99-
positions=[ensemble_index],
100-
widths=box_width,
101-
whis=(
102-
LOWER_PERCENTILE_FOR_WHISKERS,
103-
UPPER_PERCENTILE_FOR_WHISKERS,
104-
),
105-
patch_artist=True,
106-
showfliers=outlier,
107-
boxprops={
108-
"facecolor": color,
109-
"alpha": 0.8,
110-
"edgecolor": color,
111-
"linewidth": 0.7,
112-
},
113-
whiskerprops={
114-
"color": color,
115-
"alpha": 1,
116-
"linewidth": 1,
117-
"linestyle": "--",
118-
},
119-
capprops={
120-
"color": color,
121-
"alpha": 1,
122-
"linewidth": 2,
123-
"linestyle": "--",
124-
},
125-
medianprops={"color": "black", "linewidth": 1, "alpha": 1},
126-
flierprops={
127-
"marker": "o",
128-
"alpha": 1,
129-
"markeredgewidth": 0.3 + (0.4 * (1 - box_width)),
130-
"markeredgecolor": color,
131-
"markerfacecolor": "none",
132-
},
133-
)
134-
if scatter:
135-
rng = np.random.default_rng(42)
136-
jitter = box_width * 0.5
137-
138-
x_points: list[np.ndarray] = []
139-
x_points.append(
140-
ensemble_index
141-
+ rng.uniform(-jitter / 2, jitter / 2, size=len(numeric_data))
142-
)
143-
144-
x_all = np.concatenate(x_points)
145-
146-
axes.scatter(
147-
x_all,
148-
numeric_data,
149-
color=color,
150-
alpha=0.35,
151-
linewidths=0,
152-
zorder=2, # above bands/boxes
153-
)
154-
if mean:
155-
axes.plot(
156-
ensemble_index,
157-
np.nanmean(numeric_data),
158-
"D",
159-
markersize=4,
160-
color="black",
161-
zorder=3, # Above boxes and scatter
162-
)
163-
164-
legend_label = (
165-
(f"{truncate_string(ensemble.experiment_name, 20)} : {ensemble.name}")
166-
if multiple_experiments
167-
else ensemble.name
168-
)
169-
config.add_legend_item(
170-
legend_label,
171-
Line2D(
172-
[],
173-
[],
174-
marker="s",
175-
linestyle="None",
176-
color=color,
177-
label=legend_label,
178-
),
179-
)
180-
if box:
181-
config.add_legend_item(
182-
"Median", Line2D([0], [0], color="black", linewidth=0.9, alpha=1)
183-
)
184-
config.add_legend_item(
185-
(
186-
f"Whiskers ({LOWER_PERCENTILE_FOR_WHISKERS}-"
187-
f"{UPPER_PERCENTILE_FOR_WHISKERS} %)"
188-
),
189-
Line2D([0], [0], color="black", linewidth=2, linestyle="--", alpha=1),
190-
)
191-
if outlier:
192-
config.add_legend_item(
193-
"Outliers",
194-
Line2D(
195-
[0],
196-
[0],
197-
marker="o",
198-
color="none",
199-
markeredgecolor="black",
200-
markerfacecolor="none",
201-
markersize=6,
202-
alpha=1,
203-
),
204-
)
205-
if scatter:
206-
config.add_legend_item(
207-
"Scatter points",
208-
Line2D(
209-
[0],
210-
[0],
211-
marker="o",
212-
color="black",
213-
markeredgecolor="None",
214-
linestyle="None",
215-
alpha=0.35,
216-
),
217-
)
218-
if mean:
219-
config.add_legend_item(
220-
"Mean",
221-
Line2D(
222-
[0],
223-
[0],
224-
marker="D",
225-
color="black",
226-
markersize=4,
227-
linestyle="None",
228-
alpha=1,
95+
generate_plots(
96+
plot_context,
97+
axes,
98+
[numeric_data.to_numpy()],
99+
[ensemble_index],
100+
box_width,
101+
color,
102+
LOWER_PERCENTILE_FOR_WHISKERS,
103+
UPPER_PERCENTILE_FOR_WHISKERS,
104+
legend_label=(
105+
(
106+
f"{truncate_string(ensemble.experiment_name, 20)}"
107+
f" : {ensemble.name}"
108+
)
109+
if multiple_experiments
110+
else ensemble.name
229111
),
230112
)
113+
generate_legend_items(
114+
plot_context,
115+
LOWER_PERCENTILE_FOR_WHISKERS,
116+
UPPER_PERCENTILE_FOR_WHISKERS,
117+
)
231118

232119
axes.set_xticks([-1, *range(len(entries)), len(entries)])
233120

src/ert/gui/plotting/ert_plots/misfits.py

Lines changed: 21 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import numpy as np
66
import pandas as pd
77
import polars as pl
8-
from matplotlib.lines import Line2D
98

9+
from ert.gui.plotting.shared_plots.generic_boxplot_with_scatter import (
10+
generate_legend_items,
11+
generate_plots,
12+
)
1013
from ert.gui.plotting.utils import PlotTools
1114
from ert.gui.plotting.utils.plot_context import PlotType
1215

@@ -178,15 +181,9 @@ def _plot_misfits(
178181

179182
all_unique_indexes = all_misfits["key_index"].unique().sort().to_list()
180183
plot_context.plot_type = PlotType.BOX
181-
config = plot_context.plotConfig()
182-
outlier = plot_context.outliers
183-
scatter = plot_context.scatter_plot
184-
box = plot_context.box_plot
185-
mean = plot_context.mean
186184

187185
index_to_pos = {idx: i for i, idx in enumerate(all_unique_indexes)}
188186

189-
many_boxes_factor = min(1, len(all_unique_indexes) / 50)
190187
sorted_ensemble_keys = sorted(data_with_misfits.keys())
191188
color_map = self._map_ensembles_to_colours(
192189
sorted_ensemble_keys, plot_context.plotConfig().line_color_cycle()
@@ -208,6 +205,8 @@ def _plot_misfits(
208205

209206
for ens_idx, ens_key in enumerate(sorted_ensemble_keys):
210207
color = color_map.get(ens_key)
208+
if color is None:
209+
continue
211210

212211
df = data_with_misfits[ens_key]
213212
if df.is_empty():
@@ -227,138 +226,23 @@ def _plot_misfits(
227226
s.to_numpy() if s.len() > 0 else np.array([np.nan])
228227
for s in grouped_misfits["misfit"]
229228
]
230-
if box:
231-
axes.boxplot(
232-
data_for_boxes,
233-
positions=positions,
234-
widths=box_width,
235-
whis=(LOWER_PERCENTILE_FOR_WHISKERS, UPPER_PERCENTILE_FOR_WHISKERS),
236-
showfliers=outlier,
237-
manage_ticks=False,
238-
patch_artist=True,
239-
boxprops={
240-
"facecolor": color,
241-
"alpha": 0.8,
242-
"edgecolor": color,
243-
"linewidth": 0.7,
244-
},
245-
whiskerprops={
246-
"color": color,
247-
"alpha": 1,
248-
"linewidth": 0.8,
249-
"linestyle": "--",
250-
},
251-
capprops={"color": color, "alpha": 1, "linewidth": 0.8},
252-
medianprops={"color": "black", "linewidth": 0.8, "alpha": 1},
253-
flierprops={
254-
"marker": "o",
255-
"alpha": 1,
256-
"markeredgewidth": 0.3 + (0.4 * (1 - many_boxes_factor)),
257-
"markeredgecolor": color,
258-
"markerfacecolor": "none",
259-
},
260-
)
261-
262-
if mean:
263-
means = np.array(
264-
[np.nanmean(arr) for arr in data_for_boxes], dtype=float
265-
)
266-
axes.plot(
267-
positions,
268-
means,
269-
"D",
270-
markersize=4,
271-
color="black",
272-
zorder=3, # Above boxes and scatter
273-
)
274-
275-
if scatter:
276-
rng = np.random.default_rng(42)
277-
jitter = box_width * 0.5
278-
279-
x_points: list[np.ndarray] = []
280-
y_points: list[np.ndarray] = []
281-
for position, box_data in zip(positions, data_for_boxes, strict=True):
282-
x_points.append(
283-
position
284-
+ rng.uniform(-jitter / 2, jitter / 2, size=len(box_data))
285-
)
286-
y_points.append(box_data)
287-
288-
x_all = np.concatenate(x_points)
289-
y_all = np.concatenate(y_points)
290-
291-
axes.scatter(
292-
x_all,
293-
y_all,
294-
color=color,
295-
alpha=0.35,
296-
linewidths=0,
297-
zorder=2, # above bands/boxes
298-
)
299-
300-
config.add_legend_item(
301-
ens_key[0],
302-
Line2D(
303-
[],
304-
[],
305-
marker="s",
306-
linestyle="None",
307-
color=color,
308-
label=ens_key[0],
309-
),
310-
)
311-
312-
if scatter:
313-
config.add_legend_item(
314-
"Scatter points",
315-
Line2D(
316-
[0],
317-
[0],
318-
marker="o",
319-
color="black",
320-
markeredgecolor="None",
321-
linestyle="None",
322-
alpha=0.35,
323-
),
324-
)
325-
326-
if box:
327-
config.add_legend_item(
328-
"Median", Line2D([0], [0], color="black", linewidth=0.6, alpha=1)
329-
)
330-
config.add_legend_item(
331-
"Whiskers (5-95%)",
332-
Line2D([0], [0], color="black", linewidth=0.7, linestyle="--", alpha=1),
229+
generate_plots(
230+
plot_context,
231+
axes,
232+
data_for_boxes,
233+
positions,
234+
box_width,
235+
color,
236+
LOWER_PERCENTILE_FOR_WHISKERS,
237+
UPPER_PERCENTILE_FOR_WHISKERS,
238+
legend_label=ens_key[0],
333239
)
334240

335-
if mean:
336-
config.add_legend_item(
337-
"Mean",
338-
Line2D(
339-
[0],
340-
[0],
341-
marker="D",
342-
color="black",
343-
markersize=4,
344-
linestyle="None",
345-
alpha=1,
346-
),
347-
)
348-
if outlier and box:
349-
config.add_legend_item(
350-
"Outliers",
351-
Line2D(
352-
[0],
353-
[0],
354-
marker="o",
355-
color="none",
356-
markeredgecolor="black",
357-
markerfacecolor="none",
358-
markersize=6,
359-
alpha=1,
360-
),
361-
)
241+
generate_legend_items(
242+
plot_context,
243+
LOWER_PERCENTILE_FOR_WHISKERS,
244+
UPPER_PERCENTILE_FOR_WHISKERS,
245+
)
362246

363247
axes.set_xlim(-0.5, len(all_unique_indexes) - 0.5)
364248
if summary_or_breakthrough:

0 commit comments

Comments
 (0)