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
@@ -1,251 +0,0 @@
|
|
1
|
-
# Copyright 2018 John Harwell, All rights reserved.
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: MIT
|
4
|
-
#
|
5
|
-
|
6
|
-
# Core packages
|
7
|
-
import typing as tp
|
8
|
-
import copy
|
9
|
-
import logging
|
10
|
-
import pathlib
|
11
|
-
|
12
|
-
# 3rd party packages
|
13
|
-
import pandas as pd
|
14
|
-
import matplotlib.pyplot as plt
|
15
|
-
|
16
|
-
# Project packages
|
17
|
-
from sierra.core import config, utils, storage
|
18
|
-
|
19
|
-
|
20
|
-
class StackedLineGraph:
|
21
|
-
"""Generates a line graph from a set of columns in a CSV file.
|
22
|
-
|
23
|
-
If the necessary data file does not exist, the graph is not generated.
|
24
|
-
|
25
|
-
If the .stddev file that goes with the .mean does not exist, then no error
|
26
|
-
bars are plotted.
|
27
|
-
|
28
|
-
If the .model file that goes with the .mean does not exist, then no model
|
29
|
-
predictions are plotted.
|
30
|
-
|
31
|
-
Ideally, model predictions/stddev calculations would be in derived classes,
|
32
|
-
but I can't figure out a good way to easily pull that stuff out of here.
|
33
|
-
|
34
|
-
"""
|
35
|
-
|
36
|
-
def __init__(self,
|
37
|
-
stats_root: pathlib.Path,
|
38
|
-
input_stem: str,
|
39
|
-
output_fpath: pathlib.Path,
|
40
|
-
title: str,
|
41
|
-
xlabel: tp.Optional[str] = None,
|
42
|
-
ylabel: tp.Optional[str] = None,
|
43
|
-
large_text: bool = False,
|
44
|
-
legend: tp.Optional[tp.List[str]] = None,
|
45
|
-
cols: tp.Optional[tp.List[str]] = None,
|
46
|
-
linestyles: tp.Optional[tp.List[str]] = None,
|
47
|
-
dashstyles: tp.Optional[tp.List[str]] = None,
|
48
|
-
logyscale: bool = False,
|
49
|
-
stddev_fpath: tp.Optional[pathlib.Path] = None,
|
50
|
-
stats: str = 'none',
|
51
|
-
model_root: tp.Optional[pathlib.Path] = None) -> None:
|
52
|
-
|
53
|
-
# Required arguments
|
54
|
-
self.stats_root = stats_root
|
55
|
-
self.input_stem = input_stem
|
56
|
-
self.output_fpath = output_fpath
|
57
|
-
self.title = title
|
58
|
-
|
59
|
-
# Optional arguments
|
60
|
-
if large_text:
|
61
|
-
self.text_size = config.kGraphTextSizeLarge
|
62
|
-
else:
|
63
|
-
self.text_size = config.kGraphTextSizeSmall
|
64
|
-
|
65
|
-
self.xlabel = xlabel
|
66
|
-
self.ylabel = ylabel
|
67
|
-
self.legend = legend
|
68
|
-
self.cols = cols
|
69
|
-
self.logyscale = logyscale
|
70
|
-
self.linestyles = linestyles
|
71
|
-
self.dashstyles = dashstyles
|
72
|
-
self.stats = stats
|
73
|
-
self.model_root = model_root
|
74
|
-
self.stddev_fpath = stddev_fpath
|
75
|
-
self.logger = logging.getLogger(__name__)
|
76
|
-
|
77
|
-
def generate(self) -> None:
|
78
|
-
ext = config.kStats['mean'].exts['mean']
|
79
|
-
input_fpath = self.stats_root / (self.input_stem + ext)
|
80
|
-
if not utils.path_exists(input_fpath):
|
81
|
-
self.logger.debug("Not generating %s: %s does not exist",
|
82
|
-
self.output_fpath,
|
83
|
-
input_fpath)
|
84
|
-
return
|
85
|
-
|
86
|
-
data_df = storage.DataFrameReader('storage.csv')(input_fpath)
|
87
|
-
|
88
|
-
model = self._read_models()
|
89
|
-
stat_dfs = self._read_stats()
|
90
|
-
|
91
|
-
# Plot specified columns from dataframe.
|
92
|
-
if self.cols is None:
|
93
|
-
ncols = max(1, int(len(data_df.columns) / 2.0))
|
94
|
-
ax = self._plot_selected_cols(
|
95
|
-
data_df, stat_dfs, data_df.columns, model)
|
96
|
-
else:
|
97
|
-
ncols = max(1, int(len(self.cols) / 2.0))
|
98
|
-
ax = self._plot_selected_cols(data_df, stat_dfs, self.cols, model)
|
99
|
-
|
100
|
-
self._plot_ticks(ax)
|
101
|
-
|
102
|
-
self._plot_legend(ax, model[1], ncols)
|
103
|
-
|
104
|
-
# Add title
|
105
|
-
ax.set_title(self.title, fontsize=self.text_size['title'])
|
106
|
-
|
107
|
-
# Add X,Y labels
|
108
|
-
if self.xlabel is not None:
|
109
|
-
ax.set_xlabel(self.xlabel, fontsize=self.text_size['xyz_label'])
|
110
|
-
|
111
|
-
if self.ylabel is not None:
|
112
|
-
ax.set_ylabel(self.ylabel, fontsize=self.text_size['xyz_label'])
|
113
|
-
|
114
|
-
# Output figure
|
115
|
-
fig = ax.get_figure()
|
116
|
-
fig.set_size_inches(config.kGraphBaseSize,
|
117
|
-
config.kGraphBaseSize)
|
118
|
-
fig.savefig(self.output_fpath,
|
119
|
-
bbox_inches='tight',
|
120
|
-
dpi=config.kGraphDPI)
|
121
|
-
# Prevent memory accumulation (fig.clf() does not close everything)
|
122
|
-
plt.close(fig)
|
123
|
-
|
124
|
-
def _plot_ticks(self, ax) -> None:
|
125
|
-
if self.logyscale:
|
126
|
-
plt.yscale('symlog')
|
127
|
-
|
128
|
-
ax.tick_params(labelsize=self.text_size['tick_label'])
|
129
|
-
|
130
|
-
def _plot_selected_cols(self,
|
131
|
-
data_df: pd.DataFrame,
|
132
|
-
stat_dfs: tp.Dict[str, pd.DataFrame],
|
133
|
-
cols: tp.List[str],
|
134
|
-
model: tp.Tuple[pd.DataFrame, tp.List[str]]):
|
135
|
-
"""
|
136
|
-
Plot the selected columns in a dataframe.
|
137
|
-
|
138
|
-
This may include:
|
139
|
-
|
140
|
-
- Errorbars
|
141
|
-
- Models
|
142
|
-
- Custom line styles
|
143
|
-
- Custom dash styles
|
144
|
-
"""
|
145
|
-
# Always plot the data
|
146
|
-
if self.linestyles is None and self.dashstyles is None:
|
147
|
-
ax = data_df[cols].plot()
|
148
|
-
elif self.dashstyles is None and self.linestyles is not None:
|
149
|
-
for c, s in zip(cols, self.linestyles):
|
150
|
-
ax = data_df[c].plot(linestyle=s)
|
151
|
-
elif self.dashstyles is not None and self.linestyles is not None:
|
152
|
-
for c, s, d in zip(cols, self.linestyles, self.dashstyles):
|
153
|
-
ax = data_df[c].plot(linestyle=s, dashes=d)
|
154
|
-
|
155
|
-
# Plot models if they have been computed
|
156
|
-
if model[0] is not None:
|
157
|
-
model[0][model[0].columns].plot(ax=ax)
|
158
|
-
|
159
|
-
# Plot stddev if it has been computed
|
160
|
-
if 'stddev' in stat_dfs.keys():
|
161
|
-
for c in cols:
|
162
|
-
self._plot_col_errorbars(data_df, stat_dfs['stddev'], c)
|
163
|
-
return ax
|
164
|
-
|
165
|
-
def _plot_col_errorbars(self,
|
166
|
-
data_df: pd.DataFrame,
|
167
|
-
stddev_df: pd.DataFrame,
|
168
|
-
col: str) -> None:
|
169
|
-
"""
|
170
|
-
Plot the errorbars for a specific column in a dataframe.
|
171
|
-
"""
|
172
|
-
plt.fill_between(data_df.index,
|
173
|
-
data_df[col] - 2 * stddev_df[col].abs(),
|
174
|
-
data_df[col] + 2 * stddev_df[col].abs(),
|
175
|
-
alpha=0.50)
|
176
|
-
|
177
|
-
def _plot_legend(self, ax, model_legend: tp.List[str], ncols: int) -> None:
|
178
|
-
# Should always use one column: If a small number of lines are plotted,
|
179
|
-
# then 1 vs. > 1 column makes no difference. If a large number of lines
|
180
|
-
# are plotted, this will make the figures more portrait than landscape,
|
181
|
-
# which is more amenable to inclusion in academic papers.
|
182
|
-
|
183
|
-
# If the legend is not specified, then we assume this is not a graph
|
184
|
-
# that will contain any models and/or no legend is desired.
|
185
|
-
legend = self.legend
|
186
|
-
|
187
|
-
if self.legend is not None:
|
188
|
-
legend = copy.deepcopy(self.legend)
|
189
|
-
if model_legend:
|
190
|
-
legend.extend(model_legend)
|
191
|
-
|
192
|
-
lines, _ = ax.get_legend_handles_labels()
|
193
|
-
ax.legend(lines,
|
194
|
-
legend,
|
195
|
-
loc='lower center',
|
196
|
-
bbox_to_anchor=(0.5, -0.5),
|
197
|
-
ncol=1,
|
198
|
-
fontsize=self.text_size['legend_label'])
|
199
|
-
else:
|
200
|
-
ax.legend().remove()
|
201
|
-
# ax.legend(loc='lower center',
|
202
|
-
# bbox_to_anchor=(0.5, -0.5),
|
203
|
-
# ncol=1,
|
204
|
-
# fontsize=self.text_size['legend_label'])
|
205
|
-
|
206
|
-
def _read_stats(self) -> tp.Dict[str, pd.DataFrame]:
|
207
|
-
dfs = {}
|
208
|
-
|
209
|
-
reader = storage.DataFrameReader('storage.csv')
|
210
|
-
if self.stats in ['conf95', 'all']:
|
211
|
-
exts = config.kStats['conf95'].exts
|
212
|
-
|
213
|
-
for k in exts:
|
214
|
-
ipath = self.stats_root / (self.input_stem + exts[k])
|
215
|
-
|
216
|
-
if utils.path_exists(ipath):
|
217
|
-
dfs[k] = reader(ipath)
|
218
|
-
else:
|
219
|
-
self.logger.warning("%sfile not found for '%s'",
|
220
|
-
exts[k],
|
221
|
-
self.input_stem)
|
222
|
-
|
223
|
-
return dfs
|
224
|
-
|
225
|
-
# 2024/09/13 [JRH]: The union is for compatability with type checkers in
|
226
|
-
# python {3.8,3.11}.
|
227
|
-
def _read_models(self) -> tp.Tuple[pd.DataFrame, tp.Union[tp.List[str], tp.List[bytes]]]:
|
228
|
-
if self.model_root is not None:
|
229
|
-
model_fpath = self.model_root / \
|
230
|
-
(self.input_stem + config.kModelsExt['model'])
|
231
|
-
legend_fpath = self.model_root / \
|
232
|
-
(self.input_stem + config.kModelsExt['legend'])
|
233
|
-
|
234
|
-
if utils.path_exists(model_fpath):
|
235
|
-
model = storage.DataFrameReader('storage.csv')(model_fpath)
|
236
|
-
if utils.path_exists(legend_fpath):
|
237
|
-
with utils.utf8open(legend_fpath, 'r') as f:
|
238
|
-
model_legend = f.read().splitlines()
|
239
|
-
else:
|
240
|
-
self.logger.warning("No legend file for model '%s' found",
|
241
|
-
model_fpath)
|
242
|
-
model_legend = ['Model Prediction']
|
243
|
-
|
244
|
-
return (model, model_legend)
|
245
|
-
|
246
|
-
return (None, [])
|
247
|
-
|
248
|
-
|
249
|
-
__api__ = [
|
250
|
-
'StackedLineGraph'
|
251
|
-
]
|
@@ -1,220 +0,0 @@
|
|
1
|
-
# Copyright 2018 John Harwell, All rights reserved.
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: MIT
|
4
|
-
#
|
5
|
-
|
6
|
-
# Core packages
|
7
|
-
import typing as tp
|
8
|
-
import logging
|
9
|
-
import pathlib
|
10
|
-
|
11
|
-
# 3rd party packages
|
12
|
-
import numpy as np
|
13
|
-
import matplotlib as mpl
|
14
|
-
import matplotlib.pyplot as plt
|
15
|
-
from mpl_toolkits.mplot3d import Axes3D
|
16
|
-
|
17
|
-
# Project packages
|
18
|
-
from sierra.core import config, storage, types
|
19
|
-
|
20
|
-
|
21
|
-
class StackedSurfaceGraph:
|
22
|
-
"""Generates a plot of a set of 3D surface graphs from a set of CSVs.
|
23
|
-
|
24
|
-
``.mean`` files must be named as``<input_stem_fpath>_X.mean``, where `X` is
|
25
|
-
non-negative integer. Input CSV files must be 2D grids of the same
|
26
|
-
cardinality.
|
27
|
-
|
28
|
-
This graph does not plot standard deviation.
|
29
|
-
|
30
|
-
If no ``.mean`` files matching the pattern are found, the graph is not
|
31
|
-
generated.
|
32
|
-
|
33
|
-
"""
|
34
|
-
kMaxSurfaces = 4
|
35
|
-
|
36
|
-
def __init__(self,
|
37
|
-
ipaths: types.PathList,
|
38
|
-
output_fpath: pathlib.Path,
|
39
|
-
title: str,
|
40
|
-
legend: tp.List[str],
|
41
|
-
xlabel: str,
|
42
|
-
ylabel: str,
|
43
|
-
zlabel: str,
|
44
|
-
xtick_labels: tp.List[str],
|
45
|
-
ytick_labels: tp.List[str],
|
46
|
-
comp_type: str,
|
47
|
-
large_text: bool = False) -> None:
|
48
|
-
|
49
|
-
self.ipaths = ipaths
|
50
|
-
self.output_fpath = output_fpath
|
51
|
-
self.title = title
|
52
|
-
self.legend = legend
|
53
|
-
self.xlabel = xlabel
|
54
|
-
self.ylabel = ylabel
|
55
|
-
self.zlabel = zlabel
|
56
|
-
self.xtick_labels = xtick_labels
|
57
|
-
self.ytick_labels = ytick_labels
|
58
|
-
self.comp_type = comp_type
|
59
|
-
|
60
|
-
if large_text:
|
61
|
-
self.text_size = config.kGraphTextSizeLarge
|
62
|
-
else:
|
63
|
-
self.text_size = config.kGraphTextSizeSmall
|
64
|
-
|
65
|
-
self.logger = logging.getLogger(__name__)
|
66
|
-
|
67
|
-
def generate(self) -> None:
|
68
|
-
reader = storage.DataFrameReader('storage.csv')
|
69
|
-
dfs = [reader(f) for f in self.ipaths]
|
70
|
-
|
71
|
-
if not dfs or len(dfs) > StackedSurfaceGraph.kMaxSurfaces:
|
72
|
-
self.logger.debug(("Not generating stacked surface graph: wrong # "
|
73
|
-
"files (must be > 0, <= %s)"),
|
74
|
-
StackedSurfaceGraph.kMaxSurfaces)
|
75
|
-
return
|
76
|
-
|
77
|
-
assert len(dfs) <= StackedSurfaceGraph.kMaxSurfaces,\
|
78
|
-
f"Too many surfaces to plot: {len(dfs)} > {StackedSurfaceGraph.kMaxSurfaces}"
|
79
|
-
|
80
|
-
# Scaffold graph
|
81
|
-
plt.figure(figsize=(config.kGraphBaseSize, config.kGraphBaseSize))
|
82
|
-
ax = plt.axes(projection='3d')
|
83
|
-
x = np.arange(len(dfs[0].columns))
|
84
|
-
y = dfs[0].index
|
85
|
-
X, Y = np.meshgrid(x, y)
|
86
|
-
|
87
|
-
# Use non-quantitative colormaps in order to get really nice looking
|
88
|
-
# surfaces that change color with Z value. From
|
89
|
-
# https://stackoverflow.com/questions/55501860/how-to-put-multiple-colormap-patches-in-a-matplotlib-legend
|
90
|
-
colors = [plt.cm.Greens, plt.cm.Reds, plt.cm.Purples, plt.cm.Oranges]
|
91
|
-
legend_cmap_handles = [mpl.patches.Rectangle(
|
92
|
-
(0, 0), 1, 1) for _ in colors]
|
93
|
-
legend_handler_map = dict(zip(legend_cmap_handles,
|
94
|
-
[HandlerColormap(c, num_stripes=8) for c in colors]))
|
95
|
-
|
96
|
-
# Plot surfaces
|
97
|
-
self._plot_surfaces(X, Y, ax, colors, dfs)
|
98
|
-
|
99
|
-
# Add title
|
100
|
-
ax.set_title(self.title, fontsize=24)
|
101
|
-
|
102
|
-
# Add X,Y,Z labels
|
103
|
-
self._plot_labels(ax)
|
104
|
-
|
105
|
-
# Add X,Y ticks
|
106
|
-
self._plot_ticks(ax, x, y)
|
107
|
-
|
108
|
-
# Add legend
|
109
|
-
self._plot_legend(ax, legend_cmap_handles, legend_handler_map)
|
110
|
-
|
111
|
-
# Output figures
|
112
|
-
fig = ax.get_figure()
|
113
|
-
fig.set_size_inches(10, 10)
|
114
|
-
self._save_figs(fig, ax)
|
115
|
-
|
116
|
-
def _plot_surfaces(self, X, Y, ax, colors, dfs):
|
117
|
-
ax.plot_surface(X, Y, dfs[0], cmap=colors[0])
|
118
|
-
|
119
|
-
# We do the calculations between dataframes in here rather than in the
|
120
|
-
# comparator, because we can be comparing more than 2.
|
121
|
-
for i in range(1, len(dfs)):
|
122
|
-
if self.comp_type == 'SUraw':
|
123
|
-
plot_df = dfs[i]
|
124
|
-
elif self.comp_type == 'SUscale':
|
125
|
-
plot_df = dfs[i] / dfs[0]
|
126
|
-
elif self.comp_type == 'SUdiff':
|
127
|
-
plot_df = dfs[i] - dfs[0]
|
128
|
-
ax.plot_surface(X, Y, plot_df, cmap=colors[i], alpha=0.5)
|
129
|
-
|
130
|
-
def _plot_ticks(self, ax, xvals, yvals):
|
131
|
-
"""Plot ticks and tick labels.
|
132
|
-
|
133
|
-
If the labels are numerical and the numbers are too large, force
|
134
|
-
scientific notation (the ``rcParam`` way of doing this does not seem to
|
135
|
-
work...)
|
136
|
-
|
137
|
-
"""
|
138
|
-
ax.tick_params(labelsize=self.text_size['tick_label'])
|
139
|
-
ax.set_xticks(xvals)
|
140
|
-
ax.set_xticklabels(self.xtick_labels, rotation='vertical')
|
141
|
-
|
142
|
-
ax.set_yticks(yvals)
|
143
|
-
ax.set_yticklabels(self.ytick_labels, rotation='vertical')
|
144
|
-
|
145
|
-
def _plot_legend(self, ax, cmap_handles, handler_map):
|
146
|
-
# Legend should have ~3 entries per column, in order to maximize real
|
147
|
-
# estate on tightly constrained papers.
|
148
|
-
ax.legend(handles=cmap_handles,
|
149
|
-
handler_map=handler_map,
|
150
|
-
labels=self.legend,
|
151
|
-
loc=9,
|
152
|
-
bbox_to_anchor=(0.5, -0.1),
|
153
|
-
ncol=len(self.legend),
|
154
|
-
fontsize=self.text_size['legend_label'])
|
155
|
-
|
156
|
-
def _plot_labels(self, ax):
|
157
|
-
max_xlen = max([len(str(l)) for l in self.xtick_labels])
|
158
|
-
max_ylen = max([len(str(l)) for l in self.ytick_labels])
|
159
|
-
ax.set_xlabel('\n' * max_xlen + self.xlabel,
|
160
|
-
fontsize=self.text_size['xyz_label'])
|
161
|
-
ax.set_ylabel('\n' * max_ylen + self.ylabel,
|
162
|
-
fontsize=self.text_size['xyz_label'])
|
163
|
-
ax.set_zlabel('\n' + self.zlabel, fontsize=self.text_size['xyz_label'])
|
164
|
-
|
165
|
-
def _save_figs(self, fig, ax):
|
166
|
-
"""Save multiple rotated copies of the same figure.
|
167
|
-
|
168
|
-
Necessary for automation of 3D figure generation, because you can't
|
169
|
-
really know a priori what views are going to give the best results. MPL
|
170
|
-
doesn't have a true 3D plot generator yet.
|
171
|
-
|
172
|
-
"""
|
173
|
-
for angle in range(0, 360, 30):
|
174
|
-
ax.view_init(elev=None, azim=angle)
|
175
|
-
# The path we are passed may contain dots from the controller same,
|
176
|
-
# so we extract the leaf of that for manipulation to add the angle
|
177
|
-
# of the view right before the file extension.
|
178
|
-
path = self.output_fpath.parent
|
179
|
-
leaf = self.output_fpath.name
|
180
|
-
components = leaf.split('.')
|
181
|
-
fname = ''.join(leaf[0:-2]) + '_' + \
|
182
|
-
str(angle) + '.' + components[-1]
|
183
|
-
fig.savefig(path / fname,
|
184
|
-
bbox_inches='tight',
|
185
|
-
dpi=config.kGraphDPI,
|
186
|
-
pad_inches=0)
|
187
|
-
# Prevent memory accumulation (fig.clf() does not close everything)
|
188
|
-
plt.close(fig)
|
189
|
-
|
190
|
-
|
191
|
-
class HandlerColormap(mpl.legend_handler.HandlerBase):
|
192
|
-
def __init__(self, cmap, num_stripes=8, **kw) -> None:
|
193
|
-
super().__init__(**kw)
|
194
|
-
self.cmap = cmap
|
195
|
-
self.num_stripes = num_stripes
|
196
|
-
|
197
|
-
def create_artists(self,
|
198
|
-
legend,
|
199
|
-
orig_handle,
|
200
|
-
xdescent,
|
201
|
-
ydescent,
|
202
|
-
width,
|
203
|
-
height,
|
204
|
-
fontsize,
|
205
|
-
trans):
|
206
|
-
stripes = []
|
207
|
-
for i in range(self.num_stripes):
|
208
|
-
s = mpl.patches.Rectangle([xdescent + i * width / self.num_stripes, ydescent],
|
209
|
-
width / self.num_stripes,
|
210
|
-
height,
|
211
|
-
fc=self.cmap(
|
212
|
-
(2 * i + 1) / (2 * self.num_stripes)),
|
213
|
-
transform=trans)
|
214
|
-
stripes.append(s)
|
215
|
-
return stripes
|
216
|
-
|
217
|
-
|
218
|
-
__api__ = [
|
219
|
-
'StackedSurfaceGraph'
|
220
|
-
]
|