pyfemtet 0.4.12__py3-none-any.whl → 0.4.14__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.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/__init__.py +1 -1
- pyfemtet/dispatch_extensions.py +4 -0
- pyfemtet/message/1. make_pot.bat +12 -0
- pyfemtet/message/2. make_mo.bat +6 -0
- pyfemtet/message/__init__.py +5 -0
- pyfemtet/message/babel.cfg +2 -0
- pyfemtet/message/locales/ja/LC_MESSAGES/messages.po +449 -0
- pyfemtet/message/locales/messages.pot +439 -0
- pyfemtet/message/messages.py +174 -0
- pyfemtet/opt/_femopt.py +9 -9
- pyfemtet/opt/_femopt_core.py +22 -17
- pyfemtet/opt/femprj_sample/ParametricIF - True.femprj +0 -0
- pyfemtet/opt/femprj_sample/ParametricIF.femprj +0 -0
- pyfemtet/opt/femprj_sample/ParametricIF.py +31 -0
- pyfemtet/opt/femprj_sample/ParametricIF_test_result.reccsv +13 -0
- pyfemtet/opt/femprj_sample/cad_ex01_NX_test_result.reccsv +13 -13
- pyfemtet/opt/femprj_sample/cad_ex01_SW_test_result.reccsv +13 -13
- pyfemtet/opt/femprj_sample/gal_ex58_parametric_test_result.reccsv +13 -13
- pyfemtet/opt/femprj_sample/gau_ex08_parametric_test_result.reccsv +23 -23
- pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -18
- pyfemtet/opt/femprj_sample/paswat_ex1_parametric_test_result.reccsv +18 -18
- pyfemtet/opt/femprj_sample/tutorial.femprj +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
- pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric_test_result.reccsv +18 -18
- pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
- pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.py +31 -0
- pyfemtet/opt/interface/_femtet.py +45 -47
- pyfemtet/opt/interface/_femtet_parametric.py +7 -2
- pyfemtet/opt/interface/_femtet_with_nx/_interface.py +4 -4
- pyfemtet/opt/interface/_femtet_with_nx/update_model.py +6 -6
- pyfemtet/opt/interface/_femtet_with_sldworks.py +5 -4
- pyfemtet/opt/opt/__init__.py +2 -0
- pyfemtet/opt/opt/_base.py +41 -20
- pyfemtet/opt/opt/_optuna.py +8 -13
- pyfemtet/opt/opt/_scipy.py +4 -8
- pyfemtet/opt/opt/_scipy_scalar.py +1 -5
- pyfemtet/opt/prediction/__init__.py +0 -0
- pyfemtet/opt/prediction/base.py +52 -0
- pyfemtet/opt/prediction/single_task_gp.py +82 -0
- pyfemtet/opt/visualization/complex_components/control_femtet.py +9 -11
- pyfemtet/opt/visualization/complex_components/main_figure_creator.py +24 -11
- pyfemtet/opt/visualization/complex_components/main_graph.py +3 -4
- pyfemtet/opt/visualization/complex_components/pm_graph.py +715 -0
- pyfemtet/opt/visualization/complex_components/pm_graph_creator.py +168 -0
- pyfemtet/opt/visualization/process_monitor/application.py +16 -12
- pyfemtet/opt/visualization/process_monitor/pages.py +22 -7
- pyfemtet/opt/visualization/result_viewer/application.py +8 -3
- pyfemtet/opt/visualization/result_viewer/pages.py +59 -47
- {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/METADATA +2 -1
- pyfemtet-0.4.14.dist-info/RECORD +151 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +0 -18
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +0 -81
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +0 -28
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +0 -22
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
- pyfemtet-0.4.12.dist-info/RECORD +0 -138
- {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/LICENSE +0 -0
- {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/WHEEL +0 -0
- {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
# type hint
|
|
2
|
+
from dash.development.base_component import Component
|
|
3
|
+
|
|
4
|
+
# callback
|
|
5
|
+
from dash import Output, Input, State, no_update, callback_context, ALL, MATCH
|
|
6
|
+
from dash.exceptions import PreventUpdate
|
|
7
|
+
|
|
8
|
+
# components
|
|
9
|
+
from dash import dash_table
|
|
10
|
+
from pyfemtet.opt.visualization.wrapped_components import html, dcc, dbc
|
|
11
|
+
|
|
12
|
+
# graph
|
|
13
|
+
import pandas as pd
|
|
14
|
+
# import plotly.express as px
|
|
15
|
+
import plotly.graph_objs as go
|
|
16
|
+
|
|
17
|
+
# the others
|
|
18
|
+
import os
|
|
19
|
+
import base64
|
|
20
|
+
import json
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
from pyfemtet.opt.visualization.complex_components.pm_graph_creator import PredictionModelCreator
|
|
24
|
+
from pyfemtet.opt.visualization.base import PyFemtetApplicationBase, AbstractPage, logger
|
|
25
|
+
from pyfemtet.message import Msg
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
FLEXBOX_STYLE_ALLOW_VERTICAL_FILL = {
|
|
29
|
+
'display': 'flex',
|
|
30
|
+
'flex-direction': 'column',
|
|
31
|
+
'flex-grow': '1',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# noinspection PyAttributeOutsideInit
|
|
36
|
+
class PredictionModelGraph(AbstractPage):
|
|
37
|
+
""""""
|
|
38
|
+
"""
|
|
39
|
+
+=================+
|
|
40
|
+
|3d|scatterplot| | <- CardHeader
|
|
41
|
+
| +--------------+
|
|
42
|
+
| +-------------+ |
|
|
43
|
+
| | Loading | | <- CardBody
|
|
44
|
+
| | +---------+ | |
|
|
45
|
+
| | | graph <-------- ToolTip
|
|
46
|
+
| | +---------+ | |
|
|
47
|
+
| +-------------+ |
|
|
48
|
+
| |
|
|
49
|
+
| +-------------+ |
|
|
50
|
+
| |p1, p2, obj <------ Dropdown (axis selection)
|
|
51
|
+
| | | |
|
|
52
|
+
| | p3 --o----- | |
|
|
53
|
+
| | p4 -----o-- <----- Slider(s) (choose the value of the others)
|
|
54
|
+
| | | |
|
|
55
|
+
| +-------------+ |
|
|
56
|
+
| |
|
|
57
|
+
+=================+
|
|
58
|
+
|
|
59
|
+
Data(data-selection)
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(self):
|
|
64
|
+
self.rsm_creator: PredictionModelCreator = PredictionModelCreator()
|
|
65
|
+
super().__init__()
|
|
66
|
+
|
|
67
|
+
def setup_component(self):
|
|
68
|
+
self.location = dcc.Location(id='rsm-graph-location', refresh=True)
|
|
69
|
+
|
|
70
|
+
# setup header
|
|
71
|
+
self.tab_list = [dbc.Tab(label=Msg.TAB_LABEL_PREDICTION_MODEL)]
|
|
72
|
+
self.tabs = dbc.Tabs(self.tab_list)
|
|
73
|
+
|
|
74
|
+
# setup body
|
|
75
|
+
# self.tooltip = dcc.Tooltip()
|
|
76
|
+
|
|
77
|
+
# set kwargs of Graph to reconstruct Graph in ProcessMonitor.
|
|
78
|
+
self.graph_kwargs = dict(
|
|
79
|
+
# animate=True, # THIS CAUSE THE UPDATED DATA / NOT-UPDATED FIGURE STATE.
|
|
80
|
+
clear_on_unhover=True,
|
|
81
|
+
style={
|
|
82
|
+
'height': '60vh',
|
|
83
|
+
},
|
|
84
|
+
figure=go.Figure()
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
self.graph: dcc.Graph = dcc.Graph(
|
|
88
|
+
**self.graph_kwargs
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self.loading = dcc.Loading(
|
|
92
|
+
children=self.graph,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# setup selection data
|
|
96
|
+
# self.selection_data_property = 'data-selection' # must be starts with "data-"
|
|
97
|
+
# self.selection_data = html.Data(id='selection-data', **{self.selection_data_property: {}})
|
|
98
|
+
|
|
99
|
+
# update rsm button
|
|
100
|
+
self.fit_rsm_button_spinner = dbc.Spinner(size='sm', spinner_style={'display': 'none'})
|
|
101
|
+
self.fit_rsm_button = dbc.Button([self.fit_rsm_button_spinner, Msg.LABEL_OF_CREATE_PREDICTION_MODEL_BUTTON], color='success')
|
|
102
|
+
self.redraw_graph_button_spinner = dbc.Spinner(size='sm', spinner_style={'display': 'none'})
|
|
103
|
+
self.redraw_graph_button = dbc.Button([self.redraw_graph_button_spinner, Msg.LABEL_OF_REDRAW_PREDICTION_MODEL_GRAPH_BUTTON])
|
|
104
|
+
|
|
105
|
+
# # set data length (to notify data updated to application)
|
|
106
|
+
# self.data_length_prop = 'data-df-length' # must start with "data-"
|
|
107
|
+
# self.data_length = html.Data(id='df-length-data', **{self.data_length_prop: None})
|
|
108
|
+
|
|
109
|
+
# Dropdowns
|
|
110
|
+
self.axis1_prm_dropdown = dbc.DropdownMenu()
|
|
111
|
+
self.axis2_prm_dropdown = dbc.DropdownMenu()
|
|
112
|
+
self.axis3_obj_dropdown = dbc.DropdownMenu()
|
|
113
|
+
self.axis_controllers = [
|
|
114
|
+
self.axis1_prm_dropdown,
|
|
115
|
+
self.axis2_prm_dropdown,
|
|
116
|
+
self.axis3_obj_dropdown,
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
# sliders
|
|
120
|
+
self.slider_stack_data_prop = 'data-prm-slider-values'
|
|
121
|
+
self.slider_stack_data = html.Data(**{self.slider_stack_data_prop: {}})
|
|
122
|
+
self.slider_container = html.Div()
|
|
123
|
+
|
|
124
|
+
def setup_layout(self):
|
|
125
|
+
self.card_header = dbc.CardHeader(self.tabs)
|
|
126
|
+
|
|
127
|
+
self.card_body = dbc.CardBody(
|
|
128
|
+
children=html.Div([self.loading]), # children=html.Div([self.loading, self.tooltip]),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
dropdown_rows = [
|
|
132
|
+
dbc.Row([dbc.Col(html.Span(Msg.LABEL_OF_AXIS1_SELECTION), align='center', style={'text-align': 'end'}, width=2), dbc.Col(self.axis_controllers[0])]),
|
|
133
|
+
dbc.Row([dbc.Col(html.Span(Msg.LABEL_OF_AXIS2_SELECTION), align='center', style={'text-align': 'end'}, width=2), dbc.Col(self.axis_controllers[1])], id='prm-axis-2-dropdown'),
|
|
134
|
+
dbc.Row([dbc.Col(html.Span(Msg.LABEL_OF_AXIS3_SELECTION), align='center', style={'text-align': 'end'}, width=2), dbc.Col(self.axis_controllers[2])]),
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
self.card_footer = dbc.CardFooter(
|
|
138
|
+
children=[
|
|
139
|
+
dbc.Stack([self.fit_rsm_button, self.redraw_graph_button], direction='horizontal', gap=2),
|
|
140
|
+
*dropdown_rows,
|
|
141
|
+
self.slider_container,
|
|
142
|
+
self.slider_stack_data,
|
|
143
|
+
],
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
self.graph_card = dbc.Card(
|
|
147
|
+
[
|
|
148
|
+
self.location,
|
|
149
|
+
# self.data_length,
|
|
150
|
+
self.card_header,
|
|
151
|
+
self.card_body,
|
|
152
|
+
self.card_footer,
|
|
153
|
+
],
|
|
154
|
+
# style=FLEXBOX_STYLE_ALLOW_VERTICAL_FILL,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
self.layout = dbc.Container(
|
|
158
|
+
children=[
|
|
159
|
+
dbc.Row(self.graph_card),
|
|
160
|
+
]
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def setup_callback(self):
|
|
164
|
+
# setup callback of subpages
|
|
165
|
+
super().setup_callback()
|
|
166
|
+
|
|
167
|
+
app = self.application.app
|
|
168
|
+
|
|
169
|
+
# ===== disable fit buttons when clicked =====
|
|
170
|
+
@app.callback(
|
|
171
|
+
Output(self.fit_rsm_button_spinner, 'spinner_style', allow_duplicate=True),
|
|
172
|
+
Output(self.fit_rsm_button, 'disabled', allow_duplicate=True),
|
|
173
|
+
Output(self.redraw_graph_button_spinner, 'spinner_style', allow_duplicate=True),
|
|
174
|
+
Output(self.redraw_graph_button, 'disabled', allow_duplicate=True),
|
|
175
|
+
Input(self.fit_rsm_button, 'n_clicks'),
|
|
176
|
+
Input(self.redraw_graph_button, 'n_clicks'),
|
|
177
|
+
State(self.fit_rsm_button_spinner, 'spinner_style'),
|
|
178
|
+
State(self.redraw_graph_button_spinner, 'spinner_style'),
|
|
179
|
+
prevent_initial_call=True,
|
|
180
|
+
)
|
|
181
|
+
def disable_fit_button(_1, _2, state1, state2):
|
|
182
|
+
if 'display' in state1.keys(): state1.pop('display')
|
|
183
|
+
if 'display' in state2.keys(): state2.pop('display')
|
|
184
|
+
return state1, True, state2, True
|
|
185
|
+
|
|
186
|
+
# ===== recreate RSM =====
|
|
187
|
+
@app.callback(
|
|
188
|
+
Output(self.redraw_graph_button, 'n_clicks'),
|
|
189
|
+
Input(self.fit_rsm_button, 'n_clicks'),
|
|
190
|
+
prevent_initial_call=True,
|
|
191
|
+
)
|
|
192
|
+
def recalculate_rsm(*args):
|
|
193
|
+
# just in case
|
|
194
|
+
if callback_context.triggered_id is None:
|
|
195
|
+
raise PreventUpdate
|
|
196
|
+
|
|
197
|
+
# load history
|
|
198
|
+
if self.application.history is None:
|
|
199
|
+
return 1 # error handling in the next `redraw_graph()` callback
|
|
200
|
+
|
|
201
|
+
# check history
|
|
202
|
+
if len(self.data_accessor()) == 0:
|
|
203
|
+
return 1 # error handling in the next `redraw_graph()` callback
|
|
204
|
+
|
|
205
|
+
# create model
|
|
206
|
+
self.rsm_creator.fit(
|
|
207
|
+
self.application.history,
|
|
208
|
+
self.data_accessor(),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return 1
|
|
212
|
+
|
|
213
|
+
# ===== Update Graph =====
|
|
214
|
+
@app.callback(
|
|
215
|
+
Output(self.graph, 'figure'),
|
|
216
|
+
# Output(self.data_length.id, self.data_length_prop), # To determine whether Process Monitor should update the graph, the main graph remembers the current amount of data.
|
|
217
|
+
Input(self.redraw_graph_button, 'n_clicks'),
|
|
218
|
+
State(self.tabs, 'active_tab'),
|
|
219
|
+
State(self.axis1_prm_dropdown, 'label'),
|
|
220
|
+
State(self.axis2_prm_dropdown, 'label'),
|
|
221
|
+
State(self.axis3_obj_dropdown, 'label'),
|
|
222
|
+
State(self.slider_container, 'children'), # for callback chain
|
|
223
|
+
State({'type': 'prm-slider', 'index': ALL}, 'value'),
|
|
224
|
+
prevent_initial_call=True,
|
|
225
|
+
)
|
|
226
|
+
def redraw_graph(_1, active_tab_id, axis1_label, axis2_label, axis3_label, _2, prm_values):
|
|
227
|
+
# just in case
|
|
228
|
+
if callback_context.triggered_id is None:
|
|
229
|
+
raise PreventUpdate
|
|
230
|
+
|
|
231
|
+
# load history
|
|
232
|
+
if self.application.history is None:
|
|
233
|
+
logger.error(Msg.ERR_NO_HISTORY_SELECTED)
|
|
234
|
+
return go.Figure() # to re-enable buttons, fire callback chain
|
|
235
|
+
prm_names = self.application.history.prm_names
|
|
236
|
+
|
|
237
|
+
# check history
|
|
238
|
+
if len(self.data_accessor()) == 0:
|
|
239
|
+
logger.error(Msg.ERR_NO_FEM_RESULT)
|
|
240
|
+
return go.Figure() # to re-enable buttons, fire callback chain
|
|
241
|
+
|
|
242
|
+
# check fit
|
|
243
|
+
if not hasattr(self.rsm_creator, 'history'):
|
|
244
|
+
logger.error(Msg.ERR_NO_PREDICTION_MODEL)
|
|
245
|
+
return go.Figure() # to re-enable buttons, fire callback chain
|
|
246
|
+
|
|
247
|
+
# get indices to remove
|
|
248
|
+
idx1 = prm_names.index(axis1_label) if axis1_label in prm_names else None
|
|
249
|
+
idx2 = prm_names.index(axis2_label) if axis2_label in prm_names else None
|
|
250
|
+
|
|
251
|
+
# replace values to remove to None
|
|
252
|
+
if idx1 is not None:
|
|
253
|
+
prm_values[idx1] = None
|
|
254
|
+
if idx2 is not None:
|
|
255
|
+
prm_values[idx2] = None
|
|
256
|
+
|
|
257
|
+
# remove all None from array: prm_values is now remaining_x
|
|
258
|
+
while None in prm_values:
|
|
259
|
+
prm_values.remove(None)
|
|
260
|
+
|
|
261
|
+
# create figure
|
|
262
|
+
fig = self.rsm_creator.create_figure(
|
|
263
|
+
axis1_label,
|
|
264
|
+
axis3_label,
|
|
265
|
+
remaining_x=prm_values,
|
|
266
|
+
prm_name_2=axis2_label,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
return fig
|
|
270
|
+
|
|
271
|
+
# ===== When the graph is updated, enable buttons =====
|
|
272
|
+
@app.callback(
|
|
273
|
+
Output(self.fit_rsm_button, 'disabled', allow_duplicate=True),
|
|
274
|
+
Output(self.fit_rsm_button_spinner, 'spinner_style', allow_duplicate=True),
|
|
275
|
+
Output(self.redraw_graph_button, 'disabled', allow_duplicate=True),
|
|
276
|
+
Output(self.redraw_graph_button_spinner, 'spinner_style', allow_duplicate=True),
|
|
277
|
+
Input(self.graph, 'figure'),
|
|
278
|
+
State(self.fit_rsm_button_spinner, 'spinner_style'),
|
|
279
|
+
State(self.redraw_graph_button_spinner, 'spinner_style'),
|
|
280
|
+
prevent_initial_call=True,
|
|
281
|
+
)
|
|
282
|
+
def enable_buttons(_, state1, state2):
|
|
283
|
+
state1.update({'display': 'none'})
|
|
284
|
+
state2.update({'display': 'none'})
|
|
285
|
+
return False, state1, False, state2
|
|
286
|
+
|
|
287
|
+
# ===== setup dropdown and sliders from history =====
|
|
288
|
+
@app.callback(
|
|
289
|
+
Output(self.axis1_prm_dropdown, 'children'),
|
|
290
|
+
Output(self.axis2_prm_dropdown, 'children'),
|
|
291
|
+
Output(self.axis3_obj_dropdown, 'children'),
|
|
292
|
+
Output(self.slider_container, 'children'),
|
|
293
|
+
Output(self.slider_stack_data, self.slider_stack_data_prop, allow_duplicate=True),
|
|
294
|
+
Input(self.location, self.location.Prop.pathname),
|
|
295
|
+
prevent_initial_call=True,
|
|
296
|
+
)
|
|
297
|
+
def setup_dropdown_and_sliders(*_):
|
|
298
|
+
# just in case
|
|
299
|
+
if callback_context.triggered_id is None:
|
|
300
|
+
raise PreventUpdate
|
|
301
|
+
|
|
302
|
+
# load history
|
|
303
|
+
if self.application.history is None:
|
|
304
|
+
logger.error(Msg.ERR_NO_HISTORY_SELECTED)
|
|
305
|
+
raise PreventUpdate
|
|
306
|
+
|
|
307
|
+
# add dropdown item to dropdown
|
|
308
|
+
axis1_dropdown_items, axis2_dropdown_items = [], []
|
|
309
|
+
for i, prm_name in enumerate(self.application.history.prm_names):
|
|
310
|
+
dm_item_1 = dbc.DropdownMenuItem(
|
|
311
|
+
children=prm_name,
|
|
312
|
+
id={'type': 'axis1-dropdown-menu-item', 'index': prm_name},
|
|
313
|
+
)
|
|
314
|
+
axis1_dropdown_items.append(dm_item_1)
|
|
315
|
+
|
|
316
|
+
dm_item_2 = dbc.DropdownMenuItem(
|
|
317
|
+
children=prm_name,
|
|
318
|
+
id={'type': 'axis2-dropdown-menu-item', 'index': prm_name},
|
|
319
|
+
)
|
|
320
|
+
axis2_dropdown_items.append(dm_item_2)
|
|
321
|
+
axis3_dropdown_items = []
|
|
322
|
+
for i, obj_name in enumerate(self.application.history.obj_names):
|
|
323
|
+
dm_item = dbc.DropdownMenuItem(
|
|
324
|
+
children=obj_name,
|
|
325
|
+
id={'type': 'axis3-dropdown-menu-item', 'index': obj_name},
|
|
326
|
+
)
|
|
327
|
+
axis3_dropdown_items.append(dm_item)
|
|
328
|
+
|
|
329
|
+
# add sliders
|
|
330
|
+
sliders = []
|
|
331
|
+
slider_values = {}
|
|
332
|
+
for prm_name in self.application.history.prm_names:
|
|
333
|
+
# get ub and lb
|
|
334
|
+
lb_column = prm_name + '_lower_bound'
|
|
335
|
+
ub_column = prm_name + '_upper_bound'
|
|
336
|
+
# get minimum lb and maximum ub
|
|
337
|
+
df = self.data_accessor()
|
|
338
|
+
lb = df[lb_column].min()
|
|
339
|
+
ub = df[ub_column].max()
|
|
340
|
+
# if lb or ub is not specified, use value instead
|
|
341
|
+
lb = df[prm_name].min() if np.isnan(lb) else lb
|
|
342
|
+
ub = df[prm_name].max() if np.isnan(ub) else ub
|
|
343
|
+
# create slider
|
|
344
|
+
value = (lb + ub) / 2
|
|
345
|
+
slider_values.update({prm_name: value})
|
|
346
|
+
stack = dbc.Stack(
|
|
347
|
+
id={'type': 'prm-slider-stack', 'index': prm_name},
|
|
348
|
+
style={'display': 'inline'},
|
|
349
|
+
children=[
|
|
350
|
+
html.Div(f'{prm_name}: '),
|
|
351
|
+
dcc.Slider(
|
|
352
|
+
lb,
|
|
353
|
+
ub,
|
|
354
|
+
marks=None,
|
|
355
|
+
value=value,
|
|
356
|
+
id={'type': 'prm-slider', 'index': prm_name},
|
|
357
|
+
tooltip={"placement": "bottom", "always_visible": True},
|
|
358
|
+
)
|
|
359
|
+
]
|
|
360
|
+
)
|
|
361
|
+
sliders.append(stack)
|
|
362
|
+
|
|
363
|
+
return axis1_dropdown_items, axis2_dropdown_items, axis3_dropdown_items, sliders, slider_values
|
|
364
|
+
|
|
365
|
+
# ===== control dropdown and slider visibility =====
|
|
366
|
+
@app.callback(
|
|
367
|
+
Output(self.axis1_prm_dropdown, 'label'), # label of dropdown
|
|
368
|
+
Output(self.axis2_prm_dropdown, 'label'),
|
|
369
|
+
Output(self.axis3_obj_dropdown, 'label'),
|
|
370
|
+
Output({'type': 'prm-slider-stack', 'index': ALL}, 'style'), # visibility of slider
|
|
371
|
+
Output('prm-axis-2-dropdown', 'hidden'),
|
|
372
|
+
Input({'type': 'axis1-dropdown-menu-item', 'index': ALL}, 'n_clicks'), # when the dropdown item is clicked
|
|
373
|
+
Input({'type': 'axis2-dropdown-menu-item', 'index': ALL}, 'n_clicks'),
|
|
374
|
+
Input({'type': 'axis3-dropdown-menu-item', 'index': ALL}, 'n_clicks'),
|
|
375
|
+
Input(self.axis1_prm_dropdown, 'children'), # for callback chain timing
|
|
376
|
+
State(self.axis1_prm_dropdown, 'label'),
|
|
377
|
+
State(self.axis2_prm_dropdown, 'label'),
|
|
378
|
+
State(self.axis3_obj_dropdown, 'label'),
|
|
379
|
+
State({'type': 'prm-slider-stack', 'index': ALL}, 'style'), # visibility of slider
|
|
380
|
+
prevent_initial_call=True,
|
|
381
|
+
)
|
|
382
|
+
def update_controller(*args):
|
|
383
|
+
# argument processing
|
|
384
|
+
current_ax1_label = args[4]
|
|
385
|
+
current_ax2_label = args[5]
|
|
386
|
+
current_ax3_label = args[6]
|
|
387
|
+
current_styles: list[dict] = args[7]
|
|
388
|
+
|
|
389
|
+
# just in case
|
|
390
|
+
if callback_context.triggered_id is None:
|
|
391
|
+
raise PreventUpdate
|
|
392
|
+
|
|
393
|
+
# load history
|
|
394
|
+
if self.application.history is None:
|
|
395
|
+
logger.error(Msg.ERR_NO_HISTORY_SELECTED)
|
|
396
|
+
raise PreventUpdate
|
|
397
|
+
prm_names = self.application.history.prm_names
|
|
398
|
+
obj_names = self.application.history.obj_names
|
|
399
|
+
|
|
400
|
+
# default return values
|
|
401
|
+
ret = {
|
|
402
|
+
(ax1_label_key := 1): no_update,
|
|
403
|
+
(ax2_label_key := 2): no_update,
|
|
404
|
+
(ax3_label_key := 3): no_update,
|
|
405
|
+
(slider_style_list_key := 4): [(style.update({'display': 'inline'}), style)[1] for style in current_styles],
|
|
406
|
+
(ax2_hidden := 5): False,
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
# ===== hide dropdown of axis 2 if prm number is 1 =====
|
|
410
|
+
if len(prm_names) < 2:
|
|
411
|
+
ret[ax2_hidden] = True
|
|
412
|
+
|
|
413
|
+
# ===== update dropdown label =====
|
|
414
|
+
|
|
415
|
+
# by callback chain on loaded after setup_dropdown_and_sliders()
|
|
416
|
+
if callback_context.triggered_id == self.axis1_prm_dropdown.id:
|
|
417
|
+
ret[ax1_label_key] = prm_names[0]
|
|
418
|
+
ret[ax2_label_key] = prm_names[1] if len(prm_names) >= 2 else ''
|
|
419
|
+
ret[ax3_label_key] = obj_names[0]
|
|
420
|
+
|
|
421
|
+
# by dropdown clicked
|
|
422
|
+
elif isinstance(callback_context.triggered_id, dict):
|
|
423
|
+
# example of triggerd_id: {'index': 'd', 'type': 'axis1-dropdown-menu-item'}
|
|
424
|
+
new_label = callback_context.triggered_id['index']
|
|
425
|
+
|
|
426
|
+
# ax1
|
|
427
|
+
if callback_context.triggered_id['type'] == 'axis1-dropdown-menu-item':
|
|
428
|
+
if new_label != current_ax2_label:
|
|
429
|
+
ret[ax1_label_key] = new_label
|
|
430
|
+
else:
|
|
431
|
+
logger.error(Msg.ERR_CANNOT_SELECT_SAME_PARAMETER)
|
|
432
|
+
|
|
433
|
+
# ax2
|
|
434
|
+
elif callback_context.triggered_id['type'] == 'axis2-dropdown-menu-item':
|
|
435
|
+
if new_label != current_ax1_label:
|
|
436
|
+
ret[ax2_label_key] = new_label
|
|
437
|
+
else:
|
|
438
|
+
logger.error(Msg.ERR_CANNOT_SELECT_SAME_PARAMETER)
|
|
439
|
+
|
|
440
|
+
# ax3
|
|
441
|
+
elif callback_context.triggered_id['type'] == 'axis3-dropdown-menu-item':
|
|
442
|
+
ret[ax3_label_key] = new_label
|
|
443
|
+
|
|
444
|
+
# ===== update visibility of sliders =====
|
|
445
|
+
for label_key, current_label in zip((ax1_label_key, ax2_label_key), (current_ax1_label, current_ax2_label)):
|
|
446
|
+
# get label of output
|
|
447
|
+
label = ret[label_key] if ret[label_key] != no_update else current_label
|
|
448
|
+
# update display style of slider
|
|
449
|
+
idx = prm_names.index(label) if label in prm_names else None
|
|
450
|
+
if idx is not None:
|
|
451
|
+
current_styles[idx].update({'display': 'none'})
|
|
452
|
+
ret[slider_style_list_key][idx] = current_styles[idx]
|
|
453
|
+
|
|
454
|
+
return tuple(ret.values())
|
|
455
|
+
|
|
456
|
+
# # # ===== update axis1-prm-dropdown =====
|
|
457
|
+
# # @app.callback(
|
|
458
|
+
# # Output(self.axis1_prm_dropdown, 'label', allow_duplicate=True),
|
|
459
|
+
# # Input(self.location, self.location.Prop.pathname),
|
|
460
|
+
# # [Input(item, 'n_clicks') for item in self.prm1_items],
|
|
461
|
+
# # State(self.axis2_prm_dropdown, 'label'),
|
|
462
|
+
# # prevent_initial_call=True,
|
|
463
|
+
# # )
|
|
464
|
+
# # def update_prm1_dropdown_menu_label(*args):
|
|
465
|
+
# # prm2_label = args[-1]
|
|
466
|
+
# #
|
|
467
|
+
# # # 一応
|
|
468
|
+
# # if callback_context.triggered_id is None:
|
|
469
|
+
# # raise PreventUpdate
|
|
470
|
+
# #
|
|
471
|
+
# # # load history
|
|
472
|
+
# # if self.application.history is None:
|
|
473
|
+
# # return 'History is not selected.'
|
|
474
|
+
# # prm_names = self.application.history.prm_names
|
|
475
|
+
# #
|
|
476
|
+
# # # 1st parameter on loaded
|
|
477
|
+
# # if callback_context.triggered_id == self.location.id:
|
|
478
|
+
# # return prm_names[0]
|
|
479
|
+
# #
|
|
480
|
+
# # # clicked
|
|
481
|
+
# # for i, item in enumerate(self.prm1_items):
|
|
482
|
+
# # if item.id == callback_context.triggered_id:
|
|
483
|
+
# # if prm_names[i] != prm2_label:
|
|
484
|
+
# # return prm_names[i]
|
|
485
|
+
# # else:
|
|
486
|
+
# # logger.error('Cannot select same parameter')
|
|
487
|
+
# # raise PreventUpdate
|
|
488
|
+
# #
|
|
489
|
+
# # # something wrong
|
|
490
|
+
# # # logger.debug('something wrong in `update_dropdown_menu_label`')
|
|
491
|
+
# # raise PreventUpdate
|
|
492
|
+
# #
|
|
493
|
+
# # # ===== update axis2-prm-dropdown =====
|
|
494
|
+
# # @app.callback(
|
|
495
|
+
# # Output(self.axis2_prm_dropdown, 'label', allow_duplicate=True),
|
|
496
|
+
# # Output(self.axis2_prm_dropdown, 'hidden', allow_duplicate=True),
|
|
497
|
+
# # Input(self.location, self.location.Prop.pathname),
|
|
498
|
+
# # [Input(item, 'n_clicks') for item in self.prm2_items],
|
|
499
|
+
# # State(self.axis1_prm_dropdown, 'label'),
|
|
500
|
+
# # prevent_initial_call=True,
|
|
501
|
+
# # )
|
|
502
|
+
# # def update_prm2_dropdown_menu_label(*args):
|
|
503
|
+
# # prm1_label = args[-1]
|
|
504
|
+
# #
|
|
505
|
+
# # # 一応
|
|
506
|
+
# # if callback_context.triggered_id is None:
|
|
507
|
+
# # raise PreventUpdate
|
|
508
|
+
# #
|
|
509
|
+
# # # load history
|
|
510
|
+
# # if self.application.history is None:
|
|
511
|
+
# # return 'History is not selected.', no_update
|
|
512
|
+
# # prm_names = self.application.history.prm_names
|
|
513
|
+
# #
|
|
514
|
+
# # # disable axis2 if only 1 parameter optimization
|
|
515
|
+
# # if len(prm_names) == 1:
|
|
516
|
+
# # return no_update, True
|
|
517
|
+
# #
|
|
518
|
+
# # # 2nd parameter on loaded
|
|
519
|
+
# # if callback_context.triggered_id == self.location.id:
|
|
520
|
+
# # return prm_names[1], False
|
|
521
|
+
# #
|
|
522
|
+
# # # clicked
|
|
523
|
+
# # for i, item in enumerate(self.prm2_items):
|
|
524
|
+
# # if item.id == callback_context.triggered_id:
|
|
525
|
+
# # if prm_names[i] != prm1_label:
|
|
526
|
+
# # return prm_names[i], False
|
|
527
|
+
# # else:
|
|
528
|
+
# # logger.error('Cannot select same parameter')
|
|
529
|
+
# # raise PreventUpdate
|
|
530
|
+
# #
|
|
531
|
+
# # # something wrong
|
|
532
|
+
# # # logger.debug('something wrong in `update_dropdown_menu_label`')
|
|
533
|
+
# # raise PreventUpdate
|
|
534
|
+
# #
|
|
535
|
+
# # # ===== update axis3-obj-dropdown =====
|
|
536
|
+
# # @app.callback(
|
|
537
|
+
# # Output(self.axis3_obj_dropdown, 'label', allow_duplicate=True),
|
|
538
|
+
# # Input(self.location, self.location.Prop.pathname),
|
|
539
|
+
# # [Input(item, 'n_clicks') for item in self.obj_items],
|
|
540
|
+
# # prevent_initial_call=True,
|
|
541
|
+
# # )
|
|
542
|
+
# # def update_obj_dropdown_menu_label(*args):
|
|
543
|
+
# # # 一応
|
|
544
|
+
# # if callback_context.triggered_id is None:
|
|
545
|
+
# # raise PreventUpdate
|
|
546
|
+
# #
|
|
547
|
+
# # if self.application.history is None:
|
|
548
|
+
# # return 'History is not selected.'
|
|
549
|
+
# #
|
|
550
|
+
# # obj_names = self.application.history.obj_names
|
|
551
|
+
# #
|
|
552
|
+
# # # 1st objective on loaded
|
|
553
|
+
# # if callback_context.triggered_id == self.location.id:
|
|
554
|
+
# # return obj_names[0]
|
|
555
|
+
# #
|
|
556
|
+
# # # clicked
|
|
557
|
+
# # for i, item in enumerate(self.obj_items):
|
|
558
|
+
# # if item.id == callback_context.triggered_id:
|
|
559
|
+
# # return obj_names[i]
|
|
560
|
+
# #
|
|
561
|
+
# # # something wrong
|
|
562
|
+
# # # logger.debug('something wrong in `update_dropdown_menu_label`')
|
|
563
|
+
# # raise PreventUpdate
|
|
564
|
+
#
|
|
565
|
+
# # ===== setup sliders =====
|
|
566
|
+
# @app.callback(
|
|
567
|
+
# Output(self.slider_container, 'children'),
|
|
568
|
+
# Output(self.slider_stack_data, self.slider_stack_data_prop),
|
|
569
|
+
# Input(self.location, self.location.Prop.pathname),
|
|
570
|
+
# Input(self.axis1_prm_dropdown, 'label'),
|
|
571
|
+
# Input(self.axis2_prm_dropdown, 'label'),
|
|
572
|
+
# State(self.slider_stack_data, self.slider_stack_data_prop),
|
|
573
|
+
# prevent_initial_call=True,
|
|
574
|
+
# )
|
|
575
|
+
# def update_sliders(_, label1, label2, slider_values):
|
|
576
|
+
# # Just in case
|
|
577
|
+
# if callback_context.triggered_id is None:
|
|
578
|
+
# raise PreventUpdate
|
|
579
|
+
#
|
|
580
|
+
# # load history
|
|
581
|
+
# if self.application.history is None:
|
|
582
|
+
# return 'History is not selected.', no_update
|
|
583
|
+
# prm_names: list = list(self.application.history.prm_names) # shallow copy
|
|
584
|
+
#
|
|
585
|
+
# prm_names.remove(label1) if label1 in prm_names else None
|
|
586
|
+
# prm_names.remove(label2) if label2 in prm_names else None
|
|
587
|
+
#
|
|
588
|
+
# out = []
|
|
589
|
+
# for prm_name in prm_names:
|
|
590
|
+
# # get ub and lb
|
|
591
|
+
# lb_column = prm_name + '_lower_bound'
|
|
592
|
+
# ub_column = prm_name + '_upper_bound'
|
|
593
|
+
# # get minimum lb and maximum ub
|
|
594
|
+
# df = self.data_accessor()
|
|
595
|
+
# lb = df[lb_column].min()
|
|
596
|
+
# ub = df[ub_column].max()
|
|
597
|
+
# # if lb or ub is not specified, use value instead
|
|
598
|
+
# lb = df[prm_name].min() if np.isnan(lb) else lb
|
|
599
|
+
# ub = df[prm_name].max() if np.isnan(ub) else ub
|
|
600
|
+
# # create slider
|
|
601
|
+
# if prm_name in slider_values.keys():
|
|
602
|
+
# value = slider_values[prm_name]
|
|
603
|
+
# print('-----')
|
|
604
|
+
# print(slider_values)
|
|
605
|
+
# else:
|
|
606
|
+
# value = (lb + ub) / 2
|
|
607
|
+
# slider_values.update({'value': value})
|
|
608
|
+
# print('ooooo')
|
|
609
|
+
# print(lb, ub)
|
|
610
|
+
# print('=====')
|
|
611
|
+
# print(value)
|
|
612
|
+
# stack = dbc.Stack(
|
|
613
|
+
# children=[
|
|
614
|
+
# html.Div(f'{prm_name}: '),
|
|
615
|
+
# dcc.Slider(
|
|
616
|
+
# lb,
|
|
617
|
+
# ub,
|
|
618
|
+
# marks=None,
|
|
619
|
+
# value=value,
|
|
620
|
+
# id={'type': f'prm-slider', 'index': prm_name},
|
|
621
|
+
# tooltip={"placement": "bottom", "always_visible": True},
|
|
622
|
+
# )
|
|
623
|
+
# ]
|
|
624
|
+
# )
|
|
625
|
+
# out.append(stack)
|
|
626
|
+
#
|
|
627
|
+
# return out, slider_values
|
|
628
|
+
#
|
|
629
|
+
# # ===== update slider values =====
|
|
630
|
+
# @app.callback(
|
|
631
|
+
# Output(self.slider_stack_data, self.slider_stack_data_prop, allow_duplicate=True),
|
|
632
|
+
# Input([{'type': 'prm-slider', 'index': prm_name}, 'value') ],
|
|
633
|
+
# prevent_initial_call=True,
|
|
634
|
+
# )
|
|
635
|
+
# def update_slider_values(values):
|
|
636
|
+
# # Just in case
|
|
637
|
+
# if callback_context.triggered_id is None:
|
|
638
|
+
# raise PreventUpdate
|
|
639
|
+
#
|
|
640
|
+
# # load history
|
|
641
|
+
# if self.application.history is None:
|
|
642
|
+
# return 'History is not selected.', no_update
|
|
643
|
+
# prm_names = self.application.history.prm_names
|
|
644
|
+
#
|
|
645
|
+
# print('==========')
|
|
646
|
+
# print(callback_context.triggered_id)
|
|
647
|
+
# print(callback_context.triggered_prop_ids)
|
|
648
|
+
# print(callback_context.triggered)
|
|
649
|
+
# print(values)
|
|
650
|
+
# float = callback_context.triggered[0]['value'][0]
|
|
651
|
+
#
|
|
652
|
+
# return {}
|
|
653
|
+
|
|
654
|
+
def create_formatted_parameter(self, row) -> Component:
|
|
655
|
+
metadata = self.application.history.metadata
|
|
656
|
+
pd.options.display.float_format = '{:.4e}'.format
|
|
657
|
+
parameters = row.iloc[:, np.where(np.array(metadata) == 'prm')[0]]
|
|
658
|
+
names = parameters.columns
|
|
659
|
+
values = [f'{value:.3e}' for value in parameters.values.ravel()]
|
|
660
|
+
data = pd.DataFrame(dict(
|
|
661
|
+
name=names, value=values
|
|
662
|
+
))
|
|
663
|
+
table = dash_table.DataTable(
|
|
664
|
+
columns=[{'name': col, 'id': col} for col in data.columns],
|
|
665
|
+
data=data.to_dict('records')
|
|
666
|
+
)
|
|
667
|
+
return table
|
|
668
|
+
|
|
669
|
+
def create_image_content_if_femtet(self, trial) -> Component:
|
|
670
|
+
img_url = None
|
|
671
|
+
metadata = self.application.history.metadata
|
|
672
|
+
if metadata[0] != '':
|
|
673
|
+
# get img path
|
|
674
|
+
d = json.loads(metadata[0])
|
|
675
|
+
femprj_path = d['femprj_path']
|
|
676
|
+
model_name = d['model_name']
|
|
677
|
+
femprj_result_dir = femprj_path.replace('.femprj', '.Results')
|
|
678
|
+
img_path = os.path.join(femprj_result_dir, f'{model_name}_trial{trial}.jpg')
|
|
679
|
+
if os.path.exists(img_path):
|
|
680
|
+
# create encoded image
|
|
681
|
+
with open(img_path, 'rb') as f:
|
|
682
|
+
content = f.read()
|
|
683
|
+
encoded_image = base64.b64encode(content).decode('utf-8')
|
|
684
|
+
img_url = 'data:image/jpeg;base64, ' + encoded_image
|
|
685
|
+
return html.Img(src=img_url, style={"width": "200px"}) if img_url is not None else html.Div()
|
|
686
|
+
|
|
687
|
+
# def get_fig_by_tab_id(self, tab_id, with_length=False):
|
|
688
|
+
# # If the history is not loaded, do nothing
|
|
689
|
+
# if self.application.history is None:
|
|
690
|
+
# raise PreventUpdate
|
|
691
|
+
#
|
|
692
|
+
# # else, get creator by tab_id
|
|
693
|
+
# if tab_id == 'default':
|
|
694
|
+
# creator = self.figure_creators[0]['creator']
|
|
695
|
+
# else:
|
|
696
|
+
# creators = [d['creator'] for d in self.figure_creators if d['tab_id'] == tab_id]
|
|
697
|
+
# if len(creators) == 0:
|
|
698
|
+
# raise PreventUpdate
|
|
699
|
+
# creator = creators[0]
|
|
700
|
+
#
|
|
701
|
+
# # create figure
|
|
702
|
+
# df = self.data_accessor()
|
|
703
|
+
# fig = creator(self.application.history, df)
|
|
704
|
+
# if with_length:
|
|
705
|
+
# return fig, len(df)
|
|
706
|
+
# else:
|
|
707
|
+
# return fig
|
|
708
|
+
|
|
709
|
+
def data_accessor(self) -> pd.DataFrame:
|
|
710
|
+
from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
|
|
711
|
+
if isinstance(self.application, ProcessMonitorApplication):
|
|
712
|
+
df = self.application.local_data
|
|
713
|
+
else:
|
|
714
|
+
df = self.application.history.local_data
|
|
715
|
+
return df
|