simdec 1.1.0__tar.gz → 1.2.0.dev0__tar.gz
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.
- {simdec-1.1.0 → simdec-1.2.0.dev0}/.gitignore +4 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/CONTRIBUTING.md +36 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/PKG-INFO +18 -36
- {simdec-1.1.0 → simdec-1.2.0.dev0}/README.md +3 -29
- {simdec-1.1.0 → simdec-1.2.0.dev0}/pyproject.toml +16 -9
- simdec-1.2.0.dev0/src/simdec/auth.py +17 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/src/simdec/decomposition.py +27 -9
- {simdec-1.1.0 → simdec-1.2.0.dev0}/src/simdec/visualization.py +82 -12
- simdec-1.1.0/Dockerfile +0 -47
- simdec-1.1.0/Makefile +0 -95
- simdec-1.1.0/app.py +0 -358
- {simdec-1.1.0 → simdec-1.2.0.dev0}/CODE_OF_CONDUCT.md +0 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/LICENSE.txt +0 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/src/simdec/__init__.py +0 -0
- {simdec-1.1.0 → simdec-1.2.0.dev0}/src/simdec/sensitivity_indices.py +0 -0
|
@@ -161,3 +161,39 @@ a release:
|
|
|
161
161
|
5. Check that release has been deployed to PyPI
|
|
162
162
|
6. Check documentation is built and deployed to readthedocs
|
|
163
163
|
7. Check that auto-generated PR is auto-merged on the conda-forge feedstock repo
|
|
164
|
+
|
|
165
|
+
## Dashboard
|
|
166
|
+
A live dashboard is available at:
|
|
167
|
+
|
|
168
|
+
https://simdec.io
|
|
169
|
+
|
|
170
|
+
The DNS records are available on CPanel and the rest is hosted on Google Cloud
|
|
171
|
+
Platform.
|
|
172
|
+
|
|
173
|
+
Developing locally requires the installation of GCP CLI and Docker engine.
|
|
174
|
+
|
|
175
|
+
A few helper commands are provided in the Makefile.
|
|
176
|
+
|
|
177
|
+
### Local use
|
|
178
|
+
|
|
179
|
+
The dashboard can be run locally using:
|
|
180
|
+
|
|
181
|
+
make serve-dev
|
|
182
|
+
|
|
183
|
+
If you want to test OAuth, you need to export the following env variables:
|
|
184
|
+
|
|
185
|
+
export PANEL_OAUTH_REDIRECT_URI=http://localhost:5006/app
|
|
186
|
+
export PANEL_OAUTH_KEY=[VALUE IN GCP Secret Manager]
|
|
187
|
+
export PANEL_OAUTH_SECRET=[VALUE IN GCP Secret Manager]
|
|
188
|
+
export PANEL_OAUTH_ENCRYPTION=[VALUE IN GCP Secret Manager]
|
|
189
|
+
|
|
190
|
+
Use the CLI tool `direnv` for convenience. Then you can serve with
|
|
191
|
+
OAuth support:
|
|
192
|
+
|
|
193
|
+
make serve-oauth
|
|
194
|
+
|
|
195
|
+
### Deployment
|
|
196
|
+
|
|
197
|
+
New version can either be deployed from the CI with `cloudbuild` or locally:
|
|
198
|
+
|
|
199
|
+
make production
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: simdec
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0.dev0
|
|
4
4
|
Summary: Sensitivity analysis using simulation decomposition
|
|
5
5
|
Project-URL: homepage, https://www.simdec.fi/
|
|
6
6
|
Project-URL: documentation, https://simdec.readthedocs.io
|
|
@@ -16,20 +16,28 @@ Classifier: License :: OSI Approved :: BSD License
|
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
-
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
23
|
Requires-Dist: numpy
|
|
24
24
|
Requires-Dist: pandas
|
|
25
|
-
Requires-Dist: panel
|
|
26
25
|
Requires-Dist: salib
|
|
27
26
|
Requires-Dist: seaborn
|
|
28
|
-
|
|
27
|
+
Provides-Extra: dashboard
|
|
28
|
+
Requires-Dist: cryptography; extra == 'dashboard'
|
|
29
|
+
Requires-Dist: panel>=1.3.8; extra == 'dashboard'
|
|
29
30
|
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: accessible-pygments; extra == 'dev'
|
|
32
|
+
Requires-Dist: cryptography; extra == 'dev'
|
|
30
33
|
Requires-Dist: hatch; extra == 'dev'
|
|
34
|
+
Requires-Dist: numpydoc; extra == 'dev'
|
|
35
|
+
Requires-Dist: panel>=1.3.8; extra == 'dev'
|
|
31
36
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
32
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: pydata-sphinx-theme; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
40
|
+
Requires-Dist: sphinx; extra == 'dev'
|
|
33
41
|
Provides-Extra: doc
|
|
34
42
|
Requires-Dist: accessible-pygments; extra == 'doc'
|
|
35
43
|
Requires-Dist: numpydoc; extra == 'doc'
|
|
@@ -69,30 +77,11 @@ The library is distributed on PyPi and can be installed with:
|
|
|
69
77
|
|
|
70
78
|
pip install simdec
|
|
71
79
|
|
|
72
|
-
To install the development version, download the source and from the root of
|
|
73
|
-
the repository:
|
|
74
|
-
|
|
75
|
-
pip install -e .[dev]
|
|
76
|
-
|
|
77
80
|
## Dashboard
|
|
78
81
|
A live dashboard is available at:
|
|
79
82
|
|
|
80
83
|
https://simdec.io
|
|
81
84
|
|
|
82
|
-
### Local use
|
|
83
|
-
|
|
84
|
-
The dashboard can be run locally using:
|
|
85
|
-
|
|
86
|
-
make serve
|
|
87
|
-
|
|
88
|
-
### Deployment
|
|
89
|
-
|
|
90
|
-
The live version of the dashboard is hosted on GCP. To deploy a new version:
|
|
91
|
-
|
|
92
|
-
PANEL_TOKEN=... make production
|
|
93
|
-
|
|
94
|
-
###
|
|
95
|
-
|
|
96
85
|
## Citations
|
|
97
86
|
|
|
98
87
|
The algorithms and visualizations used in this package came primarily out of
|
|
@@ -103,13 +92,6 @@ Foundation, and Finnish Foundation for Economic Education.
|
|
|
103
92
|
If you use SimDec in your research we would appreciate a citation to the
|
|
104
93
|
following publications:
|
|
105
94
|
|
|
106
|
-
- Kozlova, M., & Yeomans, J. S. (2022). Monte Carlo Enhancement via Simulation
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- Kozlova, M., Moss, R. J., Yeomans, J. S., & Caers, J. (forthcoming).
|
|
110
|
-
Uncovering Heterogeneous Effects in Computational Models for Sustainable
|
|
111
|
-
Decision-making. _Environmental Modelling & Software_.
|
|
112
|
-
- Kozlova, M., Moss, R. J., Roy, P., Alam, A., & Yeomans, J. S. (forthcoming).
|
|
113
|
-
SimDec algorithm. In M. Kozlova & J. S. Yeomans (Eds.), _Sensitivity Analysis
|
|
114
|
-
for Business, Technology, and Policymaking Made Easy with Simulation
|
|
115
|
-
Decomposition_. Routledge.
|
|
95
|
+
- Kozlova, M., & Yeomans, J. S. (2022). Monte Carlo Enhancement via Simulation Decomposition: A “Must-Have” Inclusion for Many Disciplines. _INFORMS Transactions on Education, 22_(3), 147-159. [Available here](https://pubsonline.informs.org/doi/10.1287/ited.2019.0240).
|
|
96
|
+
- Kozlova, M., Moss, R. J., Yeomans, J. S., & Caers, J. (2024). Uncovering Heterogeneous Effects in Computational Models for Sustainable Decision-making. _Environmental Modelling & Software_, 171, 105898. [https://doi.org/10.1016/j.envsoft.2023.105898](https://doi.org/10.1016/j.envsoft.2023.105898)
|
|
97
|
+
- Kozlova, M., Moss, R. J., Roy, P., Alam, A., & Yeomans, J. S. (forthcoming). SimDec algorithm and guidelines for its usage and interpretation. In M. Kozlova & J. S. Yeomans (Eds.), _Sensitivity Analysis for Business, Technology, and Policymaking. Made Easy with Simulation Decomposition_. Routledge.
|
|
@@ -27,30 +27,11 @@ The library is distributed on PyPi and can be installed with:
|
|
|
27
27
|
|
|
28
28
|
pip install simdec
|
|
29
29
|
|
|
30
|
-
To install the development version, download the source and from the root of
|
|
31
|
-
the repository:
|
|
32
|
-
|
|
33
|
-
pip install -e .[dev]
|
|
34
|
-
|
|
35
30
|
## Dashboard
|
|
36
31
|
A live dashboard is available at:
|
|
37
32
|
|
|
38
33
|
https://simdec.io
|
|
39
34
|
|
|
40
|
-
### Local use
|
|
41
|
-
|
|
42
|
-
The dashboard can be run locally using:
|
|
43
|
-
|
|
44
|
-
make serve
|
|
45
|
-
|
|
46
|
-
### Deployment
|
|
47
|
-
|
|
48
|
-
The live version of the dashboard is hosted on GCP. To deploy a new version:
|
|
49
|
-
|
|
50
|
-
PANEL_TOKEN=... make production
|
|
51
|
-
|
|
52
|
-
###
|
|
53
|
-
|
|
54
35
|
## Citations
|
|
55
36
|
|
|
56
37
|
The algorithms and visualizations used in this package came primarily out of
|
|
@@ -61,13 +42,6 @@ Foundation, and Finnish Foundation for Economic Education.
|
|
|
61
42
|
If you use SimDec in your research we would appreciate a citation to the
|
|
62
43
|
following publications:
|
|
63
44
|
|
|
64
|
-
- Kozlova, M., & Yeomans, J. S. (2022). Monte Carlo Enhancement via Simulation
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- Kozlova, M., Moss, R. J., Yeomans, J. S., & Caers, J. (forthcoming).
|
|
68
|
-
Uncovering Heterogeneous Effects in Computational Models for Sustainable
|
|
69
|
-
Decision-making. _Environmental Modelling & Software_.
|
|
70
|
-
- Kozlova, M., Moss, R. J., Roy, P., Alam, A., & Yeomans, J. S. (forthcoming).
|
|
71
|
-
SimDec algorithm. In M. Kozlova & J. S. Yeomans (Eds.), _Sensitivity Analysis
|
|
72
|
-
for Business, Technology, and Policymaking Made Easy with Simulation
|
|
73
|
-
Decomposition_. Routledge.
|
|
45
|
+
- Kozlova, M., & Yeomans, J. S. (2022). Monte Carlo Enhancement via Simulation Decomposition: A “Must-Have” Inclusion for Many Disciplines. _INFORMS Transactions on Education, 22_(3), 147-159. [Available here](https://pubsonline.informs.org/doi/10.1287/ited.2019.0240).
|
|
46
|
+
- Kozlova, M., Moss, R. J., Yeomans, J. S., & Caers, J. (2024). Uncovering Heterogeneous Effects in Computational Models for Sustainable Decision-making. _Environmental Modelling & Software_, 171, 105898. [https://doi.org/10.1016/j.envsoft.2023.105898](https://doi.org/10.1016/j.envsoft.2023.105898)
|
|
47
|
+
- Kozlova, M., Moss, R. J., Roy, P., Alam, A., & Yeomans, J. S. (forthcoming). SimDec algorithm and guidelines for its usage and interpretation. In M. Kozlova & J. S. Yeomans (Eds.), _Sensitivity Analysis for Business, Technology, and Policymaking. Made Easy with Simulation Decomposition_. Routledge.
|
|
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simdec"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.2.0dev0"
|
|
8
8
|
description = "Sensitivity analysis using simulation decomposition"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
11
|
license = "BSD-3-Clause"
|
|
12
12
|
authors = [
|
|
13
13
|
{ name = "Pamphile Roy" },
|
|
@@ -23,9 +23,9 @@ classifiers = [
|
|
|
23
23
|
"Operating System :: OS Independent",
|
|
24
24
|
"Programming Language :: Python",
|
|
25
25
|
"Programming Language :: Python :: 3",
|
|
26
|
-
"Programming Language :: Python :: 3.9",
|
|
27
26
|
"Programming Language :: Python :: 3.10",
|
|
28
27
|
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
31
|
dependencies = [
|
|
@@ -33,11 +33,14 @@ dependencies = [
|
|
|
33
33
|
"pandas",
|
|
34
34
|
"SALib",
|
|
35
35
|
"seaborn",
|
|
36
|
-
"typer[all]",
|
|
37
|
-
"panel",
|
|
38
36
|
]
|
|
39
37
|
|
|
40
38
|
[project.optional-dependencies]
|
|
39
|
+
dashboard = [
|
|
40
|
+
"panel>=1.3.8",
|
|
41
|
+
"cryptography",
|
|
42
|
+
]
|
|
43
|
+
|
|
41
44
|
test = [
|
|
42
45
|
"pytest",
|
|
43
46
|
"pytest-cov",
|
|
@@ -51,29 +54,33 @@ doc = [
|
|
|
51
54
|
]
|
|
52
55
|
|
|
53
56
|
dev = [
|
|
54
|
-
"simdec[doc,test]",
|
|
57
|
+
"simdec[doc,test,dashboard]",
|
|
55
58
|
"pre-commit",
|
|
56
59
|
"hatch",
|
|
57
60
|
]
|
|
58
61
|
|
|
59
|
-
[project.scripts]
|
|
60
|
-
simdec = "simdec.workflow:app"
|
|
61
|
-
|
|
62
62
|
[project.urls]
|
|
63
63
|
homepage = "https://www.simdec.fi/"
|
|
64
64
|
documentation = "https://simdec.readthedocs.io"
|
|
65
65
|
source = "https://github.com/Simulation-Decomposition/simdec-python"
|
|
66
66
|
|
|
67
67
|
[tool.hatch]
|
|
68
|
+
build.targets.wheel.packages = ["src/simdec"]
|
|
68
69
|
build.targets.sdist.exclude = [
|
|
69
70
|
".github",
|
|
70
71
|
"docs",
|
|
72
|
+
"panel",
|
|
71
73
|
"tests",
|
|
72
74
|
"*.rst",
|
|
73
75
|
"*.yml",
|
|
74
76
|
".*",
|
|
77
|
+
"Makefile",
|
|
78
|
+
"Dockerfile",
|
|
75
79
|
]
|
|
76
80
|
|
|
81
|
+
[project.entry-points."panel.auth"]
|
|
82
|
+
custom_google = "simdec.auth:CustomGoogleLoginHandler"
|
|
83
|
+
|
|
77
84
|
[tool.pytest.ini_options]
|
|
78
85
|
addopts = "--durations 10"
|
|
79
86
|
testpaths = [
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from panel.auth import GoogleLoginHandler
|
|
2
|
+
from panel.io.resources import CDN_DIST
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CustomGoogleLoginHandler(GoogleLoginHandler):
|
|
6
|
+
def _simple_get(self):
|
|
7
|
+
html = self._login_template.render(errormessage="", PANEL_CDN=CDN_DIST)
|
|
8
|
+
self.write(html)
|
|
9
|
+
|
|
10
|
+
async def get(self):
|
|
11
|
+
if "login" in self.request.uri and "state" not in self.request.uri:
|
|
12
|
+
self._simple_get()
|
|
13
|
+
else:
|
|
14
|
+
await super().get()
|
|
15
|
+
|
|
16
|
+
async def post(self):
|
|
17
|
+
await super().get()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
+
from hashlib import blake2b
|
|
4
5
|
from typing import Literal
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
@@ -14,13 +15,15 @@ __all__ = ["decomposition", "states_expansion"]
|
|
|
14
15
|
def states_expansion(states: list[int], inputs: pd.DataFrame) -> list[list[str]]:
|
|
15
16
|
"""Expand states list to fully represent all scenarios."""
|
|
16
17
|
inputs = pd.DataFrame(inputs)
|
|
17
|
-
|
|
18
|
+
expanded_states = []
|
|
19
|
+
for state in states:
|
|
18
20
|
if isinstance(state, int):
|
|
19
|
-
states: list
|
|
20
21
|
if state == 2:
|
|
21
|
-
|
|
22
|
+
expanded_states.append(["low", "high"])
|
|
22
23
|
elif state == 3:
|
|
23
|
-
|
|
24
|
+
expanded_states.append(["low", "medium", "high"])
|
|
25
|
+
else:
|
|
26
|
+
expanded_states.append(state)
|
|
24
27
|
|
|
25
28
|
# categorical for a given variable
|
|
26
29
|
cat_cols = inputs.select_dtypes(exclude=["number"])
|
|
@@ -33,9 +36,9 @@ def states_expansion(states: list[int], inputs: pd.DataFrame) -> list[list[str]]
|
|
|
33
36
|
|
|
34
37
|
for i, states_cat_ in zip(cat_cols_idx, states_cats_):
|
|
35
38
|
n_unique = np.unique(inputs.iloc[:, i]).size
|
|
36
|
-
|
|
39
|
+
expanded_states[i] = list(states_cat_) if n_unique < 5 else expanded_states[i]
|
|
37
40
|
|
|
38
|
-
return
|
|
41
|
+
return expanded_states
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
@dataclass
|
|
@@ -46,6 +49,17 @@ class DecompositionResult:
|
|
|
46
49
|
states: list[int]
|
|
47
50
|
bin_edges: np.ndarray
|
|
48
51
|
|
|
52
|
+
def __reduce__(self):
|
|
53
|
+
h = blake2b(key=b"result hashing", digest_size=20)
|
|
54
|
+
|
|
55
|
+
h.update(str(self.var_names).encode())
|
|
56
|
+
h.update(str(self.statistic).encode())
|
|
57
|
+
h.update(str(self.bins).encode())
|
|
58
|
+
h.update(str(self.states).encode())
|
|
59
|
+
h.update(str(self.bin_edges).encode())
|
|
60
|
+
|
|
61
|
+
return [h.hexdigest()]
|
|
62
|
+
|
|
49
63
|
|
|
50
64
|
def decomposition(
|
|
51
65
|
inputs: pd.DataFrame,
|
|
@@ -109,9 +123,13 @@ def decomposition(
|
|
|
109
123
|
|
|
110
124
|
# only keep the explained variance corresponding to `dec_limit`
|
|
111
125
|
sensitivity_indices = sensitivity_indices[var_order]
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
|
|
127
|
+
if auto_ordering:
|
|
128
|
+
n_var_dec = np.where(np.cumsum(sensitivity_indices) < dec_limit)[0].size
|
|
129
|
+
n_var_dec = max(1, n_var_dec) # keep at least one variable
|
|
130
|
+
n_var_dec = min(5, n_var_dec) # use at most 5 variables
|
|
131
|
+
else:
|
|
132
|
+
n_var_dec = inputs.shape[1]
|
|
115
133
|
|
|
116
134
|
# 2. states formation
|
|
117
135
|
if states is None:
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import itertools
|
|
2
3
|
from typing import Literal
|
|
3
4
|
|
|
5
|
+
import colorsys
|
|
4
6
|
import matplotlib as mpl
|
|
5
7
|
import matplotlib.pyplot as plt
|
|
6
8
|
import numpy as np
|
|
@@ -11,7 +13,12 @@ from pandas.io.formats.style import Styler
|
|
|
11
13
|
__all__ = ["visualization", "tableau", "palette"]
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
SEQUENTIAL_PALETTES = [
|
|
17
|
+
"#DC267F",
|
|
18
|
+
"#E8EA2F",
|
|
19
|
+
"#26DCD1",
|
|
20
|
+
"#C552E4",
|
|
21
|
+
"#3F45D0",
|
|
15
22
|
"Oranges",
|
|
16
23
|
"Purples",
|
|
17
24
|
"Reds",
|
|
@@ -33,7 +40,58 @@ sequential_palettes = [
|
|
|
33
40
|
]
|
|
34
41
|
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
@functools.cache
|
|
44
|
+
def sequential_cmaps():
|
|
45
|
+
cmaps = []
|
|
46
|
+
for cmap in SEQUENTIAL_PALETTES:
|
|
47
|
+
try:
|
|
48
|
+
cmap_ = mpl.colormaps[cmap]
|
|
49
|
+
except KeyError:
|
|
50
|
+
color = mpl.colors.hex2color(cmap)
|
|
51
|
+
cmap_ = single_color_to_colormap(color)
|
|
52
|
+
cmaps.append(cmap_)
|
|
53
|
+
return cmaps
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def single_color_to_colormap(
|
|
57
|
+
rgba_color: list[float] | str, *, factor: float = 0.5
|
|
58
|
+
) -> mpl.colors.LinearSegmentedColormap:
|
|
59
|
+
"""Create a linear colormap using a single color."""
|
|
60
|
+
if isinstance(rgba_color, str):
|
|
61
|
+
rgba_color = mpl.colors.hex2color(rgba_color)
|
|
62
|
+
# discard alpha channel
|
|
63
|
+
if len(rgba_color) == 4:
|
|
64
|
+
*rgb_color, alpha = rgba_color
|
|
65
|
+
else:
|
|
66
|
+
alpha = 1.0
|
|
67
|
+
rgb_color = rgba_color
|
|
68
|
+
rgba_color = list(rgba_color) + [1]
|
|
69
|
+
|
|
70
|
+
# lighten and darken from factor around single color
|
|
71
|
+
hls_color = colorsys.rgb_to_hls(*rgb_color)
|
|
72
|
+
|
|
73
|
+
lightness = hls_color[1]
|
|
74
|
+
lightened_hls_color = (hls_color[0], lightness * (1 + factor), hls_color[2])
|
|
75
|
+
lightened_rgb_color = list(colorsys.hls_to_rgb(*lightened_hls_color))
|
|
76
|
+
|
|
77
|
+
darkened_hls_color = (hls_color[0], lightness * (1 - factor), hls_color[2])
|
|
78
|
+
darkened_rgb_color = list(colorsys.hls_to_rgb(*darkened_hls_color))
|
|
79
|
+
|
|
80
|
+
lightened_rgba_color = lightened_rgb_color + [alpha]
|
|
81
|
+
darkened_rgba_color = darkened_rgb_color + [alpha]
|
|
82
|
+
|
|
83
|
+
# convert to CMAP
|
|
84
|
+
cmap = mpl.colors.LinearSegmentedColormap.from_list(
|
|
85
|
+
"CustomSingleColor",
|
|
86
|
+
[lightened_rgba_color, rgba_color, darkened_rgba_color],
|
|
87
|
+
N=3,
|
|
88
|
+
)
|
|
89
|
+
return cmap
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def palette(
|
|
93
|
+
states: list[int], cmaps: list[mpl.colors.LinearSegmentedColormap] = None
|
|
94
|
+
) -> list[list[float]]:
|
|
37
95
|
"""Colour palette.
|
|
38
96
|
|
|
39
97
|
The product of the states gives the number of scenarios. For each
|
|
@@ -43,20 +101,32 @@ def palette(states: list[int]) -> list[list[float]]:
|
|
|
43
101
|
----------
|
|
44
102
|
states : list of int
|
|
45
103
|
List of possible states for the considered parameter.
|
|
46
|
-
|
|
104
|
+
cmaps : list of LinearSegmentedColormap
|
|
105
|
+
List of colormaps. Must have the same number of colormaps as the number
|
|
106
|
+
of first level of states.
|
|
47
107
|
Returns
|
|
48
108
|
-------
|
|
49
|
-
palette : list of
|
|
50
|
-
List of
|
|
109
|
+
palette : list of float of size (n, 4)
|
|
110
|
+
List of colors corresponding to scenarios. RGBA formatted.
|
|
51
111
|
"""
|
|
112
|
+
n_cmaps = states[0]
|
|
113
|
+
if cmaps is None:
|
|
114
|
+
cmaps = sequential_cmaps()[:n_cmaps]
|
|
115
|
+
else:
|
|
116
|
+
cmaps = cmaps[:n_cmaps]
|
|
117
|
+
if len(cmaps) != n_cmaps:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
f"Must have the same number of cmaps ({len(cmaps)}) as the "
|
|
120
|
+
f"number of first states ({n_cmaps})"
|
|
121
|
+
)
|
|
122
|
+
|
|
52
123
|
colors = []
|
|
53
124
|
# one palette per first level state, could use more palette when there are
|
|
54
125
|
# many levels
|
|
55
126
|
n_shades = int(np.prod(states[1:]))
|
|
56
|
-
for i in range(
|
|
57
|
-
|
|
58
|
-
cmap
|
|
59
|
-
colors.append(cmap(range(1, n_shades + 1)))
|
|
127
|
+
for i in range(n_cmaps):
|
|
128
|
+
cmap = cmaps[i].resampled(n_shades)
|
|
129
|
+
colors.append(cmap(np.linspace(0, 1, n_shades)))
|
|
60
130
|
|
|
61
131
|
return np.concatenate(colors).tolist()
|
|
62
132
|
|
|
@@ -108,7 +178,7 @@ def visualization(
|
|
|
108
178
|
elif kind == "boxplot":
|
|
109
179
|
ax = sns.boxplot(
|
|
110
180
|
bins,
|
|
111
|
-
palette=palette
|
|
181
|
+
palette=palette,
|
|
112
182
|
orient="h",
|
|
113
183
|
order=list(bins.columns)[::-1],
|
|
114
184
|
ax=ax,
|
|
@@ -180,10 +250,10 @@ def tableau(
|
|
|
180
250
|
# only select/ordering interesting columns
|
|
181
251
|
table = table[["colour", "std", "min", "mean", "max", "probability"]]
|
|
182
252
|
|
|
183
|
-
table.insert(loc=0, column="N°", value=np.arange(1, stop=len(table) + 1))
|
|
253
|
+
table.insert(loc=0, column="N°", value=np.arange(1, stop=len(table) + 1)[::-1])
|
|
184
254
|
|
|
185
255
|
# style the colour background with palette
|
|
186
|
-
cmap = mpl.colors.ListedColormap(palette
|
|
256
|
+
cmap = mpl.colors.ListedColormap(palette)
|
|
187
257
|
styler = table.style
|
|
188
258
|
styler.format(precision=2)
|
|
189
259
|
styler.background_gradient(subset=["colour"], cmap=cmap)
|
simdec-1.1.0/Dockerfile
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
## Step 1/3: Base image
|
|
2
|
-
FROM python:3.11-slim-bookworm as base
|
|
3
|
-
RUN \
|
|
4
|
-
--mount=type=cache,target=/var/cache/apt \
|
|
5
|
-
apt-get update && apt-get upgrade -y && apt install curl -y
|
|
6
|
-
|
|
7
|
-
## Step 2/3: Build/Install app dependencies
|
|
8
|
-
FROM base as builder
|
|
9
|
-
# Allow statements and log messages to immediately appear in the Knative logs
|
|
10
|
-
ENV PYTHONUNBUFFERED True
|
|
11
|
-
|
|
12
|
-
COPY pyproject.toml README.md /
|
|
13
|
-
|
|
14
|
-
RUN --mount=type=cache,target=/var/cache/apt apt install -y gcc git
|
|
15
|
-
RUN --mount=type=cache,mode=0777,target=/root/.cache/pip \
|
|
16
|
-
pip install --upgrade pip setuptools wheel && \
|
|
17
|
-
pip install -e . && \
|
|
18
|
-
mkdir -p /app/src
|
|
19
|
-
|
|
20
|
-
COPY tests/data /app/tests/data
|
|
21
|
-
COPY src/simdec /app/src/simdec
|
|
22
|
-
COPY app.py /app/app.py
|
|
23
|
-
# matplotlib cache
|
|
24
|
-
RUN mkdir -p /app/.config/matplotlib
|
|
25
|
-
|
|
26
|
-
# Step 3/3: Image
|
|
27
|
-
FROM base as panel
|
|
28
|
-
# Allow statements and log messages to immediately appear in the Knative logs
|
|
29
|
-
ENV PYTHONUNBUFFERED True
|
|
30
|
-
ENV PYTHONPATH=/app/src
|
|
31
|
-
ENV PYTHONIOENCODING=utf-8
|
|
32
|
-
ENV ENV=production
|
|
33
|
-
ENV PORT=8080
|
|
34
|
-
|
|
35
|
-
ARG PANEL_TOKEN
|
|
36
|
-
|
|
37
|
-
COPY --from=builder /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/
|
|
38
|
-
COPY --from=builder /usr/local/bin/panel /usr/local/bin/panel
|
|
39
|
-
COPY --from=builder /app/src /app/src
|
|
40
|
-
COPY --from=builder /app/tests/data /app/tests/data
|
|
41
|
-
COPY --from=builder /app/app.py /app/app.py
|
|
42
|
-
|
|
43
|
-
WORKDIR /app
|
|
44
|
-
RUN useradd app && usermod -a -G app app
|
|
45
|
-
USER app
|
|
46
|
-
# Run the web service on container startup.
|
|
47
|
-
CMD panel serve app.py --address 0.0.0.0 --port $PORT --allow-websocket-origin="*" --basic-auth=$PANEL_TOKEN --num-procs 2 --cookie-secret my_super_safe_cookie_secret
|
simdec-1.1.0/Makefile
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
.PHONY: help prepare doc test serve build publish-production
|
|
2
|
-
.DEFAULT_GOAL := help
|
|
3
|
-
SHELL:=/bin/bash
|
|
4
|
-
|
|
5
|
-
ifndef version
|
|
6
|
-
override version = development
|
|
7
|
-
endif
|
|
8
|
-
|
|
9
|
-
ifndef region
|
|
10
|
-
override region = europe-north1
|
|
11
|
-
endif
|
|
12
|
-
|
|
13
|
-
ifndef project
|
|
14
|
-
override project = delta-entity-401706
|
|
15
|
-
endif
|
|
16
|
-
|
|
17
|
-
ifndef PANEL_TOKEN
|
|
18
|
-
# only for local dev, another token is used for deployment
|
|
19
|
-
override PANEL_TOKEN = e41ea4c145bf13a60c8779c24356
|
|
20
|
-
endif
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Add help text after each target name starting with '\#\#'
|
|
24
|
-
help: ## show this help
|
|
25
|
-
@echo -e "Help for this makefile\n"
|
|
26
|
-
@echo "Possible commands are:"
|
|
27
|
-
@grep -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -e 's/\(.*\):.*##\(.*\)/ \1: \2/'
|
|
28
|
-
|
|
29
|
-
prepare: ## Install dependencies and pre-commit hook
|
|
30
|
-
pip install -e ".[dev]"
|
|
31
|
-
pre-commit install
|
|
32
|
-
gcloud init
|
|
33
|
-
gcloud auth configure-docker
|
|
34
|
-
|
|
35
|
-
doc: ## Build Sphinx documentation
|
|
36
|
-
sphinx-build -b html docs docs/html
|
|
37
|
-
|
|
38
|
-
test: ## Run tests with coverage
|
|
39
|
-
pytest --cov simdec --cov-report term-missing
|
|
40
|
-
|
|
41
|
-
serve-dev: ## Serve Panel dashboard - Dev mode
|
|
42
|
-
panel serve app.py --show --autoreload
|
|
43
|
-
|
|
44
|
-
serve: ## Serve Panel dashboard - Prod mode
|
|
45
|
-
panel serve app.py
|
|
46
|
-
|
|
47
|
-
build-local:
|
|
48
|
-
docker build -f ./Dockerfile \
|
|
49
|
-
--build-arg PANEL_TOKEN=$(PANEL_TOKEN) \
|
|
50
|
-
--tag simdec-panel:$(version) \
|
|
51
|
-
--pull \
|
|
52
|
-
./.
|
|
53
|
-
|
|
54
|
-
run-local: build-local
|
|
55
|
-
docker run --rm -it \
|
|
56
|
-
--name=simdec-panel \
|
|
57
|
-
--memory=1g \
|
|
58
|
-
--cpuset-cpus=0 \
|
|
59
|
-
-e ENV=development \
|
|
60
|
-
-p "8080:8080" \
|
|
61
|
-
simdec-panel:$(version)
|
|
62
|
-
|
|
63
|
-
build:
|
|
64
|
-
docker build -f ./Dockerfile \
|
|
65
|
-
--platform linux/amd64 \
|
|
66
|
-
--build-arg PANEL_TOKEN=$(PANEL_TOKEN) \
|
|
67
|
-
--tag simdec-panel:$(version) \
|
|
68
|
-
--pull \
|
|
69
|
-
./.
|
|
70
|
-
|
|
71
|
-
run: build
|
|
72
|
-
docker run --rm -it \
|
|
73
|
-
--name=simdec-panel \
|
|
74
|
-
--memory=1g \
|
|
75
|
-
--cpuset-cpus=0 \
|
|
76
|
-
-e ENV=development \
|
|
77
|
-
-p "8080:8080" \
|
|
78
|
-
simdec-panel:$(version)
|
|
79
|
-
|
|
80
|
-
publish-production: build
|
|
81
|
-
docker tag simdec-panel:$(version) $(region)-docker.pkg.dev/$(project)/simdec-panel/simdec-panel:$(version)
|
|
82
|
-
docker push $(region)-docker.pkg.dev/$(project)/simdec-panel/simdec-panel:$(version)
|
|
83
|
-
|
|
84
|
-
production: publish-production
|
|
85
|
-
@echo "Deploying '$(version)'."
|
|
86
|
-
gcloud run deploy simdec-panel \
|
|
87
|
-
--concurrency=10 \
|
|
88
|
-
--max-instances=1 \
|
|
89
|
-
--region=$(region) \
|
|
90
|
-
--port=8080 \
|
|
91
|
-
--set-env-vars ENV=production \
|
|
92
|
-
--allow-unauthenticated \
|
|
93
|
-
--timeout=600 \
|
|
94
|
-
--image=$(region)-docker.pkg.dev/$(project)/simdec-panel/simdec-panel:$(version) \
|
|
95
|
-
--memory 1Gi
|
simdec-1.1.0/app.py
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import bisect
|
|
2
|
-
import io
|
|
3
|
-
|
|
4
|
-
from bokeh.models import PrintfTickFormatter
|
|
5
|
-
from bokeh.models.widgets.tables import NumberFormatter
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
import numpy as np
|
|
8
|
-
import pandas as pd
|
|
9
|
-
import panel as pn
|
|
10
|
-
|
|
11
|
-
import simdec as sd
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# panel app
|
|
15
|
-
pn.extension(template="material")
|
|
16
|
-
pn.extension("tabulator")
|
|
17
|
-
|
|
18
|
-
pn.config.sizing_mode = "stretch_width"
|
|
19
|
-
pn.config.throttled = True
|
|
20
|
-
font_size = "12pt"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@pn.cache
|
|
24
|
-
def load_data(text_fname):
|
|
25
|
-
if text_fname is None:
|
|
26
|
-
text_fname = "tests/data/stress.csv"
|
|
27
|
-
else:
|
|
28
|
-
text_fname = io.BytesIO(text_fname)
|
|
29
|
-
|
|
30
|
-
data = pd.read_csv(text_fname)
|
|
31
|
-
pn.state.clear_caches()
|
|
32
|
-
return data
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@pn.cache
|
|
36
|
-
def column_inputs(data, output):
|
|
37
|
-
inputs = list(data.columns)
|
|
38
|
-
inputs.remove(output)
|
|
39
|
-
return inputs
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@pn.cache
|
|
43
|
-
def filtered_inputs(data, input_names):
|
|
44
|
-
return data[input_names]
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@pn.cache
|
|
48
|
-
def column_output(data):
|
|
49
|
-
return list(data.columns)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@pn.cache
|
|
53
|
-
def filtered_output(data, output_name):
|
|
54
|
-
return data[output_name]
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@pn.cache
|
|
58
|
-
def sensitivity_indices(inputs, output):
|
|
59
|
-
sensitivity_indices = sd.sensitivity_indices(inputs=inputs, output=output)
|
|
60
|
-
if 0.01 < sum(sensitivity_indices.si) < 2.0:
|
|
61
|
-
indices = sensitivity_indices.si
|
|
62
|
-
else:
|
|
63
|
-
indices = sensitivity_indices.first_order
|
|
64
|
-
return indices
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def sensitivity_indices_table(si, inputs):
|
|
68
|
-
var_names = inputs.columns
|
|
69
|
-
var_order = np.argsort(si)[::-1]
|
|
70
|
-
var_names = var_names[var_order].tolist()
|
|
71
|
-
|
|
72
|
-
si = list(si[var_order])
|
|
73
|
-
sum_si = sum(si)
|
|
74
|
-
|
|
75
|
-
var_names.append("Sum of Indices")
|
|
76
|
-
si_numerics = si.copy()
|
|
77
|
-
si.append(0)
|
|
78
|
-
si_numerics.append(sum_si)
|
|
79
|
-
|
|
80
|
-
d = {"Inputs": var_names, "Indices": si, "": si_numerics}
|
|
81
|
-
df = pd.DataFrame(data=d)
|
|
82
|
-
formatters = {
|
|
83
|
-
"Indices": {"type": "progress", "max": sum_si, "color": "#007eff"},
|
|
84
|
-
"": NumberFormatter(format="0.00"),
|
|
85
|
-
}
|
|
86
|
-
widget = pn.widgets.Tabulator(
|
|
87
|
-
df,
|
|
88
|
-
show_index=False,
|
|
89
|
-
formatters=formatters,
|
|
90
|
-
theme="bulma",
|
|
91
|
-
)
|
|
92
|
-
widget.style.apply(
|
|
93
|
-
lambda x: ["font-style: italic"] * 3, axis=1, subset=df.index[-1]
|
|
94
|
-
)
|
|
95
|
-
widget.style.apply(lambda x: ["font-size: 11pt"] * len(si))
|
|
96
|
-
return widget
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@pn.cache
|
|
100
|
-
def explained_variance(si):
|
|
101
|
-
return sum(si) + np.finfo(np.float64).eps
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def filtered_si(sensitivity_indices_table, input_names):
|
|
105
|
-
df = sensitivity_indices_table.value
|
|
106
|
-
si = []
|
|
107
|
-
for input_name in input_names:
|
|
108
|
-
si.append(df.loc[df["Inputs"] == input_name, "Indices"])
|
|
109
|
-
return np.asarray(si).flatten()
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def explained_variance_80(sensitivity_indices_table):
|
|
113
|
-
si = sensitivity_indices_table.value["Indices"]
|
|
114
|
-
pos_80 = bisect.bisect_right(np.cumsum(si), 0.8)
|
|
115
|
-
|
|
116
|
-
# pos_80 = max(2, pos_80)
|
|
117
|
-
# pos_80 = min(len(si), pos_80)
|
|
118
|
-
|
|
119
|
-
input_names = sensitivity_indices_table.value["Inputs"]
|
|
120
|
-
return input_names.to_list()[: pos_80 + 1]
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def decomposition(dec_limit, si, inputs, output):
|
|
124
|
-
return sd.decomposition(
|
|
125
|
-
inputs=inputs,
|
|
126
|
-
output=output,
|
|
127
|
-
sensitivity_indices=si,
|
|
128
|
-
dec_limit=dec_limit,
|
|
129
|
-
auto_ordering=False,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def palette(res):
|
|
134
|
-
return sd.palette(res.states)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def n_bins_auto(res):
|
|
138
|
-
min_ = np.nanmin(res.bins)
|
|
139
|
-
max_ = np.nanmax(res.bins)
|
|
140
|
-
return len(np.histogram_bin_edges(res.bins, bins="auto", range=(min_, max_))) - 1
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def display_n_bins(kind):
|
|
144
|
-
if kind != "Stacked histogram":
|
|
145
|
-
return
|
|
146
|
-
|
|
147
|
-
return selector_n_bins
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def figure(res, palette, n_bins, kind, output_name):
|
|
151
|
-
kind = "histogram" if kind == "Stacked histogram" else "boxplot"
|
|
152
|
-
plt.close("all")
|
|
153
|
-
fig, ax = plt.subplots()
|
|
154
|
-
_ = sd.visualization(
|
|
155
|
-
bins=res.bins, palette=palette, n_bins=n_bins, kind=kind, ax=ax
|
|
156
|
-
)
|
|
157
|
-
ax.set(xlabel=output_name)
|
|
158
|
-
return fig
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def states_from_data(res, inputs):
|
|
162
|
-
return sd.states_expansion(states=res.states, inputs=inputs)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def tableau(res, states, palette):
|
|
166
|
-
# use a notebook to see the styling
|
|
167
|
-
_, styler = sd.tableau(
|
|
168
|
-
statistic=res.statistic,
|
|
169
|
-
var_names=res.var_names,
|
|
170
|
-
states=states,
|
|
171
|
-
bins=res.bins,
|
|
172
|
-
palette=palette,
|
|
173
|
-
)
|
|
174
|
-
return styler
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def tableau_states(res, states):
|
|
178
|
-
data = []
|
|
179
|
-
for var_name, states_, bin_edges in zip(res.var_names, states, res.bin_edges):
|
|
180
|
-
for i, state in enumerate(states_):
|
|
181
|
-
data.append([var_name, state, bin_edges[i], bin_edges[i + 1]])
|
|
182
|
-
|
|
183
|
-
table = pd.DataFrame(data, columns=["variable", "state", "min", "max"])
|
|
184
|
-
table.set_index(["variable", "state"], inplace=True)
|
|
185
|
-
|
|
186
|
-
styler = table.style
|
|
187
|
-
styler.format(precision=2)
|
|
188
|
-
styler.set_table_styles([{"selector": "th", "props": [("text-align", "center")]}])
|
|
189
|
-
return styler
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
# Bindings
|
|
193
|
-
text_fname = pn.widgets.FileInput(sizing_mode="stretch_width", accept=".csv")
|
|
194
|
-
|
|
195
|
-
interactive_file = pn.bind(load_data, text_fname)
|
|
196
|
-
|
|
197
|
-
interactive_column_output = pn.bind(column_output, interactive_file)
|
|
198
|
-
selector_output = pn.widgets.Select(name="Output", options=interactive_column_output)
|
|
199
|
-
interactive_output = pn.bind(filtered_output, interactive_file, selector_output)
|
|
200
|
-
|
|
201
|
-
interactive_column_input = pn.bind(column_inputs, interactive_file, selector_output)
|
|
202
|
-
selector_inputs_sensitivity = pn.widgets.MultiSelect(
|
|
203
|
-
name="Inputs", value=interactive_column_input, options=interactive_column_input
|
|
204
|
-
)
|
|
205
|
-
interactive_inputs = pn.bind(
|
|
206
|
-
filtered_output, interactive_file, selector_inputs_sensitivity
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
interactive_sensitivity_indices = pn.bind(
|
|
210
|
-
sensitivity_indices, interactive_inputs, interactive_output
|
|
211
|
-
)
|
|
212
|
-
interactive_explained_variance = pn.bind(
|
|
213
|
-
explained_variance, interactive_sensitivity_indices
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
interactive_sensitivity_indices_table = pn.bind(
|
|
217
|
-
sensitivity_indices_table, interactive_sensitivity_indices, interactive_inputs
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
interactive_explained_variance_80 = pn.bind(
|
|
221
|
-
explained_variance_80, interactive_sensitivity_indices_table
|
|
222
|
-
)
|
|
223
|
-
selector_inputs_decomposition = pn.widgets.MultiChoice(
|
|
224
|
-
name="Select inputs for decomposition",
|
|
225
|
-
value=interactive_explained_variance_80,
|
|
226
|
-
options=selector_inputs_sensitivity,
|
|
227
|
-
solid=False,
|
|
228
|
-
)
|
|
229
|
-
interactive_inputs_decomposition = pn.bind(
|
|
230
|
-
filtered_output, interactive_file, selector_inputs_decomposition
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
interactive_filtered_si = pn.bind(
|
|
234
|
-
filtered_si, interactive_sensitivity_indices_table, selector_inputs_decomposition
|
|
235
|
-
)
|
|
236
|
-
interactive_filtered_explained_variance = pn.bind(
|
|
237
|
-
explained_variance, interactive_filtered_si
|
|
238
|
-
)
|
|
239
|
-
indicator_explained_variance = pn.indicators.Number(
|
|
240
|
-
name="Explained variance ratio from selected inputs:",
|
|
241
|
-
value=interactive_filtered_explained_variance,
|
|
242
|
-
title_size=font_size,
|
|
243
|
-
font_size=font_size,
|
|
244
|
-
format="{value:.2f}",
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
interactive_decomposition = pn.bind(
|
|
249
|
-
decomposition,
|
|
250
|
-
interactive_explained_variance,
|
|
251
|
-
interactive_filtered_si,
|
|
252
|
-
interactive_inputs_decomposition,
|
|
253
|
-
interactive_output,
|
|
254
|
-
)
|
|
255
|
-
interactive_palette = pn.bind(palette, interactive_decomposition)
|
|
256
|
-
|
|
257
|
-
switch_histogram_boxplot = pn.widgets.RadioButtonGroup(
|
|
258
|
-
name="Switch histogram - boxplot",
|
|
259
|
-
options=["Stacked histogram", "Boxplot"],
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
interactive_n_bins_auto = pn.bind(n_bins_auto, interactive_decomposition)
|
|
263
|
-
selector_n_bins = pn.widgets.EditableIntSlider(
|
|
264
|
-
name="Number of bins",
|
|
265
|
-
start=0,
|
|
266
|
-
end=100,
|
|
267
|
-
value=interactive_n_bins_auto,
|
|
268
|
-
step=10,
|
|
269
|
-
# bar_color="#FFFFFF", # does not work
|
|
270
|
-
format=PrintfTickFormatter(format="%d bins"),
|
|
271
|
-
)
|
|
272
|
-
conditional_selector_n_bins = pn.bind(display_n_bins, switch_histogram_boxplot)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
interactive_figure = pn.bind(
|
|
276
|
-
figure,
|
|
277
|
-
interactive_decomposition,
|
|
278
|
-
interactive_palette,
|
|
279
|
-
selector_n_bins,
|
|
280
|
-
switch_histogram_boxplot,
|
|
281
|
-
selector_output,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
interactive_states = pn.bind(
|
|
286
|
-
states_from_data, interactive_decomposition, interactive_inputs_decomposition
|
|
287
|
-
)
|
|
288
|
-
interactive_tableau = pn.bind(
|
|
289
|
-
tableau, interactive_decomposition, interactive_states, interactive_palette
|
|
290
|
-
)
|
|
291
|
-
interactive_tableau_states = pn.bind(
|
|
292
|
-
tableau_states, interactive_decomposition, interactive_states
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
# App layout
|
|
296
|
-
|
|
297
|
-
top_description = """
|
|
298
|
-
## Data
|
|
299
|
-
"""
|
|
300
|
-
|
|
301
|
-
si_description = """
|
|
302
|
-
## Sensitivity Indices
|
|
303
|
-
"""
|
|
304
|
-
|
|
305
|
-
decomposition_description = """
|
|
306
|
-
## Decomposition
|
|
307
|
-
"""
|
|
308
|
-
|
|
309
|
-
table_description = """
|
|
310
|
-
## Scenarios
|
|
311
|
-
"""
|
|
312
|
-
|
|
313
|
-
states_description = """
|
|
314
|
-
## Details on inputs' states
|
|
315
|
-
"""
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
pn_params = pn.layout.WidgetBox(
|
|
319
|
-
pn.pane.Markdown(top_description, styles={"color": "#0072b5"}),
|
|
320
|
-
text_fname,
|
|
321
|
-
selector_output,
|
|
322
|
-
selector_inputs_sensitivity,
|
|
323
|
-
pn.pane.Markdown(decomposition_description, styles={"color": "#0072b5"}),
|
|
324
|
-
selector_inputs_decomposition,
|
|
325
|
-
indicator_explained_variance,
|
|
326
|
-
pn.pane.Markdown("## Visualization", styles={"color": "#0072b5"}),
|
|
327
|
-
switch_histogram_boxplot,
|
|
328
|
-
conditional_selector_n_bins,
|
|
329
|
-
max_width=350,
|
|
330
|
-
sizing_mode="stretch_width",
|
|
331
|
-
).servable(area="sidebar")
|
|
332
|
-
|
|
333
|
-
pn_app = pn.Column(
|
|
334
|
-
pn.Row(
|
|
335
|
-
pn.Column(
|
|
336
|
-
pn.panel(
|
|
337
|
-
pn.pane.Matplotlib(
|
|
338
|
-
interactive_figure,
|
|
339
|
-
tight=True,
|
|
340
|
-
format="svg",
|
|
341
|
-
sizing_mode="stretch_both",
|
|
342
|
-
max_height=500,
|
|
343
|
-
height_policy="min",
|
|
344
|
-
)
|
|
345
|
-
),
|
|
346
|
-
pn.Spacer(height=50),
|
|
347
|
-
pn.pane.Markdown(si_description, styles={"color": "#0072b5"}),
|
|
348
|
-
pn.Column(interactive_sensitivity_indices_table, width=400),
|
|
349
|
-
),
|
|
350
|
-
pn.Column(
|
|
351
|
-
pn.pane.Markdown(table_description, styles={"color": "#0072b5"}),
|
|
352
|
-
pn.panel(interactive_tableau),
|
|
353
|
-
pn.Spacer(height=125),
|
|
354
|
-
pn.pane.Markdown(states_description, styles={"color": "#0072b5"}),
|
|
355
|
-
pn.panel(interactive_tableau_states),
|
|
356
|
-
),
|
|
357
|
-
)
|
|
358
|
-
).servable(title="Simulation Decomposition Dashboard")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|