craceplot 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- craceplot/__init__.py +60 -0
- craceplot/_containers/__init__.py +0 -0
- craceplot/_containers/_core.py +1602 -0
- craceplot/_containers/_draw.py +104 -0
- craceplot/_inst/examples/acotsp/crace-3240078.stdout +838 -0
- craceplot/_inst/examples/acotsp/crace.stderr +8 -0
- craceplot/_inst/examples/acotsp/crace.test +216 -0
- craceplot/_inst/examples/acotsp/crace.train +622 -0
- craceplot/_inst/examples/cats200/crace-2814581.stdout +1665 -0
- craceplot/_inst/examples/cats200/crace.stderr +10 -0
- craceplot/_inst/examples/cats200/crace.test +1010 -0
- craceplot/_inst/examples/cats200/crace.train +655 -0
- craceplot/_plots/__init__.py +8 -0
- craceplot/_plots/_core.py +80 -0
- craceplot/_plots/parameters.py +1805 -0
- craceplot/_plots/quality.py +1406 -0
- craceplot/_scripts/__init__.py +4 -0
- craceplot/_scripts/_main.py +132 -0
- craceplot/_scripts/_utils.py +66 -0
- craceplot/_scripts/main +3 -0
- craceplot/_scripts/open_guide +12 -0
- craceplot/_settings/_description.py +168 -0
- craceplot/_settings/_options.json +299 -0
- craceplot/_utils/__init__.py +0 -0
- craceplot/_utils/_base.py +196 -0
- craceplot/_utils/_const.py +8 -0
- craceplot/_utils/_crace.py +42 -0
- craceplot/_utils/_format.py +191 -0
- craceplot/_vergit.py +2 -0
- craceplot/_version.py +24 -0
- craceplot/_vignettes/guide.ipynb +18943 -0
- craceplot-0.1.0.dist-info/METADATA +369 -0
- craceplot-0.1.0.dist-info/RECORD +61 -0
- craceplot-0.1.0.dist-info/WHEEL +5 -0
- craceplot-0.1.0.dist-info/entry_points.txt +2 -0
- craceplot-0.1.0.dist-info/licenses/LICENSE.md +21 -0
- craceplot-0.1.0.dist-info/top_level.txt +2 -0
- docs/_config.yml +51 -0
- docs/_static/css/custom.css +168 -0
- docs/_static/js/navbar.js +40 -0
- docs/_toc.yml +5 -0
- docs/index.md +4 -0
- docs/references/404.md +14 -0
- docs/references/authors.md +46 -0
- docs/references/citiation.bib +17 -0
- docs/references/functions/index.md +5 -0
- docs/references/functions/param_boxplot.ipynb +19 -0
- docs/references/index.md +44 -0
- docs/references/license.md +21 -0
- docs/references/others/favicon.ico +0 -0
- docs/references/others/favicon_io/about.txt +6 -0
- docs/references/others/favicon_io/android-chrome-192x192.png +0 -0
- docs/references/others/favicon_io/android-chrome-512x512.png +0 -0
- docs/references/others/favicon_io/apple-touch-icon.png +0 -0
- docs/references/others/favicon_io/favicon-16x16.png +0 -0
- docs/references/others/favicon_io/favicon-32x32.png +0 -0
- docs/references/others/favicon_io/site.webmanifest +1 -0
- docs/references/others/logo.png +0 -0
- docs/references/others/logo1.png +0 -0
- docs/references/plots/acotsp-parallelcoord-all.png +0 -0
- docs/requirements.txt +5 -0
|
@@ -0,0 +1,1805 @@
|
|
|
1
|
+
# craceplot._plot.parameters.py
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import re
|
|
8
|
+
import random
|
|
9
|
+
import inspect
|
|
10
|
+
import math
|
|
11
|
+
import time
|
|
12
|
+
import traceback
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pandas as pd
|
|
16
|
+
from types import SimpleNamespace
|
|
17
|
+
from matplotlib.colors import Colormap
|
|
18
|
+
from typing import TYPE_CHECKING, Union, Literal, Callable, TypeVar, ParamSpec, Optional
|
|
19
|
+
|
|
20
|
+
from craceplot._plots._core import *
|
|
21
|
+
from craceplot._utils._base import *
|
|
22
|
+
from craceplot._containers._core import bold, underline, reset, CplotOptions, Errors as CE
|
|
23
|
+
|
|
24
|
+
P = ParamSpec("P")
|
|
25
|
+
R = TypeVar("R")
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from crace.containers.crace_results import CraceResults
|
|
29
|
+
|
|
30
|
+
__all__ = []
|
|
31
|
+
|
|
32
|
+
def export(func: Callable[P, R]) -> Callable[P, R]:
|
|
33
|
+
"""append func name to list __all__"""
|
|
34
|
+
__all__.append(func.__name__)
|
|
35
|
+
return func
|
|
36
|
+
|
|
37
|
+
exclude_cols = ['configuration_id', 'slice_sampled']
|
|
38
|
+
missing_label = "<NA>"
|
|
39
|
+
|
|
40
|
+
args = SimpleNamespace(
|
|
41
|
+
# required parameters
|
|
42
|
+
data=None,
|
|
43
|
+
options=None,
|
|
44
|
+
configs=None,
|
|
45
|
+
sel_vars=None,
|
|
46
|
+
sel_kvar=None,
|
|
47
|
+
slice=True,
|
|
48
|
+
out_dir=None,
|
|
49
|
+
file_name=None,
|
|
50
|
+
tile=None,
|
|
51
|
+
cat=False,
|
|
52
|
+
console=True,
|
|
53
|
+
# optional parameters
|
|
54
|
+
colorby=None,
|
|
55
|
+
showscale=True,
|
|
56
|
+
shownan=True,
|
|
57
|
+
showfliers=False,
|
|
58
|
+
showmeans=False,
|
|
59
|
+
dpi=800,
|
|
60
|
+
nbins=5,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def add_slice(data: pd.DataFrame, slice: pd.DataFrame):
|
|
64
|
+
"""add slice information to selected data"""
|
|
65
|
+
last_configs = slice["last_config_id"].to_numpy(dtype=int)
|
|
66
|
+
idx = np.searchsorted(last_configs, data["configuration_id"].values, side="right")
|
|
67
|
+
new = data.assign(slice_sampled=idx + 1)
|
|
68
|
+
|
|
69
|
+
return new
|
|
70
|
+
|
|
71
|
+
def sel_conf(data: pd.DataFrame, args, configs=None):
|
|
72
|
+
"""
|
|
73
|
+
return a dataframe based on configuration types of IDs
|
|
74
|
+
|
|
75
|
+
:param data: full experiments data
|
|
76
|
+
:type data: pd.DataFrame
|
|
77
|
+
:param configs: string or list
|
|
78
|
+
"""
|
|
79
|
+
# configs: Union[Literal['all', 'final', 'elites', 'else'], list[int], None]='all',
|
|
80
|
+
|
|
81
|
+
if not configs: return data
|
|
82
|
+
elif isinstance(configs, str):
|
|
83
|
+
c = configs.lower()
|
|
84
|
+
if c == 'all': return data
|
|
85
|
+
elif c == 'final':
|
|
86
|
+
sel = args.data.elites
|
|
87
|
+
return data[data['configuration_id'].isin(sel)]
|
|
88
|
+
elif c == 'elites':
|
|
89
|
+
sel = args.data.all_elites
|
|
90
|
+
return data[data['configuration_id'].isin(sel)]
|
|
91
|
+
elif isinstance(configs, list):
|
|
92
|
+
return data[data['configuration_id'].isin(configs)]
|
|
93
|
+
else:
|
|
94
|
+
raise CE.OptionError(f"Failed to select data based on provided configuration value {configs}, "
|
|
95
|
+
f"please check {underline}configs{reset} or {underline}numConfigurations{reset}/{underline}selConfigurations{reset}")
|
|
96
|
+
|
|
97
|
+
def parse_parameters(parameters, data):
|
|
98
|
+
"""
|
|
99
|
+
load the range of each parameter in the provided Crace results
|
|
100
|
+
"""
|
|
101
|
+
# parse all parameters from log files
|
|
102
|
+
all_parameters = {}
|
|
103
|
+
tmp_params = parameters.get_names()
|
|
104
|
+
for p in tmp_params:
|
|
105
|
+
all_parameters[p] = {}
|
|
106
|
+
all_parameters[p]['type'] = parameters.get_parameter(p).type
|
|
107
|
+
all_parameters[p]['domain'] = parameters.get_parameter(p).domain
|
|
108
|
+
|
|
109
|
+
# add user defined parameters
|
|
110
|
+
all_parameters['configuration_id'] = {}
|
|
111
|
+
all_parameters['configuration_id']['type'] = 'i'
|
|
112
|
+
all_parameters['configuration_id']['domain'] = [int(data['configuration_id'].min()), int(data['configuration_id'].max())]
|
|
113
|
+
all_parameters['slice_sampled'] = {}
|
|
114
|
+
all_parameters['slice_sampled']['type'] = 'i'
|
|
115
|
+
all_parameters['slice_sampled']['domain'] = [int(data['slice_sampled'].min()), int(data['slice_sampled'].max())]
|
|
116
|
+
return all_parameters
|
|
117
|
+
|
|
118
|
+
@enforce_types
|
|
119
|
+
def _check_options(name: str, args: SimpleNamespace):
|
|
120
|
+
"""
|
|
121
|
+
check options
|
|
122
|
+
|
|
123
|
+
options provided by args have higher priority
|
|
124
|
+
|
|
125
|
+
each option will be read from args when plotting
|
|
126
|
+
|
|
127
|
+
ONLY modify args
|
|
128
|
+
|
|
129
|
+
# required parameters
|
|
130
|
+
data=None,
|
|
131
|
+
options=None,
|
|
132
|
+
sel_vars=None,
|
|
133
|
+
sel_kvar=None,
|
|
134
|
+
slice=True,
|
|
135
|
+
out_dir=None,
|
|
136
|
+
file_name=None,
|
|
137
|
+
tile=None,
|
|
138
|
+
cat=False,
|
|
139
|
+
console=True,
|
|
140
|
+
# optional parameters
|
|
141
|
+
showscale=True,
|
|
142
|
+
shownan=True,
|
|
143
|
+
dpi=800,
|
|
144
|
+
nbins=5,
|
|
145
|
+
|
|
146
|
+
"""
|
|
147
|
+
# data must be provided
|
|
148
|
+
if not args.data:
|
|
149
|
+
raise CE.OptionError(f"{bold}data{reset} must be provided for plotting.")
|
|
150
|
+
|
|
151
|
+
# check onlytest
|
|
152
|
+
onlytest = args.data.options.onlytest.value
|
|
153
|
+
if onlytest: raise CE.CplotError(
|
|
154
|
+
f"The provided crace log files only has results for test part, "
|
|
155
|
+
f"which is unavaliable for plotting parameters."
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# slice: bool=True
|
|
159
|
+
# options.slice: Union[Literal['budget','b','experiment','e','exp','time','t','T'], bool, None]
|
|
160
|
+
if args.options.slice.value is True or args.slice:
|
|
161
|
+
args.slice = True
|
|
162
|
+
elif (args.options.slice.value is False
|
|
163
|
+
or args.options.slice.value is None
|
|
164
|
+
or not args.slice):
|
|
165
|
+
args.slice = False
|
|
166
|
+
else:
|
|
167
|
+
print(f"#\n# Option {underline}slice{reset} value {bold}{args.options.slice.value}{reset} "
|
|
168
|
+
f"is not avaliable when plotting for parameters\n"
|
|
169
|
+
f"# selected parameters: {', '.join(args.sel_vars)}")
|
|
170
|
+
|
|
171
|
+
# showscale: bool=True
|
|
172
|
+
args.showscale = True if args.options.showscale.value or args.slice else False
|
|
173
|
+
|
|
174
|
+
# dpi: int
|
|
175
|
+
args.dpi = args.options.dpi.value if not args.options.dpi.is_default() else args.dpi
|
|
176
|
+
|
|
177
|
+
# out_dir: str=None
|
|
178
|
+
if not args.out_dir and args.options.outDir.is_set():
|
|
179
|
+
args.out_dir = args.options.outDir.value
|
|
180
|
+
if not os.path.exists(args.out_dir):
|
|
181
|
+
raise CE.OptionError(f"Provided {bold}outDir/out_dir{reset} is not exist.")
|
|
182
|
+
|
|
183
|
+
# file_name: str=None
|
|
184
|
+
if not args.file_name and args.options.fileName.is_set():
|
|
185
|
+
args.file_name = args.options.fileName.value
|
|
186
|
+
|
|
187
|
+
# tile: str=None
|
|
188
|
+
if not args.tile and args.options.title.is_set():
|
|
189
|
+
args.tile = args.options.title.value
|
|
190
|
+
|
|
191
|
+
# ===================================================================================
|
|
192
|
+
# check multiParameters (args.sel_vars)
|
|
193
|
+
multi_required = ['pair']
|
|
194
|
+
key_required = ['pair']
|
|
195
|
+
|
|
196
|
+
if not args.sel_vars:
|
|
197
|
+
|
|
198
|
+
# random selected parameters only when multiParameters is [] and sel_vars is None
|
|
199
|
+
if not args.options.multiParameters.value:
|
|
200
|
+
if name == 'coord': k=10
|
|
201
|
+
elif name == 'cat': k=2
|
|
202
|
+
elif name == 'sun': k=6
|
|
203
|
+
elif name == 'hist':
|
|
204
|
+
if args.slice: k=1
|
|
205
|
+
else: k=8
|
|
206
|
+
elif name == 'box': k=1
|
|
207
|
+
else:
|
|
208
|
+
raise CE.OptionError(f"{underline}multiParamters/parameters/sel_vars{reset} must be provided here.")
|
|
209
|
+
|
|
210
|
+
if name not in []:
|
|
211
|
+
random.seed(time.time())
|
|
212
|
+
args.sel_vars = sorted(random.sample(args.data.parameters.get_names(), k=k), key=str.lower)
|
|
213
|
+
print(f"#\n# No parameters selected to draw plot, "
|
|
214
|
+
f"set to the default(random selected {k} parameters).\n"
|
|
215
|
+
f"# selected parameters: {', '.join(args.sel_vars)}"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# check each parameters when multiParameters is provided
|
|
219
|
+
# and assign valid multiParameters to args.sel_vars
|
|
220
|
+
else:
|
|
221
|
+
for x in args.options.multiParameters.value:
|
|
222
|
+
if x not in args.data.parameters.get_names():
|
|
223
|
+
raise CE.ParameterValueError(f"Provided {bold}{x}{reset} is an invalid parameter.")
|
|
224
|
+
args.sel_vars = args.options.multiParameters.value
|
|
225
|
+
|
|
226
|
+
# check sel_vars for specific plots
|
|
227
|
+
if name in ['cat', 'heat', 'joint'] and len(args.sel_vars) > 2:
|
|
228
|
+
del args.sel_vars[2:]
|
|
229
|
+
print(f"#\n# More than two parameters are provided for drawing plot.\n"
|
|
230
|
+
f"# selected parameters: {', '.join(args.sel_vars)}")
|
|
231
|
+
|
|
232
|
+
if name in ['joint'] and len(args.sel_vars) == 1:
|
|
233
|
+
print(f"#\n# Two parameters must be provided for drawing plot.\n")
|
|
234
|
+
|
|
235
|
+
if name in ['pair', 'joint']:
|
|
236
|
+
for x in args.sel_vars:
|
|
237
|
+
if args.data.parameters.get_parameter(x).type == 'c':
|
|
238
|
+
raise CE.OptionError(f"When {bold}{methods_table_param[name]}{reset} is selected, "
|
|
239
|
+
f"{underline}multiParameters/sel_vars{reset} ({bold}{x}{reset}) must be numeric.")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# ====================================================================================
|
|
243
|
+
# check keyParameter (args.sel_kvar)
|
|
244
|
+
# provided key parameter
|
|
245
|
+
if args.sel_kvar is not None:
|
|
246
|
+
key_v = args.sel_kvar
|
|
247
|
+
elif args.options and args.options.keyParameter.is_set():
|
|
248
|
+
key_v = args.options.keyParameter.value
|
|
249
|
+
else:
|
|
250
|
+
key_v = None
|
|
251
|
+
|
|
252
|
+
# if key parameter is provided
|
|
253
|
+
if key_v:
|
|
254
|
+
if name == 'coord':
|
|
255
|
+
print(f"#\n# Parameter {bold}{key_v}{reset} is used for colorscale.")
|
|
256
|
+
if name == 'pair' and args.data.parameters.get_parameter(key_v).type != 'c':
|
|
257
|
+
raise CE.OptionError(f"When {bold}pairplot{reset} is selected, {underline}keyParameter/sel_kvar{reset} must be categorical.")
|
|
258
|
+
|
|
259
|
+
# if key parameter is not provided: set as default
|
|
260
|
+
else:
|
|
261
|
+
if name == 'coord':
|
|
262
|
+
print(f"#\n# No {underline}keyParameter{reset} or {bold}sel_kvar{reset} provided, set colorscale as default.")
|
|
263
|
+
elif name == 'box' and not args.sel_vars:
|
|
264
|
+
raise CE.OptionError(f"Either {underline}multiParamters/sel_vars{reset} or "
|
|
265
|
+
f"{underline}keyParameter/hue/sel_kvar{reset} must be provided here "
|
|
266
|
+
f"for {bold}{methods_table_param[name]}{reset}")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
elif name in key_required:
|
|
270
|
+
raise CE.OptionError(f"{underline}keyParameter/hue/sel_kvar{reset} must be provided here.")
|
|
271
|
+
|
|
272
|
+
if args.options.slice.value or args.slice:
|
|
273
|
+
key_v = 'slice_sampled'
|
|
274
|
+
else:
|
|
275
|
+
key_v = 'configuration_id'
|
|
276
|
+
|
|
277
|
+
args.sel_kvar = key_v if name not in ['heat', 'cat'] else None
|
|
278
|
+
|
|
279
|
+
if name == 'pair' and args.data.parameters.get_parameter(args.sel_kvar).type != 'c':
|
|
280
|
+
raise CE.OptionError(f"When {bold}pairplot{reset} is selected, {underline}keyParameter/sel_kvar{reset} must be categorical.")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# check configurations
|
|
284
|
+
if not args.configs:
|
|
285
|
+
c = args.options.numConfigurations.value
|
|
286
|
+
if c.lower() in ['all', 'final', 'elites']:
|
|
287
|
+
args.configs = c
|
|
288
|
+
elif c.lower() == 'else':
|
|
289
|
+
args.configs = c
|
|
290
|
+
else:
|
|
291
|
+
args.configs = None
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _check_str_list(lst):
|
|
295
|
+
import ast
|
|
296
|
+
try:
|
|
297
|
+
for x in lst:
|
|
298
|
+
if not isinstance(x, str):
|
|
299
|
+
return False
|
|
300
|
+
v = ast.literal_eval(x)
|
|
301
|
+
if not isinstance(v, (int, float)):
|
|
302
|
+
return False
|
|
303
|
+
return True
|
|
304
|
+
except Exception:
|
|
305
|
+
return False
|
|
306
|
+
|
|
307
|
+
@enforce_types
|
|
308
|
+
def _map_values(name: str, data: pd.DataFrame, ori_params, parameters, cat: bool=False, nbins: int=5, shownan: bool=True):
|
|
309
|
+
"""map parameter values"""
|
|
310
|
+
data = data[list(parameters.keys())].copy()
|
|
311
|
+
|
|
312
|
+
# print("#\n# The selected crace results:")
|
|
313
|
+
# print(data)
|
|
314
|
+
|
|
315
|
+
num = len(data)
|
|
316
|
+
|
|
317
|
+
vars_dict = []
|
|
318
|
+
vars_dict = safe_copy(parameters)
|
|
319
|
+
|
|
320
|
+
# add ticktext
|
|
321
|
+
for pname in parameters.keys():
|
|
322
|
+
vars_dict[pname]['vals'] = safe_copy(vars_dict[pname]['domain'])
|
|
323
|
+
vars_dict[pname]['text'] = safe_copy(vars_dict[pname]['domain'])
|
|
324
|
+
|
|
325
|
+
map_dic = {}
|
|
326
|
+
show_info = False
|
|
327
|
+
print_info = True if name in ['cat', 'coord'] else False
|
|
328
|
+
|
|
329
|
+
types = set(parameters[pname]['type'] for pname in ori_params.keys())
|
|
330
|
+
max_l = max([len(x) for x in vars_dict.keys() if x not in exclude_cols])
|
|
331
|
+
|
|
332
|
+
col = data[pname].copy()
|
|
333
|
+
data[pname] = (col.replace(['null', 'NULL', 'none', 'None', 'missing', 'NA', 'NaN', None], np.nan))
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
# ====================================================================================
|
|
337
|
+
# replace NaN values
|
|
338
|
+
if shownan:
|
|
339
|
+
all_nan_cols = data.count() == 0
|
|
340
|
+
ratios = [data[pname].isna().sum() / float(num) for pname in all_nan_cols.index]
|
|
341
|
+
# if any (r > 0 for r in ratios): print("#\n# Replacig MISSING values..")
|
|
342
|
+
|
|
343
|
+
for pname, per in zip(all_nan_cols.index, ratios):
|
|
344
|
+
if pname not in vars_dict.keys(): continue
|
|
345
|
+
if pname in exclude_cols: continue
|
|
346
|
+
|
|
347
|
+
ptype = vars_dict[pname]['type']
|
|
348
|
+
pdomain = safe_copy(vars_dict[pname]['domain'])
|
|
349
|
+
|
|
350
|
+
if per > 0:
|
|
351
|
+
# replace nan
|
|
352
|
+
# === categorical / ordinal ===
|
|
353
|
+
if ptype in ('c', 'o'):
|
|
354
|
+
# expand domain
|
|
355
|
+
if data[pname].isna().any() and missing_label not in pdomain:
|
|
356
|
+
vars_dict[pname]['domain'] = pdomain + [missing_label]
|
|
357
|
+
vars_dict[pname]['vals'] = pdomain + [missing_label]
|
|
358
|
+
vars_dict[pname]['text'] = pdomain + [missing_label]
|
|
359
|
+
|
|
360
|
+
col = data[pname].copy()
|
|
361
|
+
data[pname] = (col.fillna(missing_label))
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# === continuous ===
|
|
365
|
+
else:
|
|
366
|
+
pmin, pmax = pdomain
|
|
367
|
+
|
|
368
|
+
minimo = pmin
|
|
369
|
+
maximo = round(pmax * 5 / 4, 1)
|
|
370
|
+
|
|
371
|
+
medio = round(pmax / 4, 1)
|
|
372
|
+
medio2 = round(pmax / 2, 1)
|
|
373
|
+
medio3 = round(pmax * 3 / 4, 1)
|
|
374
|
+
|
|
375
|
+
vars_dict[pname]['domain'] = [minimo, maximo]
|
|
376
|
+
vars_dict[pname]['vals'] = [minimo, medio, medio2, medio3, pmax, maximo]
|
|
377
|
+
vars_dict[pname]['text'] = [minimo, medio, medio2, medio3, pmax, missing_label]
|
|
378
|
+
|
|
379
|
+
col = data[pname].copy()
|
|
380
|
+
data[pname] = (col.fillna(maximo).astype(float))
|
|
381
|
+
|
|
382
|
+
elif ptype in ('i', 'i,log', 'r', 'r,log'):
|
|
383
|
+
minimo, maximo = pdomain
|
|
384
|
+
|
|
385
|
+
medio = round(maximo / 4, 1)
|
|
386
|
+
medio2 = round(maximo / 2, 1)
|
|
387
|
+
medio3 = round(maximo * 3 / 4, 1)
|
|
388
|
+
|
|
389
|
+
vars_dict[pname]['domain'] = [minimo, maximo]
|
|
390
|
+
vars_dict[pname]['vals'] = vars_dict[pname]['text'] = [minimo, medio, medio2, medio3, maximo]
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# ====================================================================================
|
|
394
|
+
# convert parameter type
|
|
395
|
+
# if name not in ['hist', 'box', 'sun', 'coord']:
|
|
396
|
+
if name in ['cat', 'heat', 'coord']:
|
|
397
|
+
for pname in parameters.keys():
|
|
398
|
+
if pname in exclude_cols: continue
|
|
399
|
+
ptype = parameters[pname]['type']
|
|
400
|
+
|
|
401
|
+
# continouse -> categorical
|
|
402
|
+
if cat and ptype != 'c':
|
|
403
|
+
old = vars_dict[pname]['domain']
|
|
404
|
+
colmin = vars_dict[pname]['domain'][0]
|
|
405
|
+
colmax = vars_dict[pname]['domain'][1]
|
|
406
|
+
safe_max = np.nextafter(colmax, np.inf)
|
|
407
|
+
safe_min = np.nextafter(colmin, -np.inf)
|
|
408
|
+
# get sub-domains
|
|
409
|
+
bins = np.linspace(safe_min, safe_max, nbins + 1)
|
|
410
|
+
display_bins = np.linspace(colmin, colmax, nbins+1)
|
|
411
|
+
# digitize
|
|
412
|
+
# return 1..N_bins
|
|
413
|
+
vals = data[pname].values
|
|
414
|
+
binned = np.full_like(vals, fill_value=np.nan, dtype=float)
|
|
415
|
+
mask = ~np.isnan(vals)
|
|
416
|
+
# map value to sub-domains
|
|
417
|
+
# from 0 to nbins-1
|
|
418
|
+
res = np.digitize(vals[mask], bins, right=False) - 1
|
|
419
|
+
res = np.clip(res, 0, nbins - 1)
|
|
420
|
+
|
|
421
|
+
# 2. update data
|
|
422
|
+
binned[mask] = res
|
|
423
|
+
data[pname] = binned
|
|
424
|
+
# 3. update domain and type
|
|
425
|
+
if missing_label not in vars_dict[pname]['text']:
|
|
426
|
+
vars_dict[pname]['text'] = [f"[{display_bins[i]:.1f}, {display_bins[i+1]:.1f})" for i in range(nbins)]
|
|
427
|
+
else:
|
|
428
|
+
vars_dict[pname]['text'] = [f"[{display_bins[i]:.1f}, {display_bins[i+1]:.1f})" for i in range(nbins-1)]+[missing_label]
|
|
429
|
+
|
|
430
|
+
vars_dict[pname]['domain'] = list(range(0, nbins))
|
|
431
|
+
vars_dict[pname]['vals'] = list(range(0, nbins))
|
|
432
|
+
vars_dict[pname]['type'] = 'c'
|
|
433
|
+
|
|
434
|
+
if not show_info:
|
|
435
|
+
print("#\n# Mapping parameter type..")
|
|
436
|
+
show_info = True
|
|
437
|
+
print(f"# (WARNING: convert parameter {bold}{pname}{reset}({ptype}) to categorical for plotting)")
|
|
438
|
+
# print("# %*s: old domain %s -> new domain %s " % (max_l, pname, old, vars_dict[pname]['text']))
|
|
439
|
+
|
|
440
|
+
# catgorical -> continouse
|
|
441
|
+
if not cat and ptype == 'c':
|
|
442
|
+
old = list(vars_dict[pname]['domain'])
|
|
443
|
+
map_dic[pname] = {v: int(i) for i, v in enumerate(old)}
|
|
444
|
+
vals = list(map_dic[pname].values())
|
|
445
|
+
|
|
446
|
+
col = data[pname].copy()
|
|
447
|
+
data[pname] = (col.map(map_dic[pname]).astype(int))
|
|
448
|
+
|
|
449
|
+
vars_dict[pname]['domain'] = [min(vals), max(vals)]
|
|
450
|
+
vars_dict[pname]['vals'] = vals
|
|
451
|
+
vars_dict[pname]['text'] = old
|
|
452
|
+
|
|
453
|
+
if not show_info:
|
|
454
|
+
print("#\n# Mapping parameter type..")
|
|
455
|
+
show_info = True
|
|
456
|
+
print(f"# (WARNING: map values of parameter {bold}{pname}{reset}({ptype}) for ploltting)")
|
|
457
|
+
# print("# %*s: old domain %s -> new domain %s " % (max_l, pname, old, vars_dict[pname]['domain']))
|
|
458
|
+
|
|
459
|
+
return data, vars_dict
|
|
460
|
+
|
|
461
|
+
@enforce_types
|
|
462
|
+
def _load_data(name: str, args: SimpleNamespace):
|
|
463
|
+
"""load data"""
|
|
464
|
+
src_configs = args.data.configurations.print_all().kwargs['all']
|
|
465
|
+
src_configs = src_configs.rename(columns={".ID": "configuration_id"})
|
|
466
|
+
src_configs = src_configs.rename(columns={".PARENT": "parent_id"})
|
|
467
|
+
|
|
468
|
+
src_pd = add_slice(data=src_configs, slice=args.data.training.slice)
|
|
469
|
+
sel_pd = sel_conf(data=src_pd, configs=args.configs, args=args)
|
|
470
|
+
|
|
471
|
+
src_vars = parse_parameters(args.data.parameters, sel_pd)
|
|
472
|
+
|
|
473
|
+
# print("#\n# The original crace results:")
|
|
474
|
+
# print(sel_pd)
|
|
475
|
+
|
|
476
|
+
ori_dict = {}
|
|
477
|
+
sel_dict = {}
|
|
478
|
+
for x in args.sel_vars:
|
|
479
|
+
ori_dict[x] = {}
|
|
480
|
+
ori_dict[x] = safe_copy(src_vars[x])
|
|
481
|
+
sel_dict[x] = {}
|
|
482
|
+
sel_dict[x] = safe_copy(src_vars[x])
|
|
483
|
+
if name in ['hist', 'box', 'coord'] or (args.sel_kvar and args.sel_kvar not in exclude_cols):
|
|
484
|
+
sel_dict[args.sel_kvar] = {}
|
|
485
|
+
sel_dict[args.sel_kvar] = safe_copy(src_vars[args.sel_kvar])
|
|
486
|
+
if name == 'heat':
|
|
487
|
+
for x in exclude_cols:
|
|
488
|
+
if x not in sel_dict: sel_dict[x] = safe_copy(src_vars[x])
|
|
489
|
+
|
|
490
|
+
new_data, new_vars = _map_values(name=name, data=sel_pd, ori_params=ori_dict, parameters=sel_dict, cat=args.cat, nbins=args.nbins, shownan=args.shownan)
|
|
491
|
+
|
|
492
|
+
# print("#\n# The new Crace results:")
|
|
493
|
+
# print(new_data)
|
|
494
|
+
|
|
495
|
+
return new_data, src_vars, new_vars
|
|
496
|
+
|
|
497
|
+
@enforce_types
|
|
498
|
+
def _resolve_input(name: str, args: SimpleNamespace):
|
|
499
|
+
"""
|
|
500
|
+
resolve input
|
|
501
|
+
"""
|
|
502
|
+
new_data= None
|
|
503
|
+
new_vars=None
|
|
504
|
+
|
|
505
|
+
_check_options(name=name, args=args)
|
|
506
|
+
|
|
507
|
+
new_data, src_vars, new_vars = _load_data(name=name, args=args)
|
|
508
|
+
|
|
509
|
+
return new_data, src_vars, new_vars
|
|
510
|
+
|
|
511
|
+
def plot_parameters(method: str, **kwargs):
|
|
512
|
+
"""
|
|
513
|
+
entrance to call plotting function from file _draw.py
|
|
514
|
+
including try-except
|
|
515
|
+
"""
|
|
516
|
+
# drawMethod: (boxplot, violinplot, parallelcoord, parallelcat, sunburst, pairplot, histplot, jointplot, heatmap)
|
|
517
|
+
|
|
518
|
+
func = dispatch_table_param.get(method)
|
|
519
|
+
|
|
520
|
+
try:
|
|
521
|
+
if func: return func(**kwargs)
|
|
522
|
+
else: raise ValueError(f"Method '{method}' is not defined in dispatch table.")
|
|
523
|
+
|
|
524
|
+
except Exception as e:
|
|
525
|
+
print("\n! There was an error while plotting for parameters:")
|
|
526
|
+
if any(isinstance(e, cls) for cls in [x[1] for x in inspect.getmembers(CE, inspect.isclass)]):
|
|
527
|
+
print(f"! {e}")
|
|
528
|
+
else:
|
|
529
|
+
err = traceback.format_exc()
|
|
530
|
+
print(err)
|
|
531
|
+
if kwargs["_console"]: return None
|
|
532
|
+
sys.exit(1)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
@export
|
|
536
|
+
@enforce_types
|
|
537
|
+
def param_parallelcoord(
|
|
538
|
+
# required parameters
|
|
539
|
+
data: CraceResults=None,
|
|
540
|
+
options: CplotOptions=None,
|
|
541
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
542
|
+
parameters: Union[list[str], str, None]=None,
|
|
543
|
+
colorby: str=None,
|
|
544
|
+
slice: bool=True,
|
|
545
|
+
out_dir: str=None,
|
|
546
|
+
file_name: str=None,
|
|
547
|
+
tile: str=None,
|
|
548
|
+
_console: bool=True,
|
|
549
|
+
# optional parameters
|
|
550
|
+
showscale: bool=True,
|
|
551
|
+
shownan: bool=True,
|
|
552
|
+
nbins: int=5,
|
|
553
|
+
# specific parameters
|
|
554
|
+
width: int=2560,
|
|
555
|
+
height: int=1440,
|
|
556
|
+
colorscale: str='Tealrose',
|
|
557
|
+
):
|
|
558
|
+
"""
|
|
559
|
+
Entrance to call parallel coord in python console
|
|
560
|
+
|
|
561
|
+
:param data: object CraceResults that must be provided.
|
|
562
|
+
:param options: object CplotOptions that must be provided.
|
|
563
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations. Supported values are 'all', 'final', 'elites' or a list of configuration IDs. Default is 'all'.
|
|
564
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
565
|
+
:param colorby: A string of parameter name selected for plotting, higher priority than option keyParameter.
|
|
566
|
+
:param showscale: Boolean used to enable/diable showing colorscale.
|
|
567
|
+
:param shownan: Boolean used to plot including/excluding missing values.
|
|
568
|
+
:param colorscale: A string of palatte name for plotting.
|
|
569
|
+
"""
|
|
570
|
+
kwargs = locals()
|
|
571
|
+
plot_parameters(method='coord', **kwargs)
|
|
572
|
+
|
|
573
|
+
@enforce_types
|
|
574
|
+
@register_param(['parallelcoord', 'coord'])
|
|
575
|
+
def _parallel_coord(
|
|
576
|
+
# required parameters
|
|
577
|
+
data: CraceResults=None,
|
|
578
|
+
options: CplotOptions=None,
|
|
579
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
580
|
+
parameters: Union[list[str], str, None]=None,
|
|
581
|
+
colorby: str=None,
|
|
582
|
+
slice: bool=True,
|
|
583
|
+
out_dir: str=None,
|
|
584
|
+
file_name: str=None,
|
|
585
|
+
tile: str=None,
|
|
586
|
+
_console: bool=True,
|
|
587
|
+
# optional parameters
|
|
588
|
+
showscale: bool=True,
|
|
589
|
+
shownan: bool=True,
|
|
590
|
+
nbins: int=5,
|
|
591
|
+
# specific parameters
|
|
592
|
+
width: int=2560,
|
|
593
|
+
height: int=1440,
|
|
594
|
+
colorscale: str='Tealrose',
|
|
595
|
+
):
|
|
596
|
+
"""drawing parallel coord plot"""
|
|
597
|
+
try:
|
|
598
|
+
import plotly.graph_objects as go
|
|
599
|
+
except ImportError as e:
|
|
600
|
+
raise e
|
|
601
|
+
|
|
602
|
+
if isinstance(parameters, str):
|
|
603
|
+
parameters = [parameters]
|
|
604
|
+
|
|
605
|
+
args = SimpleNamespace(
|
|
606
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(parameters),
|
|
607
|
+
sel_kvar=colorby, slice=slice,
|
|
608
|
+
out_dir=out_dir, file_name=file_name, tile=tile,
|
|
609
|
+
cat=False, console=_console,
|
|
610
|
+
configs=configs,
|
|
611
|
+
# optional parameters
|
|
612
|
+
showscale=showscale, shownan=shownan,
|
|
613
|
+
dpi=800, nbins=nbins,
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
new_data, src_vars, new_vars = _resolve_input(name='coord', args=args)
|
|
617
|
+
|
|
618
|
+
# draw parallelcoord
|
|
619
|
+
plot_dict = []
|
|
620
|
+
dimensions = {}
|
|
621
|
+
for name in new_vars.keys():
|
|
622
|
+
if new_vars[name]['type'] != 'c':
|
|
623
|
+
dimensions = dict(
|
|
624
|
+
range = new_vars[name]['domain'],
|
|
625
|
+
tickvals = new_vars[name]['vals'],
|
|
626
|
+
ticktext = new_vars[name]['text'],
|
|
627
|
+
label = name,
|
|
628
|
+
values = new_data[name]
|
|
629
|
+
)
|
|
630
|
+
else:
|
|
631
|
+
dimensions = dict(
|
|
632
|
+
range = new_vars[name]['domain'],
|
|
633
|
+
tickvals = new_vars[name]['vals'],
|
|
634
|
+
ticktext = new_vars[name]['text'],
|
|
635
|
+
label = name,
|
|
636
|
+
values = new_data[name]
|
|
637
|
+
)
|
|
638
|
+
plot_dict.append(dimensions)
|
|
639
|
+
|
|
640
|
+
if src_vars[args.sel_kvar]['type'] != 'c':
|
|
641
|
+
cmin = src_vars[args.sel_kvar]['domain'][0]
|
|
642
|
+
cmax = src_vars[args.sel_kvar]['domain'][1]
|
|
643
|
+
data_key = pd.to_numeric(new_data[args.sel_kvar])
|
|
644
|
+
|
|
645
|
+
else:
|
|
646
|
+
cmin = 0
|
|
647
|
+
cmax = len(src_vars[args.sel_kvar]['domain'])
|
|
648
|
+
data_key = new_data[args.sel_kvar]
|
|
649
|
+
|
|
650
|
+
fig = go.Figure(data=
|
|
651
|
+
go.Parcoords(
|
|
652
|
+
line = dict(color = data_key,
|
|
653
|
+
colorscale = colorscale,
|
|
654
|
+
showscale = showscale,
|
|
655
|
+
cmin = cmin,
|
|
656
|
+
cmax = cmax),
|
|
657
|
+
dimensions = list([line for line in plot_dict])
|
|
658
|
+
))
|
|
659
|
+
|
|
660
|
+
# if not _console:
|
|
661
|
+
# fig.write_image(f"{args.out_dir}/{args.file_name}", width=width, height=height)
|
|
662
|
+
# print("# {} has been saved in {}.".format(args.file_name+'.png', args.out_dir))
|
|
663
|
+
fig.show()
|
|
664
|
+
|
|
665
|
+
# @export
|
|
666
|
+
@enforce_types
|
|
667
|
+
def param_parallelcat(
|
|
668
|
+
# required parameters
|
|
669
|
+
data: CraceResults=None,
|
|
670
|
+
options: CplotOptions=None,
|
|
671
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
672
|
+
sel_vars: list=None,
|
|
673
|
+
sel_kvar: str=None,
|
|
674
|
+
slice: bool=True,
|
|
675
|
+
out_dir: str=None,
|
|
676
|
+
file_name: str=None,
|
|
677
|
+
tile: str=None,
|
|
678
|
+
_console: bool=True,
|
|
679
|
+
# optional parameters
|
|
680
|
+
shownan: bool=True,
|
|
681
|
+
nbins: int=5,
|
|
682
|
+
# specific parameters
|
|
683
|
+
width: int=2560,
|
|
684
|
+
height: int=1440,
|
|
685
|
+
):
|
|
686
|
+
kwargs = locals()
|
|
687
|
+
plot_parameters(method='cat', **kwargs)
|
|
688
|
+
|
|
689
|
+
@enforce_types
|
|
690
|
+
# @register_param(['parallelcat', 'cat'])
|
|
691
|
+
def _parallel_cat(
|
|
692
|
+
# required parameters
|
|
693
|
+
data: CraceResults=None,
|
|
694
|
+
options: CplotOptions=None,
|
|
695
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
696
|
+
sel_vars: list=None,
|
|
697
|
+
sel_kvar: str=None,
|
|
698
|
+
slice: bool=True,
|
|
699
|
+
out_dir: str=None,
|
|
700
|
+
file_name: str=None,
|
|
701
|
+
tile: str=None,
|
|
702
|
+
_console: bool=True,
|
|
703
|
+
# optional parameters
|
|
704
|
+
shownan: bool=True,
|
|
705
|
+
nbins: int=5,
|
|
706
|
+
# specific parameters
|
|
707
|
+
width: int=2560,
|
|
708
|
+
height: int=1440,
|
|
709
|
+
):
|
|
710
|
+
"""drawing parallel cat"""
|
|
711
|
+
|
|
712
|
+
try:
|
|
713
|
+
import plotly.graph_objects as go
|
|
714
|
+
except ImportError as e:
|
|
715
|
+
raise e
|
|
716
|
+
|
|
717
|
+
args = SimpleNamespace(
|
|
718
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(sel_vars),
|
|
719
|
+
sel_kvar=sel_kvar, slice=slice,
|
|
720
|
+
out_dir=out_dir, file_name=file_name, tile=tile,
|
|
721
|
+
cat=True, console=_console,
|
|
722
|
+
configs=configs,
|
|
723
|
+
# optional parameters
|
|
724
|
+
showscale=False, shownan=shownan,
|
|
725
|
+
dpi=800, nbins=nbins,
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
new_data, _, new_vars = _resolve_input(name='cat', args=args)
|
|
729
|
+
|
|
730
|
+
if args.sel_vars:
|
|
731
|
+
if len(args.sel_vars) > 2:
|
|
732
|
+
raise CE.OptionError(f"When {bold}parallelcat{reset} is called, "
|
|
733
|
+
f"two parameter names must be provided for option {underline}multiParameters{reset}!")
|
|
734
|
+
else:
|
|
735
|
+
args.sel_vars = list(new_vars.keys())
|
|
736
|
+
|
|
737
|
+
catx = args.sel_vars[0]
|
|
738
|
+
caty = args.sel_vars[1]
|
|
739
|
+
|
|
740
|
+
plot_dict = []
|
|
741
|
+
dimensions = {}
|
|
742
|
+
for name in new_vars.keys():
|
|
743
|
+
if new_vars[name]['type'] == 'c' and name not in exclude_cols:
|
|
744
|
+
dimensions = dict(
|
|
745
|
+
label = name,
|
|
746
|
+
values = new_data[name]
|
|
747
|
+
)
|
|
748
|
+
plot_dict.append(dimensions)
|
|
749
|
+
|
|
750
|
+
color = np.zeros(len(plot_dict), dtype='uint8')
|
|
751
|
+
colorscale = [[0, 'gray'], [1, 'firebrick']]
|
|
752
|
+
|
|
753
|
+
# Build figure as FigureWidget
|
|
754
|
+
fig = go.FigureWidget(data=[
|
|
755
|
+
go.Scatter(
|
|
756
|
+
x = new_data[catx],
|
|
757
|
+
y = new_data[caty],
|
|
758
|
+
marker={'color': 'gray'},
|
|
759
|
+
mode='markers',
|
|
760
|
+
selected={'marker': {'color': 'firebrick'}},
|
|
761
|
+
unselected={'marker': {'opacity': 0.5}}
|
|
762
|
+
),
|
|
763
|
+
go.Parcats(
|
|
764
|
+
domain={'y': [0, 0.4]},
|
|
765
|
+
dimensions=list([line for line in plot_dict]),
|
|
766
|
+
line={'colorscale': colorscale, 'cmin': 0, 'cmax': 1, 'color': color, 'shape': 'hspline'}),
|
|
767
|
+
])
|
|
768
|
+
|
|
769
|
+
fig.add_trace(fig.data[0])
|
|
770
|
+
fig.add_trace(fig.data[1])
|
|
771
|
+
|
|
772
|
+
fig.update_layout(
|
|
773
|
+
height=height,
|
|
774
|
+
xaxis={'title': catx},
|
|
775
|
+
yaxis={'title': caty, 'domain': [0.6, 1]},
|
|
776
|
+
dragmode='lasso',
|
|
777
|
+
hovermode='closest',
|
|
778
|
+
overwrite=True)
|
|
779
|
+
|
|
780
|
+
# Update color callback
|
|
781
|
+
def update_color(trace, points, state):
|
|
782
|
+
global color, color_numeric
|
|
783
|
+
print("Event triggered", points.point_inds)
|
|
784
|
+
|
|
785
|
+
for i in range(len(color)):
|
|
786
|
+
color[i] = 'gray'
|
|
787
|
+
for ind in points.point_inds:
|
|
788
|
+
color[ind] = 'firebrick'
|
|
789
|
+
|
|
790
|
+
color_numeric = [0 if c == 'gray' else 1 for c in color]
|
|
791
|
+
fig.data[1].line.color = color_numeric
|
|
792
|
+
fig.update_traces()
|
|
793
|
+
|
|
794
|
+
# Register callback on scatter selection...
|
|
795
|
+
fig.data[0].on_selection(update_color)
|
|
796
|
+
# and parcats click
|
|
797
|
+
fig.data[1].on_click(update_color)
|
|
798
|
+
|
|
799
|
+
# if not _console:
|
|
800
|
+
# fig.write_image(f"{args.out_dir}/{args.file_name}", width=width, height=height)
|
|
801
|
+
# print("# {} has been saved in {}.".format(args.file_name+'.png', args.out_dir))
|
|
802
|
+
fig.show()
|
|
803
|
+
|
|
804
|
+
@export
|
|
805
|
+
@enforce_types
|
|
806
|
+
def param_sunburst(
|
|
807
|
+
# required parameters
|
|
808
|
+
data: CraceResults=None,
|
|
809
|
+
options: CplotOptions=None,
|
|
810
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
811
|
+
parameters: Union[list[str], str, None]=None,
|
|
812
|
+
_console: bool=True,
|
|
813
|
+
# optional paramters
|
|
814
|
+
shownan: bool=True,
|
|
815
|
+
nbins: int=5,
|
|
816
|
+
# specific parameters
|
|
817
|
+
palette: str='vlag',
|
|
818
|
+
autosize: bool=True,
|
|
819
|
+
branchvalues: str='total',
|
|
820
|
+
maxdepth: int=3,
|
|
821
|
+
count: str='branches',
|
|
822
|
+
insidetextorientation: str='horizontal',
|
|
823
|
+
textinfo: str="label+value",
|
|
824
|
+
):
|
|
825
|
+
"""
|
|
826
|
+
Entrance to call sunburst in python console
|
|
827
|
+
|
|
828
|
+
:param data: object CraceResults that must be provided.
|
|
829
|
+
:param options: object CplotOptions that must be provided.
|
|
830
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
831
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]='all'
|
|
832
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
833
|
+
:param shownan: Boolean used to plot including/excluding missing values.
|
|
834
|
+
:param palette: A string of palatte name for plotting.
|
|
835
|
+
:param branchvalues: parameter of function Sunburst
|
|
836
|
+
:param count: parameter of function Sunburst
|
|
837
|
+
:param insidetextorientation: parameter of function Sunburst
|
|
838
|
+
:param textinfo: paramter of function Sunburst
|
|
839
|
+
"""
|
|
840
|
+
|
|
841
|
+
kwargs = locals()
|
|
842
|
+
plot_parameters(method='sun', **kwargs)
|
|
843
|
+
|
|
844
|
+
@enforce_types
|
|
845
|
+
@register_param(['sunburst', 'sun'])
|
|
846
|
+
def _sun_burst(
|
|
847
|
+
# required parameters
|
|
848
|
+
data: CraceResults=None,
|
|
849
|
+
options: CplotOptions=None,
|
|
850
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
851
|
+
parameters: Union[list[str], str, None]=None,
|
|
852
|
+
_console: bool=True,
|
|
853
|
+
# optional paramters
|
|
854
|
+
shownan: bool=True,
|
|
855
|
+
nbins: int=5,
|
|
856
|
+
# specific parameters
|
|
857
|
+
palette: str='vlag',
|
|
858
|
+
autosize: bool=True,
|
|
859
|
+
branchvalues: str='total',
|
|
860
|
+
maxdepth: int=3,
|
|
861
|
+
count: str='branches',
|
|
862
|
+
insidetextorientation: str='horizontal',
|
|
863
|
+
textinfo: str="label+value",
|
|
864
|
+
):
|
|
865
|
+
"""drawing sun burst plot"""
|
|
866
|
+
|
|
867
|
+
try:
|
|
868
|
+
import plotly.graph_objects as go
|
|
869
|
+
import seaborn as sns
|
|
870
|
+
except ImportError as e:
|
|
871
|
+
raise e
|
|
872
|
+
|
|
873
|
+
if isinstance(parameters, str):
|
|
874
|
+
parameters = [parameters]
|
|
875
|
+
|
|
876
|
+
args = SimpleNamespace(
|
|
877
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(parameters),
|
|
878
|
+
sel_kvar=None, slice=True, out_dir=None, file_name=None, tile=None,
|
|
879
|
+
cat=True, console=_console, configs=configs,
|
|
880
|
+
# optional parameters
|
|
881
|
+
showscale=False, shownan=shownan,
|
|
882
|
+
dpi=800, nbins=nbins,
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
new_data, src_vars, new_vars = _resolve_input(name='sun', args=args)
|
|
886
|
+
|
|
887
|
+
subgroup = {}
|
|
888
|
+
for name in new_vars.keys():
|
|
889
|
+
if name in exclude_cols: continue
|
|
890
|
+
subgroup[name] = {}
|
|
891
|
+
subgroup[name]['names'] = []
|
|
892
|
+
subgroup[name]['props'] = []
|
|
893
|
+
if new_vars[name]['type'] != 'c':
|
|
894
|
+
# new_vars: new domain including parsed <NA>
|
|
895
|
+
# missing_label <--> round(pmax * 5 / 4, 1)
|
|
896
|
+
new_data[name] = pd.to_numeric(new_data[name])
|
|
897
|
+
left = src_vars[name]['domain'][0]
|
|
898
|
+
right = src_vars[name]['domain'][1]
|
|
899
|
+
tmp = (left+right)/3
|
|
900
|
+
sub1 = '[{:.2f}, {:.2f}]'.format(left, tmp)
|
|
901
|
+
sub2 = '[{:.2f}, {:.2f}]'.format(tmp, 2*tmp)
|
|
902
|
+
sub3 = '[{:.2f}, {:.2f}]'.format(2*tmp, right)
|
|
903
|
+
|
|
904
|
+
subgroup[name]['names'].append(sub1)
|
|
905
|
+
s_bool = ((new_data[name] >= left) & (new_data[name] < tmp))
|
|
906
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
907
|
+
|
|
908
|
+
subgroup[name]['names'].append(sub2)
|
|
909
|
+
s_bool = ((new_data[name] >= tmp) & (new_data[name] < 2*tmp))
|
|
910
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
911
|
+
|
|
912
|
+
subgroup[name]['names'].append(sub3)
|
|
913
|
+
s_bool = ((new_data[name] >= 2*tmp) & (new_data[name] <= right))
|
|
914
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
915
|
+
|
|
916
|
+
if shownan and sum(subgroup[name]['props']) < len(new_data[name]):
|
|
917
|
+
# considering <NA> values
|
|
918
|
+
subgroup[name]['names'].append(missing_label)
|
|
919
|
+
s_bool = (new_data[name] > right)
|
|
920
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
921
|
+
|
|
922
|
+
else:
|
|
923
|
+
for x in new_vars[name]['domain']:
|
|
924
|
+
subgroup[name]['names'].append(x)
|
|
925
|
+
s_bool = new_data[name] == x
|
|
926
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
927
|
+
if shownan and sum(subgroup[name]['props']) < len(new_data[name]):
|
|
928
|
+
subgroup[name]['names'].append(missing_label)
|
|
929
|
+
s_bool = ~new_data[name].isin(new_vars[name]['domain'])
|
|
930
|
+
subgroup[name]['props'].append(s_bool.sum())
|
|
931
|
+
|
|
932
|
+
labels = []
|
|
933
|
+
values = []
|
|
934
|
+
parents = []
|
|
935
|
+
for name in new_vars.keys():
|
|
936
|
+
if name in exclude_cols: continue
|
|
937
|
+
i = 0
|
|
938
|
+
labels.append(name)
|
|
939
|
+
# values.append(self.count_values(sun_data[name]))
|
|
940
|
+
values.append(sum(subgroup[name]['props']))
|
|
941
|
+
# values[0] += sum(subgroup[name]['props'])
|
|
942
|
+
parents.append("")
|
|
943
|
+
for label in subgroup[name]['names']:
|
|
944
|
+
labels.append(label)
|
|
945
|
+
values.append(subgroup[name]['props'][i])
|
|
946
|
+
parents.append(name)
|
|
947
|
+
i += 1
|
|
948
|
+
ids = [f"{parent}/{label}" if parent else label for label, parent in zip(labels, parents)]
|
|
949
|
+
|
|
950
|
+
# print(f'\nvalues: {values}')
|
|
951
|
+
# print(f'\nlabels: {labels}')
|
|
952
|
+
# print(f'\nparents: {parents}')
|
|
953
|
+
|
|
954
|
+
mapped_palette = sns.color_palette(palette, len(labels)).as_hex()
|
|
955
|
+
|
|
956
|
+
fig = go.Figure()
|
|
957
|
+
fig.add_trace(go.Sunburst(
|
|
958
|
+
ids=ids,
|
|
959
|
+
labels = labels,
|
|
960
|
+
parents = parents,
|
|
961
|
+
values = values,
|
|
962
|
+
branchvalues=branchvalues,
|
|
963
|
+
maxdepth=maxdepth,
|
|
964
|
+
count=count,
|
|
965
|
+
insidetextorientation=insidetextorientation,
|
|
966
|
+
insidetextfont=dict(size=12,color='black'),
|
|
967
|
+
outsidetextfont=dict(size=12),
|
|
968
|
+
textinfo=textinfo,
|
|
969
|
+
marker=dict(colors=mapped_palette),
|
|
970
|
+
))
|
|
971
|
+
|
|
972
|
+
fig.update_layout(
|
|
973
|
+
margin = dict(t=0, l=0, r=0, b=0),
|
|
974
|
+
uniformtext=dict(minsize=8, mode='hide'),
|
|
975
|
+
autosize=autosize,
|
|
976
|
+
)
|
|
977
|
+
|
|
978
|
+
# if not _console:
|
|
979
|
+
# fig.write_image(f"{args.out_dir}/{args.file_name}", width=width, height=height)
|
|
980
|
+
# print("# {} has been saved in {}.".format(args.file_name+'.png', args.out_dir))
|
|
981
|
+
fig.show()
|
|
982
|
+
|
|
983
|
+
@export
|
|
984
|
+
@enforce_types
|
|
985
|
+
def param_pairplot(
|
|
986
|
+
# required parameters
|
|
987
|
+
data: CraceResults=None,
|
|
988
|
+
options: CplotOptions=None,
|
|
989
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
990
|
+
parameters: Union[list[str], str, None]=None,
|
|
991
|
+
slice: bool=True,
|
|
992
|
+
_console: bool=True,
|
|
993
|
+
# optional parameters
|
|
994
|
+
shownan: bool=True,
|
|
995
|
+
dpi: int=800,
|
|
996
|
+
# specific parameters
|
|
997
|
+
hue: str=None,
|
|
998
|
+
palette: str='vlag',
|
|
999
|
+
kind: Literal['auto', 'hist', 'kde', None] = 'kde',
|
|
1000
|
+
height: int=4
|
|
1001
|
+
):
|
|
1002
|
+
"""
|
|
1003
|
+
Entrance to call pairplot in python console
|
|
1004
|
+
|
|
1005
|
+
:param data: object CraceResults that must be provided.
|
|
1006
|
+
:param options: object CplotOptions that must be provided.
|
|
1007
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
1008
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]='all'
|
|
1009
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
1010
|
+
:param hue: A string of parameter name selected for plotting.
|
|
1011
|
+
:param shownan: Boolean used to plot including/excluding missing values.
|
|
1012
|
+
:param palette: A string of palatte name for plotting.
|
|
1013
|
+
:param kind: A string from provided values for the type/shape of plots.
|
|
1014
|
+
"""
|
|
1015
|
+
|
|
1016
|
+
kwargs = locals()
|
|
1017
|
+
plot_parameters(method='pair', **kwargs)
|
|
1018
|
+
|
|
1019
|
+
@enforce_types
|
|
1020
|
+
@register_param(['pairplot', 'pair'])
|
|
1021
|
+
def _pair_plot(
|
|
1022
|
+
# required parameters
|
|
1023
|
+
data: CraceResults=None,
|
|
1024
|
+
options: CplotOptions=None,
|
|
1025
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1026
|
+
parameters: Union[list[str], str, None]=None,
|
|
1027
|
+
slice: bool=True,
|
|
1028
|
+
_console: bool=True,
|
|
1029
|
+
# optional parameters
|
|
1030
|
+
shownan: bool=True,
|
|
1031
|
+
dpi: int=800,
|
|
1032
|
+
# specific parameters
|
|
1033
|
+
hue: str=None,
|
|
1034
|
+
palette: str='deep',
|
|
1035
|
+
kind: Literal['auto', 'hist', 'kde'] = 'kde',
|
|
1036
|
+
height: int=4
|
|
1037
|
+
):
|
|
1038
|
+
"""drawing pair plot"""
|
|
1039
|
+
|
|
1040
|
+
try:
|
|
1041
|
+
import seaborn as sns
|
|
1042
|
+
import matplotlib.pyplot as plt
|
|
1043
|
+
except ImportError as e:
|
|
1044
|
+
raise e
|
|
1045
|
+
|
|
1046
|
+
if isinstance(parameters, str):
|
|
1047
|
+
parameters = [parameters]
|
|
1048
|
+
|
|
1049
|
+
args = SimpleNamespace(
|
|
1050
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(parameters),
|
|
1051
|
+
sel_kvar=hue, slice=slice,
|
|
1052
|
+
out_dir=None, file_name=None, tile=None,
|
|
1053
|
+
cat=False, console=_console,
|
|
1054
|
+
configs=configs,
|
|
1055
|
+
# optional parameters
|
|
1056
|
+
showscale=False, shownan=shownan,
|
|
1057
|
+
dpi=dpi, nbins=5
|
|
1058
|
+
)
|
|
1059
|
+
|
|
1060
|
+
new_data, _, _ = _resolve_input(name='pair', args=args)
|
|
1061
|
+
|
|
1062
|
+
init_plot_style(size=1.2)
|
|
1063
|
+
|
|
1064
|
+
import warnings
|
|
1065
|
+
warnings.filterwarnings("ignore", message="Ignoring `palette` because no `hue` variable has been assigned.")
|
|
1066
|
+
|
|
1067
|
+
levels = new_data[hue].unique()
|
|
1068
|
+
# auto canonicalize palette
|
|
1069
|
+
palette_dict = dict(zip(levels, sns.color_palette(palette, n_colors=len(levels))))
|
|
1070
|
+
# enforce categorical
|
|
1071
|
+
new_data[hue] = pd.Categorical(new_data[hue], categories=list(palette_dict.keys()))
|
|
1072
|
+
|
|
1073
|
+
fig = sns.pairplot(data=new_data,
|
|
1074
|
+
hue=hue,
|
|
1075
|
+
vars=parameters,
|
|
1076
|
+
palette=palette_dict,
|
|
1077
|
+
diag_kind=kind,
|
|
1078
|
+
height=height,
|
|
1079
|
+
dropna=not(shownan),)
|
|
1080
|
+
|
|
1081
|
+
# remove legend from pariplot
|
|
1082
|
+
if hasattr(fig, "_legend") and fig._legend is not None:
|
|
1083
|
+
fig._legend.remove()
|
|
1084
|
+
|
|
1085
|
+
# add legend
|
|
1086
|
+
# especially for the case: no
|
|
1087
|
+
import matplotlib.patches as mpatches
|
|
1088
|
+
handles = [mpatches.Patch(color=palette_dict[lvl], label=lvl) for lvl in palette_dict]
|
|
1089
|
+
fig._legend = fig.fig.legend(handles=handles, title=hue, loc='center right')
|
|
1090
|
+
fig._legend.get_frame().set_visible(False)
|
|
1091
|
+
|
|
1092
|
+
if not _console:
|
|
1093
|
+
fig.savefig(f"{args.out_dir}/{args.file_name}.png", dpi=args.dpi)
|
|
1094
|
+
print("# {} has been saved in {}.".format(args.file_name, args.out_dir))
|
|
1095
|
+
plt.show()
|
|
1096
|
+
|
|
1097
|
+
@export
|
|
1098
|
+
@enforce_types
|
|
1099
|
+
def param_heatmap(
|
|
1100
|
+
# required parameters
|
|
1101
|
+
data: CraceResults=None,
|
|
1102
|
+
options: CplotOptions=None,
|
|
1103
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1104
|
+
parameters: Union[list[str], str, None]=None,
|
|
1105
|
+
_console: bool=True,
|
|
1106
|
+
# optional parameters
|
|
1107
|
+
shownan: bool=True,
|
|
1108
|
+
nbins: int=5,
|
|
1109
|
+
dpi: int=800,
|
|
1110
|
+
# specific parameters
|
|
1111
|
+
colormap: Optional[Union[str, list, Colormap]] = 'PuBu',
|
|
1112
|
+
fmt: str='g',
|
|
1113
|
+
):
|
|
1114
|
+
"""
|
|
1115
|
+
Entrance to call heatmap in python console
|
|
1116
|
+
|
|
1117
|
+
:param data: object CraceResults that must be provided.
|
|
1118
|
+
:param options: object CplotOptions that must be provided.
|
|
1119
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
1120
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]='all'
|
|
1121
|
+
:param parameters: a list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
1122
|
+
:param shownan: boolean used to plot including/excluding missing values.
|
|
1123
|
+
:param colormap: a string of matplotlib colormap name for plotting.
|
|
1124
|
+
:param nbins: integer used to split the domain for continouos paramters
|
|
1125
|
+
"""
|
|
1126
|
+
kwargs = locals()
|
|
1127
|
+
plot_parameters(method='heat', **kwargs)
|
|
1128
|
+
|
|
1129
|
+
@enforce_types
|
|
1130
|
+
@register_param(['heatmap', 'heat'])
|
|
1131
|
+
def _heatmap(
|
|
1132
|
+
# required parameters
|
|
1133
|
+
data: CraceResults=None,
|
|
1134
|
+
options: CplotOptions=None,
|
|
1135
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1136
|
+
parameters: Union[list[str], str, None]=None,
|
|
1137
|
+
_console: bool=True,
|
|
1138
|
+
# optional parameters
|
|
1139
|
+
shownan: bool=True,
|
|
1140
|
+
nbins: int=5,
|
|
1141
|
+
dpi: int=800,
|
|
1142
|
+
# specific parameters
|
|
1143
|
+
colormap: Optional[Union[str, list, Colormap]] = 'PuBu',
|
|
1144
|
+
fmt: str='g',
|
|
1145
|
+
):
|
|
1146
|
+
|
|
1147
|
+
try:
|
|
1148
|
+
import seaborn as sns
|
|
1149
|
+
import matplotlib.pyplot as plt
|
|
1150
|
+
except ImportError as e:
|
|
1151
|
+
raise e
|
|
1152
|
+
|
|
1153
|
+
if isinstance(parameters, str):
|
|
1154
|
+
parameters = [parameters]
|
|
1155
|
+
|
|
1156
|
+
args = SimpleNamespace(
|
|
1157
|
+
data=safe_copy(data), options=safe_copy(options),
|
|
1158
|
+
sel_vars=safe_copy(parameters),
|
|
1159
|
+
sel_kvar=None, slice=True,
|
|
1160
|
+
out_dir=None, file_name=None, tile=None,
|
|
1161
|
+
cat=True, console=_console,
|
|
1162
|
+
configs=configs,
|
|
1163
|
+
# optional parameters
|
|
1164
|
+
showscale=False, shownan=shownan,
|
|
1165
|
+
dpi=dpi, nbins=nbins,
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
new_data, _, new_vars = _resolve_input(name='heat', args=args)
|
|
1169
|
+
param_names = [x for x in new_vars.keys() if x not in exclude_cols]
|
|
1170
|
+
|
|
1171
|
+
if len(param_names) == 1:
|
|
1172
|
+
index='slice_sampled'
|
|
1173
|
+
columns=param_names[0]
|
|
1174
|
+
else:
|
|
1175
|
+
index=param_names[0]
|
|
1176
|
+
columns=param_names[1]
|
|
1177
|
+
|
|
1178
|
+
pivot_table = new_data.pivot_table(index=index, columns=columns, values='configuration_id', aggfunc='count')
|
|
1179
|
+
|
|
1180
|
+
if pivot_table.empty:
|
|
1181
|
+
raise CE.CplotError(f"The selected two parameters are mutually exclusive, "
|
|
1182
|
+
f"with no overlapping value combinations.")
|
|
1183
|
+
|
|
1184
|
+
init_plot_style()
|
|
1185
|
+
|
|
1186
|
+
fig = sns.heatmap(pivot_table, annot=True, cmap=colormap, fmt=fmt)
|
|
1187
|
+
|
|
1188
|
+
# y_name, x_name = index, columns
|
|
1189
|
+
for name in param_names:
|
|
1190
|
+
|
|
1191
|
+
if name == columns:
|
|
1192
|
+
cols = pivot_table.columns
|
|
1193
|
+
fig.set_xticklabels(new_vars[name]['text'])
|
|
1194
|
+
else:
|
|
1195
|
+
rows = pivot_table.index
|
|
1196
|
+
fig.set_yticklabels(new_vars[name]['text'])
|
|
1197
|
+
|
|
1198
|
+
# if not _console:
|
|
1199
|
+
# fig.savefig(f"{args.out_dir}/{args.file_name}.png", dpi=args.dpi)
|
|
1200
|
+
# print("# {} has been saved in {}.".format(args.file_name, args.out_dir))
|
|
1201
|
+
plt.show()
|
|
1202
|
+
|
|
1203
|
+
@export
|
|
1204
|
+
@enforce_types
|
|
1205
|
+
def param_jointplot(
|
|
1206
|
+
# required parameters
|
|
1207
|
+
data: CraceResults=None,
|
|
1208
|
+
options: CplotOptions=None,
|
|
1209
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1210
|
+
parameters: Union[list[str], str, None]=None,
|
|
1211
|
+
slice: bool=True,
|
|
1212
|
+
_console: bool=True,
|
|
1213
|
+
# optional parameters
|
|
1214
|
+
shownan: bool=True,
|
|
1215
|
+
nbins: int=5,
|
|
1216
|
+
dpi: int=800,
|
|
1217
|
+
# specific parameters
|
|
1218
|
+
kind: Literal['scatter', 'kde', 'hist', 'hex', 'reg', 'resid']='hist',
|
|
1219
|
+
space: float=0.1,
|
|
1220
|
+
ratio: int=4,
|
|
1221
|
+
palette: str='vlag',
|
|
1222
|
+
hue: str=None,
|
|
1223
|
+
height: int=5,
|
|
1224
|
+
):
|
|
1225
|
+
"""
|
|
1226
|
+
Entrance to call pairplot in python console
|
|
1227
|
+
|
|
1228
|
+
:param data: object CraceResults that must be provided.
|
|
1229
|
+
:param options: object CplotOptions that must be provided.
|
|
1230
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
1231
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]='all'
|
|
1232
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
1233
|
+
:param hue: A string of parameter name selected for plotting.
|
|
1234
|
+
:param shownan: Boolean used to plot including/excluding missing values.
|
|
1235
|
+
:param palette: A string of palatte name for plotting.
|
|
1236
|
+
:param kind: A string from provided values for the type/shape of plots.
|
|
1237
|
+
| Literal['scatter', 'kde', 'hist', 'hex', 'reg', 'resid']='hist'
|
|
1238
|
+
"""
|
|
1239
|
+
|
|
1240
|
+
kwargs = locals()
|
|
1241
|
+
plot_parameters(method='joint', **kwargs)
|
|
1242
|
+
|
|
1243
|
+
@enforce_types
|
|
1244
|
+
@register_param(['jointplot', 'joint'])
|
|
1245
|
+
def _jointplot(
|
|
1246
|
+
# required parameters
|
|
1247
|
+
data: CraceResults=None,
|
|
1248
|
+
options: CplotOptions=None,
|
|
1249
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1250
|
+
parameters: Union[list[str], str, None]=None,
|
|
1251
|
+
slice: bool=True,
|
|
1252
|
+
_console: bool=True,
|
|
1253
|
+
# optional parameters
|
|
1254
|
+
shownan: bool=True,
|
|
1255
|
+
nbins: int=5,
|
|
1256
|
+
dpi: int=800,
|
|
1257
|
+
# specific parameters
|
|
1258
|
+
kind: Literal['scatter', 'kde', 'hist', 'hex', 'reg', 'resid']='hist',
|
|
1259
|
+
space: float=0.1,
|
|
1260
|
+
ratio: int=4,
|
|
1261
|
+
palette: str='vlag',
|
|
1262
|
+
hue: str=None,
|
|
1263
|
+
height: int=5,
|
|
1264
|
+
):
|
|
1265
|
+
"""drawing joint plot"""
|
|
1266
|
+
|
|
1267
|
+
try:
|
|
1268
|
+
import seaborn as sns
|
|
1269
|
+
import matplotlib.pyplot as plt
|
|
1270
|
+
except ImportError as e:
|
|
1271
|
+
raise e
|
|
1272
|
+
|
|
1273
|
+
if isinstance(parameters, str):
|
|
1274
|
+
parameters = [parameters]
|
|
1275
|
+
|
|
1276
|
+
args = SimpleNamespace(
|
|
1277
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(parameters),
|
|
1278
|
+
sel_kvar=hue, slice=slice,
|
|
1279
|
+
out_dir=None, file_name=None, tile=None,
|
|
1280
|
+
cat=False, console=_console,
|
|
1281
|
+
configs=configs,
|
|
1282
|
+
# optional parameters
|
|
1283
|
+
showscale=False, shownan=shownan,
|
|
1284
|
+
dpi=dpi, nbins=nbins,
|
|
1285
|
+
)
|
|
1286
|
+
|
|
1287
|
+
new_data, _, new_vars = _resolve_input(name='joint', args=args)
|
|
1288
|
+
param_names = args.sel_vars
|
|
1289
|
+
|
|
1290
|
+
x=param_names[0]
|
|
1291
|
+
y=param_names[1]
|
|
1292
|
+
|
|
1293
|
+
init_plot_style()
|
|
1294
|
+
|
|
1295
|
+
fig = sns.jointplot(data=new_data, x=x, y=y, hue=hue,
|
|
1296
|
+
kind=kind, space=space, ratio=ratio,
|
|
1297
|
+
palette=palette, height=height)
|
|
1298
|
+
|
|
1299
|
+
xmin, xmax = new_vars[x]['domain']
|
|
1300
|
+
ymin, ymax = new_vars[y]['domain']
|
|
1301
|
+
fig.ax_joint.set_xlim(xmin, xmax)
|
|
1302
|
+
fig.ax_joint.set_ylim(ymin, ymax)
|
|
1303
|
+
fig.ax_marg_x.set_xlim(xmin, xmax)
|
|
1304
|
+
fig.ax_marg_y.set_ylim(ymin, ymax)
|
|
1305
|
+
|
|
1306
|
+
# if not _console:
|
|
1307
|
+
# fig.savefig(f"{args.out_dir}/{args.file_name}.png", dpi=args.dpi)
|
|
1308
|
+
# print("# {} has been saved in {}.".format(args.file_name, args.out_dir))
|
|
1309
|
+
plt.show()
|
|
1310
|
+
|
|
1311
|
+
@export
|
|
1312
|
+
@enforce_types
|
|
1313
|
+
def param_histplot(
|
|
1314
|
+
# required parameters
|
|
1315
|
+
data: CraceResults=None,
|
|
1316
|
+
options: CplotOptions=None,
|
|
1317
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1318
|
+
parameters: Union[list[str], str, None]=None,
|
|
1319
|
+
slice: bool=False,
|
|
1320
|
+
_console: bool=True,
|
|
1321
|
+
# optional parameters
|
|
1322
|
+
shownan: bool=True,
|
|
1323
|
+
nbins: int=5,
|
|
1324
|
+
dpi: int=1600,
|
|
1325
|
+
# specific parameters
|
|
1326
|
+
stat: Literal['count', 'frequency', 'probability', 'percent', 'density']='percent',
|
|
1327
|
+
density: bool=False,
|
|
1328
|
+
sharex: bool=False,
|
|
1329
|
+
sharey: bool=True,
|
|
1330
|
+
):
|
|
1331
|
+
"""
|
|
1332
|
+
Entrance to call histplot in python console
|
|
1333
|
+
|
|
1334
|
+
:param data: object CraceResults that must be provided.
|
|
1335
|
+
:param options: object CplotOptions that must be provided.
|
|
1336
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
1337
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]
|
|
1338
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
1339
|
+
:param slice: A boolean value used to enable/disable mapping plot aspects to different slices.
|
|
1340
|
+
:param shownan: A boolean value used to plot including/excluding missing values.
|
|
1341
|
+
:param stat: A string from provided values for the type/shape of plots.
|
|
1342
|
+
| Literal['count', 'frequency', 'probability', 'percent', 'density']='percent'
|
|
1343
|
+
:param density: A boolean value used to enable/disable plotting the rugplot in addition.
|
|
1344
|
+
:param sharex: A boolean value used to enable/disable sharing x axis when plotting.
|
|
1345
|
+
:param sharey: A boolean value used to enable/disable sharing y axis when plotting.
|
|
1346
|
+
"""
|
|
1347
|
+
|
|
1348
|
+
kwargs = locals()
|
|
1349
|
+
plot_parameters(method='hist', **kwargs)
|
|
1350
|
+
|
|
1351
|
+
@enforce_types
|
|
1352
|
+
@register_param(['histplot', 'hist'])
|
|
1353
|
+
def _histplot(
|
|
1354
|
+
# required parameters
|
|
1355
|
+
data: CraceResults=None,
|
|
1356
|
+
options: CplotOptions=None,
|
|
1357
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1358
|
+
parameters: Union[list[str], str, None]=None,
|
|
1359
|
+
slice: bool=False,
|
|
1360
|
+
_console: bool=True,
|
|
1361
|
+
# optional parameters
|
|
1362
|
+
shownan: bool=False,
|
|
1363
|
+
nbins: int=5,
|
|
1364
|
+
dpi: int=1600,
|
|
1365
|
+
# specific parameters
|
|
1366
|
+
stat: Literal['count', 'frequency', 'probability', 'percent', 'density']='percent',
|
|
1367
|
+
density: bool=False,
|
|
1368
|
+
sharex: bool=False,
|
|
1369
|
+
sharey: bool=True,
|
|
1370
|
+
):
|
|
1371
|
+
|
|
1372
|
+
try:
|
|
1373
|
+
import seaborn as sns
|
|
1374
|
+
import matplotlib.pyplot as plt
|
|
1375
|
+
except ImportError as e:
|
|
1376
|
+
raise e
|
|
1377
|
+
|
|
1378
|
+
if isinstance(parameters, str):
|
|
1379
|
+
parameters = [parameters]
|
|
1380
|
+
|
|
1381
|
+
args = SimpleNamespace(
|
|
1382
|
+
data=safe_copy(data), options=safe_copy(options),
|
|
1383
|
+
configs=configs,
|
|
1384
|
+
sel_vars=safe_copy(parameters), sel_kvar=None,
|
|
1385
|
+
out_dir=None, file_name=None, tile=None,
|
|
1386
|
+
slice=slice, cat=False, console=_console,
|
|
1387
|
+
# optional parameters
|
|
1388
|
+
showscale=False, shownan=shownan,
|
|
1389
|
+
dpi=dpi, nbins=nbins,
|
|
1390
|
+
)
|
|
1391
|
+
|
|
1392
|
+
new_data, src_vars, new_vars = _resolve_input(name='hist', args=args)
|
|
1393
|
+
param_names = [x for x in new_vars.keys() if x not in exclude_cols]
|
|
1394
|
+
|
|
1395
|
+
if args.slice:
|
|
1396
|
+
init_plot_style(size=1.1)
|
|
1397
|
+
|
|
1398
|
+
page_num = len(param_names)
|
|
1399
|
+
file_names = locals()
|
|
1400
|
+
for i in range(0, page_num):
|
|
1401
|
+
file_names['plot%s' % i] = args.file_name.split('.')[0]+str(i) if args.file_name else str(i)
|
|
1402
|
+
name = param_names[i]
|
|
1403
|
+
max_slice = max(new_data['slice_sampled'])
|
|
1404
|
+
fig, axis = plt.subplots(max_slice, 1, sharey=True, sharex=True, figsize=(max_slice/1.2, max_slice/1.2))
|
|
1405
|
+
|
|
1406
|
+
for j in range(1, max_slice+1):
|
|
1407
|
+
ax = axis[j-1]
|
|
1408
|
+
kde = False
|
|
1409
|
+
if src_vars[name]['type'] != 'c':
|
|
1410
|
+
kde=True
|
|
1411
|
+
|
|
1412
|
+
# statstr
|
|
1413
|
+
# Aggregate statistic to compute in each bin.
|
|
1414
|
+
# count: show the number of observations in each bin
|
|
1415
|
+
# frequency: show the number of observations divided by the bin width
|
|
1416
|
+
# probability or proportion: normalize such that bar heights sum to 1
|
|
1417
|
+
# percent: normalize such that bar heights sum to 100
|
|
1418
|
+
# density: normalize such that the total area of the histogram equals 1
|
|
1419
|
+
|
|
1420
|
+
fig = sns.histplot(data=new_data[new_data['slice_sampled'] == j].sort_values(by=name, na_position='last', ascending=True),
|
|
1421
|
+
x=name, stat=stat, kde=kde, ax=ax)
|
|
1422
|
+
if kde and density:
|
|
1423
|
+
fig = sns.rugplot(data=new_data[new_data['slice_sampled'] == j].sort_values(by=name, na_position='last', ascending=True),
|
|
1424
|
+
linewidth=1.0, height=0.1, x=name, ax=ax)
|
|
1425
|
+
|
|
1426
|
+
ax.set_ylabel(f' {j}', rotation=0)
|
|
1427
|
+
ax.yaxis.set_label_position('right')
|
|
1428
|
+
|
|
1429
|
+
fig.text(-0.07, 0.5*max_slice, stat, horizontalalignment='left', verticalalignment='baseline', rotation='vertical', transform=ax.transAxes)
|
|
1430
|
+
fig.text(1.05, 0.5*max_slice, 'slice', horizontalalignment='right', verticalalignment='baseline', rotation='vertical', transform=ax.transAxes)
|
|
1431
|
+
|
|
1432
|
+
# plot = fig.get_figure()
|
|
1433
|
+
# file_name = file_names['plot%s' % i]
|
|
1434
|
+
# save_name = f"{args.out_dir}/{file_name}.png"
|
|
1435
|
+
# if not _console:
|
|
1436
|
+
# plt.suptitle(args.tile, size=10)
|
|
1437
|
+
# plot.savefig(save_name, dpi=args.dpi)
|
|
1438
|
+
# print("# {} has been saved in {}.".format(file_name, args.out_dir))
|
|
1439
|
+
plt.show()
|
|
1440
|
+
|
|
1441
|
+
else:
|
|
1442
|
+
init_plot_style(size=1.3)
|
|
1443
|
+
|
|
1444
|
+
num = 8
|
|
1445
|
+
page_num = math.ceil(len(param_names)/num)
|
|
1446
|
+
params = locals()
|
|
1447
|
+
file_names = locals()
|
|
1448
|
+
start = 0
|
|
1449
|
+
for i in range(0, page_num):
|
|
1450
|
+
fig, axis = plt.subplots(2, 4, sharey=sharey, sharex=sharex, figsize=(16, 12))
|
|
1451
|
+
plt.subplots_adjust(hspace=0.3, wspace=0.25, bottom=0.2)
|
|
1452
|
+
# title = '\nPage ' + str(i+1) + ' of ' + str(page_num)
|
|
1453
|
+
|
|
1454
|
+
if start+num-1 <= len(param_names):
|
|
1455
|
+
params['params%s' % i] = param_names[start:start+num]
|
|
1456
|
+
else:
|
|
1457
|
+
params['params%s' % i] = param_names[start:]
|
|
1458
|
+
start = start+num
|
|
1459
|
+
file_names['plot%s' % i] = args.file_name.split('.')[0]+str(i) if args.file_name else str(i)
|
|
1460
|
+
|
|
1461
|
+
page_plots = min(num, len(params['params%s' % i]))
|
|
1462
|
+
|
|
1463
|
+
row = column = idx = 0
|
|
1464
|
+
for idx in range(num):
|
|
1465
|
+
ax = axis[row, column]
|
|
1466
|
+
if idx < page_plots:
|
|
1467
|
+
name = params['params%s' % i][idx]
|
|
1468
|
+
kde = False
|
|
1469
|
+
if src_vars[name]['type'] != 'c':
|
|
1470
|
+
kde = True
|
|
1471
|
+
|
|
1472
|
+
fig = sns.histplot(data=new_data.sort_values(by=name, na_position='last', ascending=True),
|
|
1473
|
+
x=name, stat=stat, kde=kde, ax=ax)
|
|
1474
|
+
if kde and density:
|
|
1475
|
+
fig = sns.rugplot(data=new_data.sort_values(by=name, na_position='last', ascending=True),
|
|
1476
|
+
linewidth=0.5, height=0.05, x=name, ax=ax)
|
|
1477
|
+
|
|
1478
|
+
if len(name) > 25:
|
|
1479
|
+
name = re.sub(r"(.{25})", "\\1\n", name)
|
|
1480
|
+
if column != 0:
|
|
1481
|
+
fig.set_ylabel('')
|
|
1482
|
+
fig.set_xlabel('\n'+name, rotation=0)
|
|
1483
|
+
else:
|
|
1484
|
+
ax.axis('off')
|
|
1485
|
+
|
|
1486
|
+
if column < 3:
|
|
1487
|
+
column += 1
|
|
1488
|
+
else:
|
|
1489
|
+
column = 0
|
|
1490
|
+
row += 1
|
|
1491
|
+
|
|
1492
|
+
# plot = fig.get_figure()
|
|
1493
|
+
# file_name = file_names['plot%s' % i]
|
|
1494
|
+
# save_name = f"{args.out_dir}/{file_name}.png"
|
|
1495
|
+
|
|
1496
|
+
# if not _console:
|
|
1497
|
+
# plot.savefig(save_name, dpi=args.dpi)
|
|
1498
|
+
# print("# {} has been saved in {}.".format(file_name, args.out_dir))
|
|
1499
|
+
plt.show()
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
@export
|
|
1503
|
+
@enforce_types
|
|
1504
|
+
def param_boxplot(
|
|
1505
|
+
# required parameters
|
|
1506
|
+
data: CraceResults=None,
|
|
1507
|
+
options: CplotOptions=None,
|
|
1508
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1509
|
+
parameters: Union[list[str], str, None]=None,
|
|
1510
|
+
_console: bool=True,
|
|
1511
|
+
# optional parameters
|
|
1512
|
+
shownan: bool=True,
|
|
1513
|
+
nbins: int=5,
|
|
1514
|
+
showfliers: bool=False,
|
|
1515
|
+
showmeans: bool=False,
|
|
1516
|
+
dpi: int=800,
|
|
1517
|
+
# specific parameters
|
|
1518
|
+
y: str='slice_sampled',
|
|
1519
|
+
palette: str='vlag',
|
|
1520
|
+
fliersize: float=.5,
|
|
1521
|
+
monochrome: bool=True,
|
|
1522
|
+
):
|
|
1523
|
+
"""
|
|
1524
|
+
Entrance to call boxplot in python console
|
|
1525
|
+
|
|
1526
|
+
:param data: object CraceResults that must be provided.
|
|
1527
|
+
:param options: object CplotOptions that must be provided.
|
|
1528
|
+
:param configs: Optional. Selected configurations for plotting, higher priority than option numConfigurations/selConfigurations.
|
|
1529
|
+
| Union[Literal['all', 'final', 'elites'], list[int], None]
|
|
1530
|
+
:param parameters: A list of parameter names selected for plotting, higher priority than option multiParameters.
|
|
1531
|
+
:param y: A string of parameter name used to map value aspects.
|
|
1532
|
+
| str='slice_sampled'
|
|
1533
|
+
:param shownan: A boolean value used to plot including/excluding missing values.
|
|
1534
|
+
:param showfliers: A boolean value used to plot including/excluding outliers.
|
|
1535
|
+
:param showmeans: A boolean value used to plot including/excluding mean values.
|
|
1536
|
+
:param palette: A string of palatte name for plotting.
|
|
1537
|
+
:param monochrome: A boolean value used to enable/disable coloring the plot.
|
|
1538
|
+
"""
|
|
1539
|
+
kwargs = locals()
|
|
1540
|
+
plot_parameters(method='box', **kwargs)
|
|
1541
|
+
|
|
1542
|
+
@enforce_types
|
|
1543
|
+
@register_param(['boxplot', 'box'])
|
|
1544
|
+
def _boxplot(
|
|
1545
|
+
# required parameters
|
|
1546
|
+
data: CraceResults=None,
|
|
1547
|
+
options: CplotOptions=None,
|
|
1548
|
+
configs: Union[Literal['all', 'final', 'elites'], list[int], None]='all',
|
|
1549
|
+
parameters: Union[list[str], str, None]=None,
|
|
1550
|
+
_console: bool=True,
|
|
1551
|
+
# optional parameters
|
|
1552
|
+
shownan: bool=True,
|
|
1553
|
+
nbins: int=5,
|
|
1554
|
+
showfliers: bool=False,
|
|
1555
|
+
showmeans: bool=False,
|
|
1556
|
+
dpi: int=800,
|
|
1557
|
+
# specific parameters
|
|
1558
|
+
y: str='slice_sampled',
|
|
1559
|
+
palette: str='vlag',
|
|
1560
|
+
fliersize: float=.5,
|
|
1561
|
+
monochrome: bool=True,
|
|
1562
|
+
):
|
|
1563
|
+
"""drawing box plot"""
|
|
1564
|
+
|
|
1565
|
+
try:
|
|
1566
|
+
import matplotlib.pyplot as plt
|
|
1567
|
+
except ImportError as e:
|
|
1568
|
+
raise e
|
|
1569
|
+
|
|
1570
|
+
if isinstance(parameters, str):
|
|
1571
|
+
parameters = [parameters]
|
|
1572
|
+
|
|
1573
|
+
args = SimpleNamespace(
|
|
1574
|
+
data=safe_copy(data), options=safe_copy(options), sel_vars=safe_copy(parameters),
|
|
1575
|
+
sel_kvar=y, slice=True,
|
|
1576
|
+
out_dir=None, file_name=None, tile=None,
|
|
1577
|
+
cat=True, console=_console,
|
|
1578
|
+
configs=configs,
|
|
1579
|
+
# optional parameters
|
|
1580
|
+
showscale=False, shownan=shownan, showfliers=showfliers, showmeans=showmeans,
|
|
1581
|
+
dpi=dpi, nbins=nbins,
|
|
1582
|
+
)
|
|
1583
|
+
|
|
1584
|
+
new_data, _, new_vars = _resolve_input(name='box', args=args)
|
|
1585
|
+
param_names = args.sel_vars
|
|
1586
|
+
|
|
1587
|
+
init_plot_style()
|
|
1588
|
+
|
|
1589
|
+
if len(param_names) >= 6:
|
|
1590
|
+
num = 6
|
|
1591
|
+
page_num = math.ceil(len(param_names)/num)
|
|
1592
|
+
params = locals()
|
|
1593
|
+
file_names = locals()
|
|
1594
|
+
start = 0
|
|
1595
|
+
for i in range(0, page_num):
|
|
1596
|
+
fig, axis = plt.subplots(2, 3, sharey=False, sharex=False)
|
|
1597
|
+
plt.subplots_adjust(hspace=0.5, wspace=0.4, bottom=0.2)
|
|
1598
|
+
# title = '\nPage ' + str(i+1) + ' of ' + str(page_num)
|
|
1599
|
+
|
|
1600
|
+
if start+num-1 <= len(param_names):
|
|
1601
|
+
params['params%s' % i] = param_names[start:start+num]
|
|
1602
|
+
else:
|
|
1603
|
+
params['params%s' % i] = param_names[start:]
|
|
1604
|
+
start = start+num
|
|
1605
|
+
file_names['plot%s' % i] = args.file_name.split('.')[0]+str(i) if args.file_name else str(i)
|
|
1606
|
+
|
|
1607
|
+
page_plots = min(num, len(params['params%s' % i]))
|
|
1608
|
+
|
|
1609
|
+
row = column = idx = 0
|
|
1610
|
+
for idx in range(num):
|
|
1611
|
+
ax = axis[row, column]
|
|
1612
|
+
if idx < page_plots:
|
|
1613
|
+
name = params['params%s' % i][idx]
|
|
1614
|
+
if new_vars[name]['type'] != 'c':
|
|
1615
|
+
fig = _sns_boxplot(data=new_data, x=name, y=y, hue=y, ax=ax,
|
|
1616
|
+
fliersize=fliersize, palette=palette, monochrome=monochrome, args=args)
|
|
1617
|
+
|
|
1618
|
+
if len(name) > 25:
|
|
1619
|
+
name = re.sub(r"(.{25})", "\\1\n", name)
|
|
1620
|
+
if column != 0:
|
|
1621
|
+
fig.set_ylabel('')
|
|
1622
|
+
fig.set_xlabel('\n'+name, rotation=0)
|
|
1623
|
+
|
|
1624
|
+
else:
|
|
1625
|
+
_barh_plot(data=new_data, x=name, y=y, fliersize=fliersize, palette=palette, ax=ax, monochrome=monochrome)
|
|
1626
|
+
|
|
1627
|
+
if len(name) > 25:
|
|
1628
|
+
name = re.sub(r"(.{25})", "\\1\n", name)
|
|
1629
|
+
if column != 0:
|
|
1630
|
+
ax.set_ylabel('')
|
|
1631
|
+
else:
|
|
1632
|
+
ax.set_ylabel(y, rotation=90)
|
|
1633
|
+
ax.set_xlabel('\n'+name, rotation=0)
|
|
1634
|
+
|
|
1635
|
+
else:
|
|
1636
|
+
ax.axis('off')
|
|
1637
|
+
|
|
1638
|
+
if column < 2:
|
|
1639
|
+
column += 1
|
|
1640
|
+
else:
|
|
1641
|
+
column = 0
|
|
1642
|
+
row += 1
|
|
1643
|
+
|
|
1644
|
+
# plot = fig.get_figure()
|
|
1645
|
+
# file_name = file_names['plot%s' % i]
|
|
1646
|
+
# save_name = f"{args.out_dir}/{file_name}.png"
|
|
1647
|
+
|
|
1648
|
+
# if not _console:
|
|
1649
|
+
# plt.suptitle(args.tile, size=15)
|
|
1650
|
+
# plot.savefig(save_name, dpi=args.dpi)
|
|
1651
|
+
# print("# {} has been saved in {}.".format(file_name, args.out_dir))
|
|
1652
|
+
plt.show()
|
|
1653
|
+
|
|
1654
|
+
else:
|
|
1655
|
+
page_num = len(param_names)
|
|
1656
|
+
file_names = locals()
|
|
1657
|
+
start = 0
|
|
1658
|
+
for i in range(0, page_num):
|
|
1659
|
+
plt.clf()
|
|
1660
|
+
ax = plt.gca()
|
|
1661
|
+
|
|
1662
|
+
# title = '\nPage ' + str(i+1) + ' of ' + str(page_num)
|
|
1663
|
+
# file_names['plot%s' % i] = args.file_name.split('.')[0]+'-'+param_names[i] if args.file_name else str(param_names[i])
|
|
1664
|
+
name = param_names[i]
|
|
1665
|
+
|
|
1666
|
+
if new_vars[name]['type'] != 'c':
|
|
1667
|
+
fig = _sns_boxplot(data=new_data, x=name, y=y, hue=y, ax=ax, args=args,
|
|
1668
|
+
fliersize=fliersize, palette=palette, monochrome=monochrome)
|
|
1669
|
+
if len(name) > 25:
|
|
1670
|
+
name = re.sub(r"(.{25})", "\\1\n", name)
|
|
1671
|
+
fig.set_xlabel('\n'+name, rotation=0)
|
|
1672
|
+
|
|
1673
|
+
else:
|
|
1674
|
+
_barh_plot(data=new_data, x=name, y=y, fliersize=fliersize, palette=palette, ax=ax, monochrome=monochrome)
|
|
1675
|
+
|
|
1676
|
+
if len(name) > 25:
|
|
1677
|
+
name = re.sub(r"(.{25})", "\\1\n", name)
|
|
1678
|
+
ax.set_xlabel('\n'+name, rotation=0)
|
|
1679
|
+
ax.set_ylabel(y, rotation=90)
|
|
1680
|
+
|
|
1681
|
+
# plot = fig.get_figure()
|
|
1682
|
+
# file_name = file_names['plot%s' % i]
|
|
1683
|
+
# save_name = f"{args.out_dir}/{file_name}.png"
|
|
1684
|
+
|
|
1685
|
+
# if not _console:
|
|
1686
|
+
# plt.suptitle(title, size=15)
|
|
1687
|
+
# plot.savefig(save_name, dpi=args.dpi)
|
|
1688
|
+
# print("# {} has been saved in {}.".format(file_name, args.out_dir))
|
|
1689
|
+
plt.show()
|
|
1690
|
+
|
|
1691
|
+
def _sns_boxplot(data, x, y, hue, ax, fliersize, palette, monochrome, args):
|
|
1692
|
+
try:
|
|
1693
|
+
import seaborn as sns
|
|
1694
|
+
except ImportError as e:
|
|
1695
|
+
raise e
|
|
1696
|
+
|
|
1697
|
+
if monochrome:
|
|
1698
|
+
fig = sns.boxplot(data=data, x=x, y=y, hue=hue, legend=None, ax=ax,
|
|
1699
|
+
whis=0.5, showfliers=args.showfliers, fliersize=fliersize,
|
|
1700
|
+
showmeans=args.showmeans, orient='h',
|
|
1701
|
+
width=0.4, linewidth=2*fliersize,
|
|
1702
|
+
palette=palette,
|
|
1703
|
+
meanprops={"marker": "x",
|
|
1704
|
+
"markeredgecolor": "black",
|
|
1705
|
+
"markersize": 1,
|
|
1706
|
+
"linewidth": 2*fliersize},
|
|
1707
|
+
boxprops=dict(facecolor="white"),
|
|
1708
|
+
medianprops={"linewidth": 2*fliersize, "color": "black"},
|
|
1709
|
+
whiskerprops={"linestyle": "--", "linewidth": 2*fliersize},
|
|
1710
|
+
)
|
|
1711
|
+
else:
|
|
1712
|
+
fig = sns.boxplot(data=data, x=x, y=y, hue=hue, legend=None, ax=ax,
|
|
1713
|
+
whis=0.5, showfliers=args.showfliers, fliersize=fliersize,
|
|
1714
|
+
showmeans=args.showmeans, orient='h',
|
|
1715
|
+
width=0.4, linewidth=2*fliersize,
|
|
1716
|
+
palette=palette,)
|
|
1717
|
+
return fig
|
|
1718
|
+
|
|
1719
|
+
def _make_hatches(n, base=['//', '||', '--', '\\\\', '++', 'xx', '..',], max_repeat=7):
|
|
1720
|
+
hatches = []
|
|
1721
|
+
for r in range(1, max_repeat + 1):
|
|
1722
|
+
for b in base:
|
|
1723
|
+
hatches.append(b * r)
|
|
1724
|
+
if len(hatches) >= n:
|
|
1725
|
+
return hatches
|
|
1726
|
+
return hatches
|
|
1727
|
+
|
|
1728
|
+
def _barh_plot(data, x, y, ax, fliersize, palette, monochrome):
|
|
1729
|
+
"""
|
|
1730
|
+
Draw 'boxplot' for categorical parameter
|
|
1731
|
+
"""
|
|
1732
|
+
try:
|
|
1733
|
+
import seaborn as sns
|
|
1734
|
+
except ImportError as e:
|
|
1735
|
+
raise e
|
|
1736
|
+
|
|
1737
|
+
new_data = (data.groupby([y, x]).size().reset_index(name="count"))
|
|
1738
|
+
new_data["ratio"] = new_data.groupby(y)["count"].transform(lambda x: x / x.sum())
|
|
1739
|
+
|
|
1740
|
+
mat = new_data.pivot(index=y, columns=x, values="ratio").fillna(0)
|
|
1741
|
+
mat = mat.sort_index(ascending=False)
|
|
1742
|
+
|
|
1743
|
+
y_new = np.arange(len(mat))
|
|
1744
|
+
left = np.zeros(len(mat))
|
|
1745
|
+
|
|
1746
|
+
if monochrome:
|
|
1747
|
+
try:
|
|
1748
|
+
import matplotlib.patches as mpatches
|
|
1749
|
+
except ImportError as e:
|
|
1750
|
+
raise e
|
|
1751
|
+
|
|
1752
|
+
hatches = _make_hatches(len(mat.columns))
|
|
1753
|
+
handles = []
|
|
1754
|
+
|
|
1755
|
+
for i, col in enumerate(mat.columns):
|
|
1756
|
+
ax.barh(y_new, mat[col].values,
|
|
1757
|
+
left=left, height=0.4,
|
|
1758
|
+
facecolor="white",
|
|
1759
|
+
edgecolor="black",
|
|
1760
|
+
linewidth=2 * fliersize,
|
|
1761
|
+
hatch=hatches[i])
|
|
1762
|
+
|
|
1763
|
+
handles.append(
|
|
1764
|
+
mpatches.Patch(
|
|
1765
|
+
facecolor="white",
|
|
1766
|
+
edgecolor="black",
|
|
1767
|
+
hatch=hatches[i],
|
|
1768
|
+
label=str(col)
|
|
1769
|
+
)
|
|
1770
|
+
)
|
|
1771
|
+
|
|
1772
|
+
left += mat[col].values
|
|
1773
|
+
|
|
1774
|
+
ax.legend(
|
|
1775
|
+
handles=handles,
|
|
1776
|
+
title=x,
|
|
1777
|
+
bbox_to_anchor=(1.02, 0.5),
|
|
1778
|
+
loc="center left",
|
|
1779
|
+
frameon=False
|
|
1780
|
+
)
|
|
1781
|
+
|
|
1782
|
+
else:
|
|
1783
|
+
levels = list(mat.columns)
|
|
1784
|
+
palette_dict = dict(zip(levels, sns.color_palette(palette, n_colors=len(levels))))
|
|
1785
|
+
|
|
1786
|
+
for col in mat.columns:
|
|
1787
|
+
ax.barh(y_new, mat[col].values,
|
|
1788
|
+
left=left, height=0.4,
|
|
1789
|
+
facecolor=palette_dict[col],
|
|
1790
|
+
edgecolor=None,
|
|
1791
|
+
linewidth=2 * fliersize,
|
|
1792
|
+
label=str(col))
|
|
1793
|
+
|
|
1794
|
+
left += mat[col].values
|
|
1795
|
+
|
|
1796
|
+
ax.legend(
|
|
1797
|
+
title=x,
|
|
1798
|
+
bbox_to_anchor=(1.02, 0.5),
|
|
1799
|
+
loc="center left",
|
|
1800
|
+
frameon=False
|
|
1801
|
+
)
|
|
1802
|
+
|
|
1803
|
+
ax.set_xlim(0, 1)
|
|
1804
|
+
ax.set_yticks(y_new)
|
|
1805
|
+
ax.set_yticklabels(mat.index)
|