sierra-research 1.3.11__py3-none-any.whl → 1.5.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.
- sierra/__init__.py +3 -3
- sierra/core/__init__.py +3 -3
- sierra/core/batchroot.py +223 -0
- sierra/core/cmdline.py +681 -1057
- sierra/core/compare.py +11 -0
- sierra/core/config.py +96 -88
- sierra/core/engine.py +306 -0
- sierra/core/execenv.py +380 -0
- sierra/core/expdef.py +11 -0
- sierra/core/experiment/__init__.py +1 -0
- sierra/core/experiment/bindings.py +150 -101
- sierra/core/experiment/definition.py +414 -245
- sierra/core/experiment/spec.py +83 -85
- sierra/core/exproot.py +44 -0
- sierra/core/generators/__init__.py +10 -0
- sierra/core/generators/experiment.py +528 -0
- sierra/core/generators/generator_factory.py +138 -137
- sierra/core/graphs/__init__.py +23 -0
- sierra/core/graphs/bcbridge.py +94 -0
- sierra/core/graphs/heatmap.py +245 -324
- sierra/core/graphs/pathset.py +27 -0
- sierra/core/graphs/schema.py +77 -0
- sierra/core/graphs/stacked_line.py +341 -0
- sierra/core/graphs/summary_line.py +506 -0
- sierra/core/logging.py +3 -2
- sierra/core/models/__init__.py +3 -1
- sierra/core/models/info.py +19 -0
- sierra/core/models/interface.py +52 -122
- sierra/core/pipeline/__init__.py +2 -5
- sierra/core/pipeline/pipeline.py +228 -126
- sierra/core/pipeline/stage1/__init__.py +10 -0
- sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
- sierra/core/pipeline/stage2/__init__.py +10 -0
- sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
- sierra/core/pipeline/stage2/runner.py +401 -0
- sierra/core/pipeline/stage3/__init__.py +12 -0
- sierra/core/pipeline/stage3/gather.py +321 -0
- sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
- sierra/core/pipeline/stage4/__init__.py +12 -2
- sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
- sierra/core/pipeline/stage5/__init__.py +12 -0
- sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
- sierra/core/pipeline/yaml.py +48 -0
- sierra/core/plugin.py +529 -62
- sierra/core/proc.py +11 -0
- sierra/core/prod.py +11 -0
- sierra/core/ros1/__init__.py +5 -1
- sierra/core/ros1/callbacks.py +22 -21
- sierra/core/ros1/cmdline.py +59 -88
- sierra/core/ros1/generators.py +159 -175
- sierra/core/ros1/variables/__init__.py +3 -0
- sierra/core/ros1/variables/exp_setup.py +122 -116
- sierra/core/startup.py +106 -76
- sierra/core/stat_kernels.py +4 -5
- sierra/core/storage.py +13 -32
- sierra/core/trampoline.py +30 -0
- sierra/core/types.py +116 -71
- sierra/core/utils.py +103 -106
- sierra/core/variables/__init__.py +1 -1
- sierra/core/variables/base_variable.py +12 -17
- sierra/core/variables/batch_criteria.py +387 -481
- sierra/core/variables/builtin.py +135 -0
- sierra/core/variables/exp_setup.py +19 -39
- sierra/core/variables/population_size.py +72 -76
- sierra/core/variables/variable_density.py +44 -68
- sierra/core/vector.py +1 -1
- sierra/main.py +256 -88
- sierra/plugins/__init__.py +119 -0
- sierra/plugins/compare/__init__.py +14 -0
- sierra/plugins/compare/graphs/__init__.py +19 -0
- sierra/plugins/compare/graphs/cmdline.py +120 -0
- sierra/plugins/compare/graphs/comparator.py +291 -0
- sierra/plugins/compare/graphs/inter_controller.py +531 -0
- sierra/plugins/compare/graphs/inter_scenario.py +297 -0
- sierra/plugins/compare/graphs/namecalc.py +53 -0
- sierra/plugins/compare/graphs/outputroot.py +73 -0
- sierra/plugins/compare/graphs/plugin.py +147 -0
- sierra/plugins/compare/graphs/preprocess.py +172 -0
- sierra/plugins/compare/graphs/schema.py +37 -0
- sierra/plugins/engine/__init__.py +14 -0
- sierra/plugins/engine/argos/__init__.py +18 -0
- sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
- sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
- sierra/plugins/engine/argos/generators/engine.py +394 -0
- sierra/plugins/engine/argos/plugin.py +393 -0
- sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
- sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
- sierra/plugins/engine/argos/variables/cameras.py +240 -0
- sierra/plugins/engine/argos/variables/constant_density.py +112 -0
- sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
- sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
- sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
- sierra/plugins/engine/argos/variables/population_size.py +115 -0
- sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
- sierra/plugins/engine/argos/variables/rendering.py +108 -0
- sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
- sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
- sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
- sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
- sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
- sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
- sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
- sierra/plugins/engine/ros1robot/__init__.py +18 -0
- sierra/plugins/engine/ros1robot/cmdline.py +159 -0
- sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
- sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
- sierra/plugins/engine/ros1robot/plugin.py +410 -0
- sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
- sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
- sierra/plugins/execenv/__init__.py +11 -0
- sierra/plugins/execenv/hpc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
- sierra/plugins/execenv/hpc/cmdline.py +137 -0
- sierra/plugins/execenv/hpc/local/__init__.py +18 -0
- sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
- sierra/plugins/execenv/hpc/local/plugin.py +145 -0
- sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
- sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
- sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
- sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
- sierra/plugins/execenv/prefectserver/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
- sierra/plugins/execenv/prefectserver/flow.py +66 -0
- sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
- sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
- sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
- sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
- sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
- sierra/plugins/expdef/__init__.py +14 -0
- sierra/plugins/expdef/json/__init__.py +14 -0
- sierra/plugins/expdef/json/plugin.py +504 -0
- sierra/plugins/expdef/xml/__init__.py +14 -0
- sierra/plugins/expdef/xml/plugin.py +386 -0
- sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
- sierra/plugins/proc/collate/__init__.py +15 -0
- sierra/plugins/proc/collate/cmdline.py +47 -0
- sierra/plugins/proc/collate/plugin.py +271 -0
- sierra/plugins/proc/compress/__init__.py +18 -0
- sierra/plugins/proc/compress/cmdline.py +47 -0
- sierra/plugins/proc/compress/plugin.py +123 -0
- sierra/plugins/proc/decompress/__init__.py +18 -0
- sierra/plugins/proc/decompress/plugin.py +96 -0
- sierra/plugins/proc/imagize/__init__.py +15 -0
- sierra/plugins/proc/imagize/cmdline.py +49 -0
- sierra/plugins/proc/imagize/plugin.py +270 -0
- sierra/plugins/proc/modelrunner/__init__.py +16 -0
- sierra/plugins/proc/modelrunner/plugin.py +250 -0
- sierra/plugins/proc/statistics/__init__.py +15 -0
- sierra/plugins/proc/statistics/cmdline.py +64 -0
- sierra/plugins/proc/statistics/plugin.py +390 -0
- sierra/plugins/{hpc → prod}/__init__.py +1 -0
- sierra/plugins/prod/graphs/__init__.py +18 -0
- sierra/plugins/prod/graphs/cmdline.py +269 -0
- sierra/plugins/prod/graphs/collate.py +279 -0
- sierra/plugins/prod/graphs/inter/__init__.py +13 -0
- sierra/plugins/prod/graphs/inter/generate.py +83 -0
- sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
- sierra/plugins/prod/graphs/inter/line.py +134 -0
- sierra/plugins/prod/graphs/intra/__init__.py +15 -0
- sierra/plugins/prod/graphs/intra/generate.py +202 -0
- sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
- sierra/plugins/prod/graphs/intra/line.py +114 -0
- sierra/plugins/prod/graphs/plugin.py +103 -0
- sierra/plugins/prod/graphs/targets.py +63 -0
- sierra/plugins/prod/render/__init__.py +18 -0
- sierra/plugins/prod/render/cmdline.py +72 -0
- sierra/plugins/prod/render/plugin.py +282 -0
- sierra/plugins/storage/__init__.py +5 -0
- sierra/plugins/storage/arrow/__init__.py +18 -0
- sierra/plugins/storage/arrow/plugin.py +38 -0
- sierra/plugins/storage/csv/__init__.py +9 -0
- sierra/plugins/storage/csv/plugin.py +12 -5
- sierra/version.py +3 -2
- sierra_research-1.5.0.dist-info/METADATA +238 -0
- sierra_research-1.5.0.dist-info/RECORD +186 -0
- {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
- sierra/core/experiment/xml.py +0 -454
- sierra/core/generators/controller_generator_parser.py +0 -34
- sierra/core/generators/exp_creator.py +0 -351
- sierra/core/generators/exp_generators.py +0 -142
- sierra/core/graphs/scatterplot2D.py +0 -109
- sierra/core/graphs/stacked_line_graph.py +0 -251
- sierra/core/graphs/stacked_surface_graph.py +0 -220
- sierra/core/graphs/summary_line_graph.py +0 -371
- sierra/core/hpc/cmdline.py +0 -142
- sierra/core/models/graphs.py +0 -87
- sierra/core/pipeline/stage2/exp_runner.py +0 -286
- sierra/core/pipeline/stage3/imagizer.py +0 -149
- sierra/core/pipeline/stage3/run_collator.py +0 -317
- sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
- sierra/core/pipeline/stage4/graph_collator.py +0 -320
- sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
- sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
- sierra/core/pipeline/stage4/model_runner.py +0 -168
- sierra/core/pipeline/stage4/rendering.py +0 -283
- sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
- sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
- sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
- sierra/core/platform.py +0 -493
- sierra/core/plugin_manager.py +0 -369
- sierra/core/root_dirpath_generator.py +0 -241
- sierra/plugins/hpc/adhoc/plugin.py +0 -125
- sierra/plugins/hpc/local/plugin.py +0 -81
- sierra/plugins/hpc/pbs/__init__.py +0 -9
- sierra/plugins/hpc/pbs/plugin.py +0 -126
- sierra/plugins/hpc/slurm/__init__.py +0 -9
- sierra/plugins/hpc/slurm/plugin.py +0 -130
- sierra/plugins/platform/__init__.py +0 -9
- sierra/plugins/platform/argos/__init__.py +0 -9
- sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
- sierra/plugins/platform/argos/plugin.py +0 -337
- sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
- sierra/plugins/platform/argos/variables/cameras.py +0 -243
- sierra/plugins/platform/argos/variables/constant_density.py +0 -136
- sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
- sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
- sierra/plugins/platform/argos/variables/population_size.py +0 -102
- sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
- sierra/plugins/platform/argos/variables/rendering.py +0 -104
- sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
- sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
- sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
- sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
- sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
- sierra/plugins/platform/ros1robot/__init__.py +0 -9
- sierra/plugins/platform/ros1robot/cmdline.py +0 -175
- sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
- sierra/plugins/platform/ros1robot/plugin.py +0 -373
- sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
- sierra/plugins/robot/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/plugin.py +0 -194
- sierra_research-1.3.11.data/data/share/man/man1/sierra-cli.1 +0 -2349
- sierra_research-1.3.11.data/data/share/man/man7/sierra-examples.7 +0 -508
- sierra_research-1.3.11.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
- sierra_research-1.3.11.data/data/share/man/man7/sierra-glossary.7 +0 -285
- sierra_research-1.3.11.data/data/share/man/man7/sierra-platforms.7 +0 -358
- sierra_research-1.3.11.data/data/share/man/man7/sierra-usage.7 +0 -729
- sierra_research-1.3.11.data/data/share/man/man7/sierra.7 +0 -78
- sierra_research-1.3.11.dist-info/METADATA +0 -492
- sierra_research-1.3.11.dist-info/RECORD +0 -133
- sierra_research-1.3.11.dist-info/top_level.txt +0 -1
- {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
- {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
sierra/core/graphs/heatmap.py
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: MIT
|
4
4
|
#
|
5
|
+
"""
|
6
|
+
Heatmap graph generation classes for stage{4,5}.
|
7
|
+
"""
|
5
8
|
|
6
9
|
# Core packages
|
7
10
|
import textwrap
|
@@ -12,149 +15,175 @@ import pathlib
|
|
12
15
|
# 3rd party packages
|
13
16
|
import numpy as np
|
14
17
|
import matplotlib.pyplot as plt
|
15
|
-
import
|
16
|
-
import
|
18
|
+
import holoviews as hv
|
19
|
+
import bokeh
|
17
20
|
|
18
21
|
# Project packages
|
19
22
|
from sierra.core import utils, config, storage, types
|
23
|
+
from . import pathset as _pathset
|
24
|
+
|
25
|
+
_logger = logging.getLogger(__name__)
|
26
|
+
|
27
|
+
|
28
|
+
def _ofile_ext(backend: str) -> tp.Optional[str]:
|
29
|
+
if backend == "matplotlib":
|
30
|
+
return config.kStaticImageType
|
31
|
+
elif backend == "bokeh":
|
32
|
+
return config.kInteractiveImageType
|
33
|
+
|
34
|
+
return None
|
35
|
+
|
36
|
+
|
37
|
+
def generate(
|
38
|
+
pathset: _pathset.PathSet,
|
39
|
+
input_stem: str,
|
40
|
+
output_stem: str,
|
41
|
+
medium: str,
|
42
|
+
title: str,
|
43
|
+
backend: str,
|
44
|
+
colnames: tp.Tuple[str, str, str] = ("x", "y", "z"),
|
45
|
+
xlabel: tp.Optional[str] = "",
|
46
|
+
ylabel: tp.Optional[str] = "",
|
47
|
+
zlabel: tp.Optional[str] = "",
|
48
|
+
large_text: bool = False,
|
49
|
+
xticklabels: tp.Optional[tp.List[str]] = None,
|
50
|
+
yticklabels: tp.Optional[tp.List[str]] = None,
|
51
|
+
transpose: bool = False,
|
52
|
+
ext=config.kStats["mean"].exts["mean"],
|
53
|
+
) -> bool:
|
54
|
+
"""
|
55
|
+
Generate a X vs. Y vs. Z heatmap plot of a ``.mean`` file.
|
20
56
|
|
57
|
+
If the necessary ``.mean`` file does not exist, the graph is not generated.
|
58
|
+
Dataframe must be constructed with {x,y,z} columns; e.g.::
|
21
59
|
|
22
|
-
|
23
|
-
|
24
|
-
|
60
|
+
x,y,z
|
61
|
+
0,0,4
|
62
|
+
0,1,5
|
63
|
+
0,2,6
|
64
|
+
0,3,4
|
65
|
+
1,0,4
|
66
|
+
0,1,4
|
67
|
+
...
|
25
68
|
|
26
|
-
|
69
|
+
The ``x``, ``y`` columns are the indices, and the ``z`` column is the value
|
70
|
+
in that cell. The names of these columns are configurable.
|
27
71
|
|
28
72
|
"""
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
""
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
Plot X,Y ticks and their corresponding labels.
|
144
|
-
"""
|
145
|
-
ax.tick_params(labelsize=self.text_size['tick_label'])
|
146
|
-
|
147
|
-
if self.xtick_labels is not None:
|
148
|
-
ax.set_xticks(np.arange(len(self.xtick_labels)))
|
149
|
-
ax.set_xticklabels(self.xtick_labels, rotation='vertical')
|
150
|
-
|
151
|
-
if self.ytick_labels is not None:
|
152
|
-
ax.set_yticks(np.arange(len(self.ytick_labels)))
|
153
|
-
ax.set_yticklabels(self.ytick_labels)
|
154
|
-
|
155
|
-
|
156
|
-
class DualHeatmap:
|
157
|
-
"""Generates a side-by-side plot of two heataps from two CSV files.
|
73
|
+
hv.extension(backend)
|
74
|
+
|
75
|
+
input_fpath = pathset.input_root / (input_stem + ext)
|
76
|
+
output_fpath = pathset.output_root / "HM-{0}.{1}".format(
|
77
|
+
output_stem, _ofile_ext(backend)
|
78
|
+
)
|
79
|
+
if not utils.path_exists(input_fpath):
|
80
|
+
_logger.debug(
|
81
|
+
"Not generating <batchroot>/%s: <batchroot>/%s does not exist",
|
82
|
+
output_fpath.relative_to(pathset.batchroot.resolve()),
|
83
|
+
input_fpath.relative_to(pathset.batchroot.resolve()),
|
84
|
+
)
|
85
|
+
return False
|
86
|
+
|
87
|
+
title = "\n".join(textwrap.wrap(title, 40))
|
88
|
+
|
89
|
+
if large_text:
|
90
|
+
text_size = config.kGraphs["text_size_large"]
|
91
|
+
else:
|
92
|
+
text_size = config.kGraphs["text_size_small"]
|
93
|
+
|
94
|
+
# Read .csv and create raw heatmap from default configuration
|
95
|
+
df = storage.df_read(input_fpath, medium)
|
96
|
+
dataset = hv.Dataset(df, kdims=[colnames[0], colnames[1]], vdims=colnames[2])
|
97
|
+
|
98
|
+
# Transpose if requested
|
99
|
+
if transpose:
|
100
|
+
dataset.data = dataset.data.transpose()
|
101
|
+
|
102
|
+
# Plot heatmap, without showing the Z-value in each cell, which generally
|
103
|
+
# obscures things more than it helps. Plus, statistical significance isn't
|
104
|
+
# observable from a heatmap, so numerical values are kind of moot.
|
105
|
+
if backend == "matplotlib":
|
106
|
+
plot = hv.HeatMap(
|
107
|
+
dataset, kdims=[colnames[0], colnames[1]], vdims=[colnames[2]]
|
108
|
+
).opts(show_values=False)
|
109
|
+
elif backend == "bokeh":
|
110
|
+
plot = hv.HeatMap(
|
111
|
+
dataset, kdims=[colnames[0], colnames[1]], vdims=[colnames[2]]
|
112
|
+
)
|
113
|
+
|
114
|
+
xticks = dataset.data[colnames[0]]
|
115
|
+
yticks = dataset.data[colnames[1]]
|
116
|
+
|
117
|
+
# Add X,Y ticks
|
118
|
+
if xticklabels:
|
119
|
+
plot.opts(xformatter=lambda x: xticklabels[xticks.index(x)])
|
120
|
+
if yticklabels:
|
121
|
+
plot.opts(yformatter=lambda y: yticklabels[yticks.index(y)])
|
122
|
+
|
123
|
+
# Add labels
|
124
|
+
plot.opts(xlabel=xlabel)
|
125
|
+
plot.opts(ylabel=ylabel)
|
126
|
+
|
127
|
+
# Set fontsizes
|
128
|
+
plot.opts(
|
129
|
+
fontsize={
|
130
|
+
"title": text_size["title"],
|
131
|
+
"labels": text_size["xyz_label"],
|
132
|
+
"ticks": text_size["tick_label"],
|
133
|
+
}
|
134
|
+
)
|
135
|
+
|
136
|
+
# Add title
|
137
|
+
plot.opts(title=title)
|
138
|
+
|
139
|
+
if backend == "matplotlib":
|
140
|
+
# Add colorbar.
|
141
|
+
# 2025-07-08 [JRH]: backend_opts is a mpl-specific Workaround; doing
|
142
|
+
# colorbar_opts={"label": ...} doesn't work for unknown reasons.
|
143
|
+
plot.opts(colorbar=True, backend_opts={"colorbar.label": zlabel})
|
144
|
+
|
145
|
+
_save(plot, output_fpath, backend)
|
146
|
+
|
147
|
+
_logger.debug(
|
148
|
+
"Graph written to <batchroot>/%s",
|
149
|
+
output_fpath.relative_to(pathset.batchroot),
|
150
|
+
)
|
151
|
+
return True
|
152
|
+
|
153
|
+
|
154
|
+
def _save(plot: hv.Overlay, output_fpath: pathlib.Path, backend: str) -> None:
|
155
|
+
if backend == "matplotlib":
|
156
|
+
hv.save(
|
157
|
+
plot.opts(fig_inches=config.kGraphs["base_size"]),
|
158
|
+
output_fpath,
|
159
|
+
fig=config.kStaticImageType,
|
160
|
+
dpi=config.kGraphs["dpi"],
|
161
|
+
)
|
162
|
+
plt.close("all")
|
163
|
+
|
164
|
+
elif backend == "bokeh":
|
165
|
+
fig = hv.render(plot)
|
166
|
+
fig.width = int(config.kGraphs["dpi"] * config.kGraphs["base_size"])
|
167
|
+
fig.height = int(config.kGraphs["dpi"] * config.kGraphs["base_size"])
|
168
|
+
html = bokeh.embed.file_html(fig, resources=bokeh.resources.INLINE)
|
169
|
+
with open(output_fpath, "w") as f:
|
170
|
+
f.write(html)
|
171
|
+
|
172
|
+
|
173
|
+
def generate2(
|
174
|
+
pathset: _pathset.PathSet,
|
175
|
+
ipaths: types.PathList,
|
176
|
+
output_stem: pathlib.Path,
|
177
|
+
medium: str,
|
178
|
+
title: str,
|
179
|
+
xlabel: tp.Optional[str] = None,
|
180
|
+
ylabel: tp.Optional[str] = None,
|
181
|
+
zlabel: tp.Optional[str] = None,
|
182
|
+
large_text: bool = False,
|
183
|
+
xticklabels: tp.Optional[tp.List[str]] = None,
|
184
|
+
yticklabels: tp.Optional[tp.List[str]] = None,
|
185
|
+
) -> bool:
|
186
|
+
"""Generate a side-by-side plot of two heataps from two CSV files.
|
158
187
|
|
159
188
|
``.mean`` files must be named as ``<input_stem_fpath>_X.mean``, where `X` is
|
160
189
|
non-negative integer. Input ``.mean`` files must be 2D grids of the same
|
@@ -165,192 +194,84 @@ class DualHeatmap:
|
|
165
194
|
If there are not exactly two file paths passed, the graph is not generated.
|
166
195
|
|
167
196
|
"""
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
fig.
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
#
|
250
|
-
# Add, then remove the colorbar for the heatmap on the left so that they
|
251
|
-
# both end up the same size. Not pythonic, but it works.
|
252
|
-
self._plot_colorbar(fig, im1, ax1, remove=True)
|
253
|
-
self._plot_colorbar(fig, im2, ax2, remove=False)
|
254
|
-
|
255
|
-
# Add X,Y,Z labels:
|
256
|
-
#
|
257
|
-
# - X labels are needed on both heatmaps.
|
258
|
-
# - Y label only needed on left heatmap.
|
259
|
-
self._plot_labels(ax1, xlabel=True, ylabel=True)
|
260
|
-
self._plot_labels(ax2, xlabel=True, ylabel=False)
|
261
|
-
|
262
|
-
# Add X,Y ticks:
|
263
|
-
#
|
264
|
-
# - X tick labels needed on both heatmaps
|
265
|
-
# - Y tick labels only needed on left heatmap.
|
266
|
-
self._plot_ticks(ax1, x, y, xlabels=True, ylabels=True)
|
267
|
-
self._plot_ticks(ax2, x, y, xlabels=True, ylabels=False)
|
268
|
-
|
269
|
-
# Output figures
|
270
|
-
fig.subplots_adjust(wspace=0.0, hspace=0.0)
|
271
|
-
fig.savefig(self.output_fpath, bbox_inches='tight',
|
272
|
-
dpi=config.kGraphDPI)
|
273
|
-
# Prevent memory accumulation (fig.clf() does not close everything)
|
274
|
-
plt.close(fig)
|
275
|
-
|
276
|
-
def _plot_colorbar(self, fig, im, ax, remove: bool) -> None:
|
277
|
-
"""
|
278
|
-
Plot the Z-axis color bar on the dual heatmap.
|
279
|
-
"""
|
280
|
-
divider = mpl_toolkits.axes_grid1.make_axes_locatable(ax)
|
281
|
-
cax = divider.append_axes('right', size='5%', pad=0.05)
|
282
|
-
|
283
|
-
bar = fig.colorbar(im, cax=cax)
|
284
|
-
if remove:
|
285
|
-
fig.delaxes(fig.axes[2])
|
286
|
-
|
287
|
-
# p0 = axes[0].get_position().get_points().flatten()
|
288
|
-
# p1 = axes[1].get_position().get_points().flatten()
|
289
|
-
# ax_cbar = fig.add_axes([p0[0], , p1[2] - p0[0], 0.05])
|
290
|
-
# bar = fig.colorbar(im, cax=ax_cbar, orientation='horizontal')
|
291
|
-
|
292
|
-
if self.zlabel is not None:
|
293
|
-
bar.ax.set_ylabel(self.zlabel, fontsize=self.text_size['xyz_label'])
|
294
|
-
|
295
|
-
def _plot_ticks(self, ax, xvals, yvals, xlabels: bool, ylabels: bool) -> None:
|
296
|
-
"""Plot ticks and tick labels.
|
297
|
-
|
298
|
-
If the labels are numerical and the numbers are too large, force
|
299
|
-
scientific notation (the ``rcParam`` way of doing this does not seem to
|
300
|
-
work...)
|
301
|
-
|
302
|
-
"""
|
303
|
-
ax.tick_params(labelsize=self.text_size['tick_label'])
|
304
|
-
|
305
|
-
if xlabels:
|
306
|
-
ax.set_xticks(yvals)
|
307
|
-
ax.set_xticklabels(self.ytick_labels, rotation='vertical')
|
308
|
-
else:
|
309
|
-
ax.set_xticks([])
|
310
|
-
ax.set_xticklabels([])
|
311
|
-
|
312
|
-
if ylabels:
|
313
|
-
ax.set_yticks(xvals)
|
314
|
-
ax.set_yticklabels(self.xtick_labels, rotation='horizontal')
|
315
|
-
else:
|
316
|
-
ax.set_yticks([])
|
317
|
-
ax.set_yticklabels([])
|
318
|
-
|
319
|
-
def _plot_labels(self, ax, xlabel: bool, ylabel: bool) -> None:
|
320
|
-
"""
|
321
|
-
Plot X,Y axis labels.
|
322
|
-
"""
|
323
|
-
if xlabel:
|
324
|
-
ax.set_xlabel(self.ylabel, fontsize=self.text_size['xyz_label'])
|
325
|
-
|
326
|
-
if ylabel:
|
327
|
-
ax.set_ylabel(self.xlabel, fontsize=self.text_size['xyz_label'])
|
328
|
-
|
329
|
-
|
330
|
-
class HeatmapSet():
|
331
|
-
"""
|
332
|
-
Generates a :class:`Heatmap` plot for each of the specified I/O path pairs.
|
333
|
-
"""
|
334
|
-
|
335
|
-
def __init__(self,
|
336
|
-
ipaths: types.PathList,
|
337
|
-
opaths: types.PathList,
|
338
|
-
titles: tp.List[str],
|
339
|
-
**kwargs) -> None:
|
340
|
-
self.ipaths = ipaths
|
341
|
-
self.opaths = opaths
|
342
|
-
self.titles = titles
|
343
|
-
self.kwargs = kwargs
|
344
|
-
|
345
|
-
def generate(self) -> None:
|
346
|
-
for ipath, opath, title in zip(self.ipaths, self.opaths, self.titles):
|
347
|
-
hm = Heatmap(input_fpath=ipath, output_fpath=opath,
|
348
|
-
title=title, **self.kwargs)
|
349
|
-
hm.generate()
|
350
|
-
|
351
|
-
|
352
|
-
__api__ = [
|
353
|
-
'Heatmap',
|
354
|
-
'DualHeatmap',
|
355
|
-
'HeatmapSet'
|
356
|
-
]
|
197
|
+
hv.extension("matplotlib")
|
198
|
+
|
199
|
+
output_fpath = pathset.output_root / "HM-{0}.{1}".format(
|
200
|
+
output_stem, config.kStaticImageType
|
201
|
+
)
|
202
|
+
# Optional arguments
|
203
|
+
if large_text:
|
204
|
+
text_size = config.kGraphs["text_size_large"]
|
205
|
+
else:
|
206
|
+
text_size = config.kGraphs["text_size_small"]
|
207
|
+
|
208
|
+
dfs = [storage.df_read(f, medium) for f in ipaths]
|
209
|
+
|
210
|
+
if not dfs or len(dfs) != 2:
|
211
|
+
_logger.debug(
|
212
|
+
("Not generating dual heatmap: wrong # files %s (must be 2)"), len(dfs)
|
213
|
+
)
|
214
|
+
return False
|
215
|
+
|
216
|
+
# Scaffold graph. We can use either dataframe for setting the graph
|
217
|
+
# size; we assume they have the same dimensions.
|
218
|
+
#
|
219
|
+
# fig, axes = plt.subplots(nrows=1, ncols=2)
|
220
|
+
# DualHeatmap.set_graph_size(dfs[0], fig)
|
221
|
+
|
222
|
+
yticks = np.arange(len(dfs[0].columns))
|
223
|
+
xticks = dfs[0].index
|
224
|
+
|
225
|
+
# Plot heatmaps
|
226
|
+
plot = hv.Image(dfs[0]) + hv.Image(dfs[1])
|
227
|
+
|
228
|
+
# Add X,Y ticks
|
229
|
+
if xticklabels:
|
230
|
+
plot.opts(xformatter=lambda x: xticklabels[xticks.index(x)])
|
231
|
+
if yticklabels:
|
232
|
+
plot.opts(yformatter=lambda y: yticklabels[yticks.index(y)])
|
233
|
+
|
234
|
+
# Add labels
|
235
|
+
plot.opts(xlabel=xlabel)
|
236
|
+
plot.opts(ylabel=ylabel)
|
237
|
+
|
238
|
+
# Set fontsizes
|
239
|
+
plot.opts(
|
240
|
+
fontsize={
|
241
|
+
"title": text_size["title"],
|
242
|
+
"labels": text_size["xyz_label"],
|
243
|
+
"ticks": text_size["tick_label"],
|
244
|
+
}
|
245
|
+
)
|
246
|
+
# Add title
|
247
|
+
plot.opts(title=title)
|
248
|
+
|
249
|
+
# Add colorbar.
|
250
|
+
plot.opts(
|
251
|
+
hv.opts.Layout(shared_axes=False),
|
252
|
+
hv.opts.Image(
|
253
|
+
colorbar=True,
|
254
|
+
colorbar_position="right",
|
255
|
+
backend_opts={"colorbar.label": zlabel},
|
256
|
+
),
|
257
|
+
)
|
258
|
+
|
259
|
+
# Output figures
|
260
|
+
plot.opts(fig_inches=config.kGraphs["base_size"])
|
261
|
+
|
262
|
+
hv.save(
|
263
|
+
plot,
|
264
|
+
output_fpath,
|
265
|
+
fig=config.kStaticImageType,
|
266
|
+
dpi=config.kGraphs["dpi"],
|
267
|
+
)
|
268
|
+
plt.close("all")
|
269
|
+
|
270
|
+
_logger.debug(
|
271
|
+
"Graph written to <batchroot>/%s",
|
272
|
+
output_fpath.relative_to(pathset.batchroot),
|
273
|
+
)
|
274
|
+
return True
|
275
|
+
|
276
|
+
|
277
|
+
__all__ = ["generate", "generate2"]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2025 John Harwell, All rights reserved.
|
3
|
+
#
|
4
|
+
# SPDX-License Identifier: MIT
|
5
|
+
#
|
6
|
+
|
7
|
+
# Core packages
|
8
|
+
from dataclasses import dataclass
|
9
|
+
import pathlib
|
10
|
+
import typing as tp
|
11
|
+
|
12
|
+
# 3rd party packages
|
13
|
+
|
14
|
+
# Project packages
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class PathSet:
|
19
|
+
"""The set of paths relevant/needed when creating graphs."""
|
20
|
+
|
21
|
+
input_root: pathlib.Path
|
22
|
+
output_root: pathlib.Path
|
23
|
+
batchroot: pathlib.Path
|
24
|
+
model_root: tp.Optional[pathlib.Path]
|
25
|
+
|
26
|
+
|
27
|
+
__all__ = ["PathSet"]
|