steer-core 0.1.16__py3-none-any.whl → 0.1.18__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.
- steer_core/Apps/Components/MaterialSelectors.py +444 -302
- steer_core/Apps/Components/RangeSliderComponents.py +177 -125
- steer_core/Apps/Components/SliderComponents.py +206 -184
- steer_core/Apps/ContextManagers.py +26 -20
- steer_core/Apps/Performance/CallbackTimer.py +3 -2
- steer_core/Apps/Utils/SliderControls.py +239 -209
- steer_core/Constants/Units.py +6 -1
- steer_core/Data/database.db +0 -0
- steer_core/DataManager.py +123 -122
- steer_core/Decorators/Coordinates.py +9 -4
- steer_core/Decorators/Electrochemical.py +7 -2
- steer_core/Decorators/General.py +7 -4
- steer_core/Decorators/Objects.py +4 -1
- steer_core/Mixins/Colors.py +185 -1
- steer_core/Mixins/Coordinates.py +112 -89
- steer_core/Mixins/Data.py +1 -1
- steer_core/Mixins/Plotter.py +149 -0
- steer_core/Mixins/Serializer.py +5 -7
- steer_core/Mixins/TypeChecker.py +42 -29
- steer_core/__init__.py +1 -1
- {steer_core-0.1.16.dist-info → steer_core-0.1.18.dist-info}/METADATA +1 -1
- steer_core-0.1.18.dist-info/RECORD +34 -0
- steer_core-0.1.16.dist-info/RECORD +0 -33
- {steer_core-0.1.16.dist-info → steer_core-0.1.18.dist-info}/WHEEL +0 -0
- {steer_core-0.1.16.dist-info → steer_core-0.1.18.dist-info}/top_level.txt +0 -0
|
@@ -7,15 +7,15 @@ from .SliderComponents import SliderWithTextInput
|
|
|
7
7
|
class MaterialSelector:
|
|
8
8
|
"""
|
|
9
9
|
A custom Dash component that combines material selection controls in a horizontal layout.
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
This component creates a horizontal row containing:
|
|
12
12
|
- A dropdown menu for selecting material names
|
|
13
13
|
- An input box for specifying weight fraction of the material
|
|
14
14
|
- Two SliderWithTextInput components for specific cost and density
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
The component is designed for material composition interfaces where users need to
|
|
17
17
|
select materials and specify their properties and proportions.
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
Attributes:
|
|
20
20
|
id_base (dict): Base identifier dictionary used to construct unique IDs for child components
|
|
21
21
|
material_options (List[Dict]): List of material options for the dropdown
|
|
@@ -30,7 +30,7 @@ class MaterialSelector:
|
|
|
30
30
|
weight_fraction_id (dict): Computed ID for the weight fraction input
|
|
31
31
|
cost_slider (SliderWithTextInput): Cost slider component
|
|
32
32
|
density_slider (SliderWithTextInput): Density slider component
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
Example:
|
|
35
35
|
>>> material_selector = MaterialSelector(
|
|
36
36
|
... id_base={'type': 'material', 'index': 0},
|
|
@@ -74,12 +74,12 @@ class MaterialSelector:
|
|
|
74
74
|
default_material: str = None,
|
|
75
75
|
default_weight_percent: float = 0,
|
|
76
76
|
slider_disable: bool = False,
|
|
77
|
-
div_width: str =
|
|
77
|
+
div_width: str = "100%",
|
|
78
78
|
hidden: bool = False,
|
|
79
79
|
):
|
|
80
80
|
"""
|
|
81
81
|
Initialize the MaterialSelector component.
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
Args:
|
|
84
84
|
id_base (dict): Base dictionary for generating component IDs.
|
|
85
85
|
material_options (List[Dict], optional): List of material options for dropdown.
|
|
@@ -94,7 +94,7 @@ class MaterialSelector:
|
|
|
94
94
|
cost_config (dict, optional): Legacy cost slider configuration. Ignored if slider_config provided.
|
|
95
95
|
density_config (dict, optional): Legacy density slider configuration. Ignored if slider_config provided.
|
|
96
96
|
title (str, optional): Title displayed for the component. Defaults to "Material".
|
|
97
|
-
default_material (str, optional): Default selected material. If None, no material
|
|
97
|
+
default_material (str, optional): Default selected material. If None, no material
|
|
98
98
|
will be initially selected in the dropdown.
|
|
99
99
|
default_weight_percent (float, optional): Default weight percentage (0.0-100.0). Defaults to 100.0.
|
|
100
100
|
slider_disable (bool, optional): Whether to disable sliders. Defaults to False.
|
|
@@ -116,198 +116,208 @@ class MaterialSelector:
|
|
|
116
116
|
self.hidden = hidden
|
|
117
117
|
|
|
118
118
|
# Generate component IDs
|
|
119
|
-
self.dropdown_id = self._make_id(
|
|
120
|
-
self.weight_fraction_id = self._make_id(
|
|
119
|
+
self.dropdown_id = self._make_id("dropdown")
|
|
120
|
+
self.weight_fraction_id = self._make_id("weight_fraction")
|
|
121
121
|
|
|
122
122
|
# Normalize configurations to handle both legacy and create_slider_config formats
|
|
123
123
|
if slider_configs is not None and slider_configs: # Check if not empty
|
|
124
124
|
# Use slider_configs arrays (index 0 = density, index 1 = cost)
|
|
125
|
-
density_normalized = self._normalize_config_from_arrays(
|
|
126
|
-
|
|
125
|
+
density_normalized = self._normalize_config_from_arrays(
|
|
126
|
+
slider_configs, 0, "Density (g/cm³)"
|
|
127
|
+
)
|
|
128
|
+
cost_normalized = self._normalize_config_from_arrays(
|
|
129
|
+
slider_configs, 1, "Specific Cost ($/kg)"
|
|
130
|
+
)
|
|
127
131
|
elif slider_configs is not None and not slider_configs: # Empty dictionary
|
|
128
132
|
# Use sensible defaults for materials
|
|
129
133
|
density_normalized = {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
"min_val": 0.0,
|
|
135
|
+
"max_val": 0.1,
|
|
136
|
+
"step": 0.01,
|
|
137
|
+
"mark_interval": 0.1,
|
|
138
|
+
"title": "Density (g/cm³)",
|
|
139
|
+
"default_val": 0.05,
|
|
136
140
|
}
|
|
137
141
|
cost_normalized = {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
"min_val": 0.0,
|
|
143
|
+
"max_val": 0.1,
|
|
144
|
+
"step": 0.01,
|
|
145
|
+
"mark_interval": 0.1,
|
|
146
|
+
"title": "Specific Cost ($/kg)",
|
|
147
|
+
"default_val": 0.05,
|
|
144
148
|
}
|
|
145
149
|
else:
|
|
146
150
|
# slider_configs is None - use sensible defaults with None values
|
|
147
151
|
density_normalized = {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
"min_val": 0.0,
|
|
153
|
+
"max_val": 0.1,
|
|
154
|
+
"step": 0.01,
|
|
155
|
+
"mark_interval": 0.1,
|
|
156
|
+
"title": "Density (g/cm³)",
|
|
157
|
+
"default_val": None, # No initial value
|
|
154
158
|
}
|
|
155
159
|
cost_normalized = {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
"min_val": 0.0,
|
|
161
|
+
"max_val": 0.1,
|
|
162
|
+
"step": 0.01,
|
|
163
|
+
"mark_interval": 0.1,
|
|
164
|
+
"title": "Specific Cost ($/kg)",
|
|
165
|
+
"default_val": None, # No initial value
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
# Create slider components
|
|
165
169
|
cost_slider_kwargs = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
"id_base": id_base,
|
|
171
|
+
"min_val": cost_normalized["min_val"],
|
|
172
|
+
"max_val": cost_normalized["max_val"],
|
|
173
|
+
"step": cost_normalized["step"],
|
|
174
|
+
"mark_interval": cost_normalized["mark_interval"],
|
|
175
|
+
"property_name": "specific_cost",
|
|
176
|
+
"title": cost_normalized["title"],
|
|
177
|
+
"default_val": cost_normalized.get(
|
|
178
|
+
"default_val", cost_normalized["min_val"]
|
|
179
|
+
),
|
|
180
|
+
"with_slider_titles": True,
|
|
181
|
+
"slider_disable": slider_disable,
|
|
182
|
+
"div_width": "100%",
|
|
177
183
|
}
|
|
178
184
|
# Add marks if available
|
|
179
|
-
if
|
|
180
|
-
cost_slider_kwargs[
|
|
181
|
-
|
|
185
|
+
if "marks" in cost_normalized:
|
|
186
|
+
cost_slider_kwargs["marks"] = cost_normalized["marks"]
|
|
187
|
+
|
|
182
188
|
self.cost_slider = SliderWithTextInput(**cost_slider_kwargs)
|
|
183
189
|
|
|
184
190
|
density_slider_kwargs = {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
191
|
+
"id_base": id_base,
|
|
192
|
+
"min_val": density_normalized["min_val"],
|
|
193
|
+
"max_val": density_normalized["max_val"],
|
|
194
|
+
"step": density_normalized["step"],
|
|
195
|
+
"mark_interval": density_normalized["mark_interval"],
|
|
196
|
+
"property_name": "density",
|
|
197
|
+
"title": density_normalized["title"],
|
|
198
|
+
"default_val": density_normalized.get(
|
|
199
|
+
"default_val", density_normalized["min_val"]
|
|
200
|
+
),
|
|
201
|
+
"with_slider_titles": True,
|
|
202
|
+
"slider_disable": slider_disable,
|
|
203
|
+
"div_width": "100%",
|
|
196
204
|
}
|
|
197
205
|
# Add marks if available
|
|
198
|
-
if
|
|
199
|
-
density_slider_kwargs[
|
|
200
|
-
|
|
206
|
+
if "marks" in density_normalized:
|
|
207
|
+
density_slider_kwargs["marks"] = density_normalized["marks"]
|
|
208
|
+
|
|
201
209
|
self.density_slider = SliderWithTextInput(**density_slider_kwargs)
|
|
202
210
|
|
|
203
|
-
def _normalize_config_from_arrays(
|
|
211
|
+
def _normalize_config_from_arrays(
|
|
212
|
+
self, config: dict, index: int, default_title: str
|
|
213
|
+
) -> dict:
|
|
204
214
|
"""
|
|
205
215
|
Normalize slider configuration from create_slider_config output arrays.
|
|
206
|
-
|
|
216
|
+
|
|
207
217
|
Args:
|
|
208
218
|
config (dict): create_slider_config output with array values
|
|
209
219
|
index (int): Index to extract from each array (0 = density, 1 = cost)
|
|
210
220
|
default_title (str): Default title if not provided
|
|
211
|
-
|
|
221
|
+
|
|
212
222
|
Returns:
|
|
213
223
|
dict: Normalized configuration with min_val, max_val, step, mark_interval, title keys
|
|
214
224
|
"""
|
|
215
225
|
normalized = {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
"min_val": config["min_vals"][index],
|
|
227
|
+
"max_val": config["max_vals"][index],
|
|
228
|
+
"step": config["step_vals"][index],
|
|
229
|
+
"title": default_title, # Use provided title
|
|
220
230
|
}
|
|
221
|
-
|
|
231
|
+
|
|
222
232
|
# Get pre-computed marks if available, otherwise calculate mark_interval
|
|
223
|
-
if
|
|
224
|
-
marks = config[
|
|
225
|
-
normalized[
|
|
233
|
+
if "mark_vals" in config and len(config["mark_vals"]) > index:
|
|
234
|
+
marks = config["mark_vals"][index]
|
|
235
|
+
normalized["marks"] = marks # Pass the actual marks dictionary
|
|
226
236
|
if len(marks) >= 2:
|
|
227
237
|
# Calculate interval from first two marks
|
|
228
238
|
mark_positions = sorted(marks.keys())
|
|
229
|
-
normalized[
|
|
239
|
+
normalized["mark_interval"] = mark_positions[1] - mark_positions[0]
|
|
230
240
|
else:
|
|
231
241
|
# Fallback: use step as mark interval
|
|
232
|
-
normalized[
|
|
242
|
+
normalized["mark_interval"] = normalized["step"]
|
|
233
243
|
else:
|
|
234
|
-
normalized[
|
|
235
|
-
|
|
244
|
+
normalized["mark_interval"] = normalized["step"]
|
|
245
|
+
|
|
236
246
|
# Add default value if available from grid values
|
|
237
|
-
if
|
|
238
|
-
normalized[
|
|
247
|
+
if "grid_slider_vals" in config and len(config["grid_slider_vals"]) > index:
|
|
248
|
+
normalized["default_val"] = config["grid_slider_vals"][index]
|
|
239
249
|
else:
|
|
240
|
-
normalized[
|
|
241
|
-
|
|
250
|
+
normalized["default_val"] = normalized["min_val"]
|
|
251
|
+
|
|
242
252
|
return normalized
|
|
243
253
|
|
|
244
254
|
def _normalize_config(self, config: dict, config_type: str) -> dict:
|
|
245
255
|
"""
|
|
246
256
|
Normalize slider configuration to handle both legacy and create_slider_config formats.
|
|
247
|
-
|
|
257
|
+
|
|
248
258
|
Args:
|
|
249
259
|
config (dict): Either legacy format or create_slider_config output
|
|
250
260
|
config_type (str): Type identifier ('cost' or 'density') for default title
|
|
251
|
-
|
|
261
|
+
|
|
252
262
|
Returns:
|
|
253
263
|
dict: Normalized configuration with min_val, max_val, step, mark_interval, title keys
|
|
254
264
|
"""
|
|
255
265
|
# Check if this is a create_slider_config output (has min_vals, max_vals, etc.)
|
|
256
|
-
if
|
|
266
|
+
if "min_vals" in config and "max_vals" in config:
|
|
257
267
|
# This is create_slider_config output - use first element from arrays
|
|
258
268
|
normalized = {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
269
|
+
"min_val": config["min_vals"][0],
|
|
270
|
+
"max_val": config["max_vals"][0],
|
|
271
|
+
"step": config["step_vals"][0],
|
|
272
|
+
"title": config_type.capitalize(), # Default title
|
|
263
273
|
}
|
|
264
|
-
|
|
274
|
+
|
|
265
275
|
# Get pre-computed marks if available, otherwise calculate mark_interval
|
|
266
|
-
if
|
|
267
|
-
marks = config[
|
|
268
|
-
normalized[
|
|
276
|
+
if "mark_vals" in config and len(config["mark_vals"]) > 0:
|
|
277
|
+
marks = config["mark_vals"][0]
|
|
278
|
+
normalized["marks"] = marks # Pass the actual marks dictionary
|
|
269
279
|
if len(marks) >= 2:
|
|
270
280
|
# Calculate interval from first two marks
|
|
271
281
|
mark_positions = sorted(marks.keys())
|
|
272
|
-
normalized[
|
|
282
|
+
normalized["mark_interval"] = mark_positions[1] - mark_positions[0]
|
|
273
283
|
else:
|
|
274
284
|
# Fallback: use step as mark interval
|
|
275
|
-
normalized[
|
|
285
|
+
normalized["mark_interval"] = normalized["step"]
|
|
276
286
|
else:
|
|
277
|
-
normalized[
|
|
278
|
-
|
|
287
|
+
normalized["mark_interval"] = normalized["step"]
|
|
288
|
+
|
|
279
289
|
# Add default value if available from grid values
|
|
280
|
-
if
|
|
281
|
-
normalized[
|
|
290
|
+
if "grid_slider_vals" in config and len(config["grid_slider_vals"]) > 0:
|
|
291
|
+
normalized["default_val"] = config["grid_slider_vals"][0]
|
|
282
292
|
else:
|
|
283
|
-
normalized[
|
|
284
|
-
|
|
293
|
+
normalized["default_val"] = normalized["min_val"]
|
|
294
|
+
|
|
285
295
|
else:
|
|
286
296
|
# This is legacy format - use as-is but ensure all required keys exist
|
|
287
297
|
normalized = config.copy()
|
|
288
|
-
if
|
|
289
|
-
normalized[
|
|
290
|
-
if
|
|
291
|
-
normalized[
|
|
292
|
-
|
|
298
|
+
if "title" not in normalized:
|
|
299
|
+
normalized["title"] = config_type.capitalize()
|
|
300
|
+
if "default_val" not in normalized:
|
|
301
|
+
normalized["default_val"] = normalized.get("min_val", 0)
|
|
302
|
+
|
|
293
303
|
return normalized
|
|
294
304
|
|
|
295
305
|
def _make_id(self, subtype: str):
|
|
296
306
|
"""
|
|
297
307
|
Generate a unique ID dictionary for component sub-elements.
|
|
298
|
-
|
|
308
|
+
|
|
299
309
|
Args:
|
|
300
310
|
subtype (str): The specific component subtype.
|
|
301
|
-
|
|
311
|
+
|
|
302
312
|
Returns:
|
|
303
313
|
dict: Complete ID dictionary containing base ID information plus subtype.
|
|
304
314
|
"""
|
|
305
|
-
return {**self.id_base,
|
|
315
|
+
return {**self.id_base, "subtype": subtype}
|
|
306
316
|
|
|
307
317
|
def _make_dropdown(self):
|
|
308
318
|
"""
|
|
309
319
|
Create and configure the material selection dropdown.
|
|
310
|
-
|
|
320
|
+
|
|
311
321
|
Returns:
|
|
312
322
|
dash.dcc.Dropdown: Configured dropdown component for material selection.
|
|
313
323
|
"""
|
|
@@ -316,131 +326,175 @@ class MaterialSelector:
|
|
|
316
326
|
options=self.material_options,
|
|
317
327
|
value=self.default_material, # Can be None for no initial selection
|
|
318
328
|
disabled=self.slider_disable,
|
|
319
|
-
style={
|
|
329
|
+
style={"width": "100%", "margin-bottom": "10px"},
|
|
320
330
|
)
|
|
321
331
|
|
|
322
332
|
def _make_weight_fraction_input(self):
|
|
323
333
|
"""
|
|
324
334
|
Create and configure the weight percentage input.
|
|
325
|
-
|
|
335
|
+
|
|
326
336
|
Returns:
|
|
327
337
|
dash.dcc.Input: Configured numeric input for weight percentage.
|
|
328
338
|
"""
|
|
329
339
|
return dcc.Input(
|
|
330
340
|
id=self.weight_fraction_id,
|
|
331
|
-
type=
|
|
341
|
+
type="number",
|
|
332
342
|
value=self.default_weight_percent, # Use percentage directly
|
|
333
343
|
min=0.0,
|
|
334
344
|
max=100.0,
|
|
335
345
|
step=0.1,
|
|
336
346
|
disabled=self.slider_disable,
|
|
337
|
-
style={
|
|
347
|
+
style={"width": "100%", "margin-bottom": "10px"},
|
|
338
348
|
)
|
|
339
349
|
|
|
340
350
|
def __call__(self):
|
|
341
351
|
"""
|
|
342
352
|
Generate the complete component layout as a callable object.
|
|
343
|
-
|
|
353
|
+
|
|
344
354
|
Creates and returns a Dash HTML Div containing all components arranged
|
|
345
355
|
in a horizontal layout with proper spacing and styling.
|
|
346
|
-
|
|
356
|
+
|
|
347
357
|
Returns:
|
|
348
358
|
dash.html.Div: Complete component layout with horizontal arrangement.
|
|
349
359
|
"""
|
|
350
|
-
return html.Div(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
360
|
+
return html.Div(
|
|
361
|
+
[
|
|
362
|
+
# Main horizontal layout
|
|
363
|
+
html.Div(
|
|
364
|
+
[
|
|
365
|
+
# Material selection column
|
|
366
|
+
html.Div(
|
|
367
|
+
[
|
|
368
|
+
html.P(
|
|
369
|
+
"Material:",
|
|
370
|
+
style={
|
|
371
|
+
"margin": "0px 0px 5px 0px",
|
|
372
|
+
"font-weight": "bold",
|
|
373
|
+
},
|
|
374
|
+
),
|
|
375
|
+
self._make_dropdown(),
|
|
376
|
+
],
|
|
377
|
+
style={
|
|
378
|
+
"width": "20%",
|
|
379
|
+
"display": "inline-block",
|
|
380
|
+
"vertical-align": "top",
|
|
381
|
+
"padding-right": "25px",
|
|
382
|
+
},
|
|
383
|
+
),
|
|
384
|
+
# Weight percentage column
|
|
385
|
+
html.Div(
|
|
386
|
+
[
|
|
387
|
+
html.P(
|
|
388
|
+
"Weight (%):",
|
|
389
|
+
style={
|
|
390
|
+
"margin": "0px 0px 5px 0px",
|
|
391
|
+
"font-weight": "bold",
|
|
392
|
+
},
|
|
393
|
+
),
|
|
394
|
+
self._make_weight_fraction_input(),
|
|
395
|
+
],
|
|
396
|
+
style={
|
|
397
|
+
"width": "15%",
|
|
398
|
+
"display": "inline-block",
|
|
399
|
+
"vertical-align": "top",
|
|
400
|
+
"padding-right": "25px",
|
|
401
|
+
},
|
|
402
|
+
),
|
|
403
|
+
# Density slider column
|
|
404
|
+
html.Div(
|
|
405
|
+
[self.density_slider()],
|
|
406
|
+
style={
|
|
407
|
+
"width": "30%",
|
|
408
|
+
"display": "inline-block",
|
|
409
|
+
"vertical-align": "top",
|
|
410
|
+
"padding-right": "25px",
|
|
411
|
+
},
|
|
412
|
+
),
|
|
413
|
+
# Cost slider column
|
|
414
|
+
html.Div(
|
|
415
|
+
[self.cost_slider()],
|
|
416
|
+
style={
|
|
417
|
+
"width": "30%",
|
|
418
|
+
"display": "inline-block",
|
|
419
|
+
"vertical-align": "top",
|
|
420
|
+
},
|
|
421
|
+
),
|
|
422
|
+
],
|
|
423
|
+
style={
|
|
424
|
+
"display": "flex",
|
|
425
|
+
"align-items": "flex-start",
|
|
426
|
+
"width": "100%",
|
|
427
|
+
"gap": "15px",
|
|
428
|
+
},
|
|
429
|
+
)
|
|
430
|
+
],
|
|
431
|
+
id=self.id_base,
|
|
432
|
+
style={
|
|
433
|
+
"border": "1px solid #ddd",
|
|
434
|
+
"border-radius": "5px",
|
|
435
|
+
"padding": "15px",
|
|
436
|
+
"margin": "10px 0px",
|
|
437
|
+
"background-color": "#f9f9f9",
|
|
438
|
+
"width": self.div_width,
|
|
439
|
+
"display": "none" if self.hidden else "block",
|
|
440
|
+
},
|
|
441
|
+
)
|
|
388
442
|
|
|
389
443
|
@property
|
|
390
444
|
def components(self):
|
|
391
445
|
"""
|
|
392
446
|
Get a dictionary mapping component types to their IDs.
|
|
393
|
-
|
|
447
|
+
|
|
394
448
|
Returns:
|
|
395
449
|
dict: Dictionary with component type keys mapping to their ID dictionaries.
|
|
396
450
|
"""
|
|
397
451
|
return {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
452
|
+
"dropdown": self.dropdown_id,
|
|
453
|
+
"weight_fraction": self.weight_fraction_id,
|
|
454
|
+
"cost_slider": self.cost_slider.slider_id,
|
|
455
|
+
"cost_input": self.cost_slider.input_id,
|
|
456
|
+
"density_slider": self.density_slider.slider_id,
|
|
457
|
+
"density_input": self.density_slider.input_id,
|
|
404
458
|
}
|
|
405
459
|
|
|
406
460
|
def get_all_inputs(self):
|
|
407
461
|
"""
|
|
408
462
|
Get Input objects for all component values.
|
|
409
|
-
|
|
463
|
+
|
|
410
464
|
Returns:
|
|
411
465
|
list: List containing Input objects for all components.
|
|
412
466
|
"""
|
|
413
467
|
return [
|
|
414
|
-
Input(self.dropdown_id,
|
|
415
|
-
Input(self.weight_fraction_id,
|
|
416
|
-
Input(self.cost_slider.slider_id,
|
|
417
|
-
Input(self.cost_slider.input_id,
|
|
418
|
-
Input(self.density_slider.slider_id,
|
|
419
|
-
Input(self.density_slider.input_id,
|
|
468
|
+
Input(self.dropdown_id, "value"),
|
|
469
|
+
Input(self.weight_fraction_id, "value"),
|
|
470
|
+
Input(self.cost_slider.slider_id, "value"),
|
|
471
|
+
Input(self.cost_slider.input_id, "value"),
|
|
472
|
+
Input(self.density_slider.slider_id, "value"),
|
|
473
|
+
Input(self.density_slider.input_id, "value"),
|
|
420
474
|
]
|
|
421
475
|
|
|
422
476
|
def get_all_outputs(self):
|
|
423
477
|
"""
|
|
424
478
|
Get Output objects for updating all component values.
|
|
425
|
-
|
|
479
|
+
|
|
426
480
|
Returns:
|
|
427
481
|
list: List containing Output objects for all components.
|
|
428
482
|
"""
|
|
429
483
|
return [
|
|
430
|
-
Output(self.dropdown_id,
|
|
431
|
-
Output(self.weight_fraction_id,
|
|
432
|
-
Output(self.cost_slider.slider_id,
|
|
433
|
-
Output(self.cost_slider.input_id,
|
|
434
|
-
Output(self.density_slider.slider_id,
|
|
435
|
-
Output(self.density_slider.input_id,
|
|
484
|
+
Output(self.dropdown_id, "value"),
|
|
485
|
+
Output(self.weight_fraction_id, "value"),
|
|
486
|
+
Output(self.cost_slider.slider_id, "value"),
|
|
487
|
+
Output(self.cost_slider.input_id, "value"),
|
|
488
|
+
Output(self.density_slider.slider_id, "value"),
|
|
489
|
+
Output(self.density_slider.input_id, "value"),
|
|
436
490
|
]
|
|
437
491
|
|
|
438
492
|
|
|
439
493
|
class ActiveMaterialSelector(MaterialSelector):
|
|
440
494
|
"""
|
|
441
495
|
A custom Dash component for active material selection with capacity controls.
|
|
442
|
-
|
|
443
|
-
This component extends MaterialSelector functionality by adding reversible and
|
|
496
|
+
|
|
497
|
+
This component extends MaterialSelector functionality by adding reversible and
|
|
444
498
|
irreversible capacity sliders alongside the standard density and cost controls.
|
|
445
499
|
It creates a horizontal row containing:
|
|
446
500
|
- A dropdown menu for selecting material names
|
|
@@ -450,9 +504,9 @@ class ActiveMaterialSelector(MaterialSelector):
|
|
|
450
504
|
* Specific cost
|
|
451
505
|
* Reversible capacity scaling
|
|
452
506
|
* Irreversible capacity scaling
|
|
453
|
-
|
|
507
|
+
|
|
454
508
|
This component is designed for battery active material interfaces where users need to
|
|
455
|
-
specify both physical properties (cost, density) and electrochemical scaling factors
|
|
509
|
+
specify both physical properties (cost, density) and electrochemical scaling factors
|
|
456
510
|
(reversible/irreversible capacity scaling).
|
|
457
511
|
"""
|
|
458
512
|
|
|
@@ -465,12 +519,12 @@ class ActiveMaterialSelector(MaterialSelector):
|
|
|
465
519
|
default_material: str = None,
|
|
466
520
|
default_weight_percent: float = 0,
|
|
467
521
|
slider_disable: bool = False,
|
|
468
|
-
div_width: str =
|
|
522
|
+
div_width: str = "100%",
|
|
469
523
|
hidden: bool = False,
|
|
470
524
|
):
|
|
471
525
|
"""
|
|
472
526
|
Initialize the ActiveMaterialSelector component.
|
|
473
|
-
|
|
527
|
+
|
|
474
528
|
Args:
|
|
475
529
|
id_base (dict): Base dictionary for generating component IDs.
|
|
476
530
|
material_options (List[Dict], optional): List of material options for dropdown.
|
|
@@ -478,13 +532,13 @@ class ActiveMaterialSelector(MaterialSelector):
|
|
|
478
532
|
If None, defaults to empty list (no options).
|
|
479
533
|
slider_configs (dict): Output from create_slider_config with arrays where:
|
|
480
534
|
- Index 0 = density configuration
|
|
481
|
-
- Index 1 = cost configuration
|
|
535
|
+
- Index 1 = cost configuration
|
|
482
536
|
- Index 2 = reversible capacity scaling configuration
|
|
483
537
|
- Index 3 = irreversible capacity scaling configuration
|
|
484
538
|
If empty dictionary {}, uses sensible defaults with preset values.
|
|
485
539
|
If None (default), uses sensible defaults with no initial values.
|
|
486
540
|
title (str, optional): Title displayed for the component. Defaults to "Active Material".
|
|
487
|
-
default_material (str, optional): Default selected material. If None, no material
|
|
541
|
+
default_material (str, optional): Default selected material. If None, no material
|
|
488
542
|
will be initially selected in the dropdown.
|
|
489
543
|
default_weight_percent (float, optional): Default weight percentage (0.0-100.0). Defaults to 100.0.
|
|
490
544
|
slider_disable (bool, optional): Whether to disable sliders. Defaults to False.
|
|
@@ -501,26 +555,42 @@ class ActiveMaterialSelector(MaterialSelector):
|
|
|
501
555
|
elif slider_configs is not None and not slider_configs:
|
|
502
556
|
# Empty dictionary - create sensible defaults with preset values
|
|
503
557
|
from ..Utils.SliderControls import create_slider_config
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
558
|
+
|
|
559
|
+
min_vals = [
|
|
560
|
+
0.0,
|
|
561
|
+
0.0,
|
|
562
|
+
0.0,
|
|
563
|
+
0.0,
|
|
564
|
+
] # density, cost, rev_cap_scaling, irrev_cap_scaling
|
|
565
|
+
max_vals = [
|
|
566
|
+
0.1,
|
|
567
|
+
0.1,
|
|
568
|
+
0.1,
|
|
569
|
+
0.1,
|
|
570
|
+
] # density, cost, rev_cap_scaling, irrev_cap_scaling
|
|
571
|
+
default_vals = [
|
|
572
|
+
0.05,
|
|
573
|
+
0.05,
|
|
574
|
+
0.05,
|
|
575
|
+
0.05,
|
|
576
|
+
] # density, cost, rev_cap_scaling, irrev_cap_scaling
|
|
507
577
|
slider_configs = create_slider_config(min_vals, max_vals, default_vals)
|
|
508
578
|
else:
|
|
509
579
|
# slider_configs is None - create sensible defaults with None values
|
|
510
580
|
# Create manual config since create_slider_config doesn't handle None values
|
|
511
581
|
slider_configs = {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
{0.0:
|
|
518
|
-
{0.0:
|
|
519
|
-
{0.0:
|
|
520
|
-
{0.0:
|
|
521
|
-
]
|
|
582
|
+
"min_vals": [0.0, 0.0, 0.0, 0.0],
|
|
583
|
+
"max_vals": [0.1, 0.1, 0.1, 0.1],
|
|
584
|
+
"step_vals": [0.01, 0.01, 0.01, 0.01],
|
|
585
|
+
"grid_slider_vals": [None, None, None, None],
|
|
586
|
+
"mark_vals": [
|
|
587
|
+
{0.0: "", 0.1: ""}, # density
|
|
588
|
+
{0.0: "", 0.1: ""}, # cost
|
|
589
|
+
{0.0: "", 0.1: ""}, # rev_cap_scaling
|
|
590
|
+
{0.0: "", 0.1: ""}, # irrev_cap_scaling
|
|
591
|
+
],
|
|
522
592
|
}
|
|
523
|
-
|
|
593
|
+
|
|
524
594
|
# Initialize the parent MaterialSelector with first two sliders (density, cost)
|
|
525
595
|
super().__init__(
|
|
526
596
|
id_base=id_base,
|
|
@@ -531,164 +601,236 @@ class ActiveMaterialSelector(MaterialSelector):
|
|
|
531
601
|
default_weight_percent=default_weight_percent,
|
|
532
602
|
slider_disable=slider_disable,
|
|
533
603
|
div_width=div_width,
|
|
534
|
-
hidden=hidden
|
|
604
|
+
hidden=hidden,
|
|
535
605
|
)
|
|
536
606
|
|
|
537
607
|
# Add the additional capacity sliders (indices 2 and 3)
|
|
538
|
-
reversible_capacity_normalized = self._normalize_config_from_arrays(
|
|
539
|
-
|
|
608
|
+
reversible_capacity_normalized = self._normalize_config_from_arrays(
|
|
609
|
+
slider_configs, 2, "Reversible Capacity Scaling"
|
|
610
|
+
)
|
|
611
|
+
irreversible_capacity_normalized = self._normalize_config_from_arrays(
|
|
612
|
+
slider_configs, 3, "Irreversible Capacity Scaling"
|
|
613
|
+
)
|
|
540
614
|
|
|
541
615
|
# Create additional slider components
|
|
542
616
|
reversible_capacity_slider_kwargs = {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
617
|
+
"id_base": id_base,
|
|
618
|
+
"min_val": reversible_capacity_normalized["min_val"],
|
|
619
|
+
"max_val": reversible_capacity_normalized["max_val"],
|
|
620
|
+
"step": reversible_capacity_normalized["step"],
|
|
621
|
+
"mark_interval": reversible_capacity_normalized["mark_interval"],
|
|
622
|
+
"property_name": "reversible_capacity_scaling",
|
|
623
|
+
"title": reversible_capacity_normalized["title"],
|
|
624
|
+
"default_val": reversible_capacity_normalized.get(
|
|
625
|
+
"default_val", reversible_capacity_normalized["min_val"]
|
|
626
|
+
),
|
|
627
|
+
"with_slider_titles": True,
|
|
628
|
+
"slider_disable": slider_disable,
|
|
629
|
+
"div_width": "100%",
|
|
554
630
|
}
|
|
555
|
-
if
|
|
556
|
-
reversible_capacity_slider_kwargs[
|
|
557
|
-
|
|
631
|
+
if "marks" in reversible_capacity_normalized:
|
|
632
|
+
reversible_capacity_slider_kwargs["marks"] = reversible_capacity_normalized[
|
|
633
|
+
"marks"
|
|
634
|
+
]
|
|
635
|
+
self.reversible_capacity_slider = SliderWithTextInput(
|
|
636
|
+
**reversible_capacity_slider_kwargs
|
|
637
|
+
)
|
|
558
638
|
|
|
559
639
|
irreversible_capacity_slider_kwargs = {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
640
|
+
"id_base": id_base,
|
|
641
|
+
"min_val": irreversible_capacity_normalized["min_val"],
|
|
642
|
+
"max_val": irreversible_capacity_normalized["max_val"],
|
|
643
|
+
"step": irreversible_capacity_normalized["step"],
|
|
644
|
+
"mark_interval": irreversible_capacity_normalized["mark_interval"],
|
|
645
|
+
"property_name": "irreversible_capacity_scaling",
|
|
646
|
+
"title": irreversible_capacity_normalized["title"],
|
|
647
|
+
"default_val": irreversible_capacity_normalized.get(
|
|
648
|
+
"default_val", irreversible_capacity_normalized["min_val"]
|
|
649
|
+
),
|
|
650
|
+
"with_slider_titles": True,
|
|
651
|
+
"slider_disable": slider_disable,
|
|
652
|
+
"div_width": "100%",
|
|
571
653
|
}
|
|
572
|
-
if
|
|
573
|
-
irreversible_capacity_slider_kwargs[
|
|
574
|
-
|
|
654
|
+
if "marks" in irreversible_capacity_normalized:
|
|
655
|
+
irreversible_capacity_slider_kwargs[
|
|
656
|
+
"marks"
|
|
657
|
+
] = irreversible_capacity_normalized["marks"]
|
|
658
|
+
self.irreversible_capacity_slider = SliderWithTextInput(
|
|
659
|
+
**irreversible_capacity_slider_kwargs
|
|
660
|
+
)
|
|
575
661
|
|
|
576
662
|
def __call__(self):
|
|
577
663
|
"""
|
|
578
664
|
Generate the complete component layout as a callable object.
|
|
579
|
-
|
|
665
|
+
|
|
580
666
|
Creates and returns a Dash HTML Div containing all components arranged
|
|
581
667
|
in a horizontal layout with proper spacing and styling.
|
|
582
|
-
|
|
668
|
+
|
|
583
669
|
Returns:
|
|
584
670
|
dash.html.Div: Complete component layout with horizontal arrangement.
|
|
585
671
|
"""
|
|
586
|
-
return html.Div(
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
672
|
+
return html.Div(
|
|
673
|
+
[
|
|
674
|
+
# Main horizontal layout
|
|
675
|
+
html.Div(
|
|
676
|
+
[
|
|
677
|
+
# Material selection column (15%)
|
|
678
|
+
html.Div(
|
|
679
|
+
[
|
|
680
|
+
html.P(
|
|
681
|
+
"Material:",
|
|
682
|
+
style={
|
|
683
|
+
"margin": "0px 0px 5px 0px",
|
|
684
|
+
"font-weight": "bold",
|
|
685
|
+
},
|
|
686
|
+
),
|
|
687
|
+
self._make_dropdown(),
|
|
688
|
+
],
|
|
689
|
+
style={
|
|
690
|
+
"width": "15%",
|
|
691
|
+
"display": "inline-block",
|
|
692
|
+
"vertical-align": "top",
|
|
693
|
+
"padding-right": "15px",
|
|
694
|
+
},
|
|
695
|
+
),
|
|
696
|
+
# Weight percentage column (15%)
|
|
697
|
+
html.Div(
|
|
698
|
+
[
|
|
699
|
+
html.P(
|
|
700
|
+
"Weight (%):",
|
|
701
|
+
style={
|
|
702
|
+
"margin": "0px 0px 5px 0px",
|
|
703
|
+
"font-weight": "bold",
|
|
704
|
+
},
|
|
705
|
+
),
|
|
706
|
+
self._make_weight_fraction_input(),
|
|
707
|
+
],
|
|
708
|
+
style={
|
|
709
|
+
"width": "15%",
|
|
710
|
+
"display": "inline-block",
|
|
711
|
+
"vertical-align": "top",
|
|
712
|
+
"padding-right": "15px",
|
|
713
|
+
},
|
|
714
|
+
),
|
|
715
|
+
# Density slider column (17.5%)
|
|
716
|
+
html.Div(
|
|
717
|
+
[self.density_slider()],
|
|
718
|
+
style={
|
|
719
|
+
"width": "17.5%",
|
|
720
|
+
"display": "inline-block",
|
|
721
|
+
"vertical-align": "top",
|
|
722
|
+
"padding-right": "15px",
|
|
723
|
+
},
|
|
724
|
+
),
|
|
725
|
+
# Cost slider column (17.5%)
|
|
726
|
+
html.Div(
|
|
727
|
+
[self.cost_slider()],
|
|
728
|
+
style={
|
|
729
|
+
"width": "17.5%",
|
|
730
|
+
"display": "inline-block",
|
|
731
|
+
"vertical-align": "top",
|
|
732
|
+
"padding-right": "15px",
|
|
733
|
+
},
|
|
734
|
+
),
|
|
735
|
+
# Reversible capacity slider column (17.5%)
|
|
736
|
+
html.Div(
|
|
737
|
+
[self.reversible_capacity_slider()],
|
|
738
|
+
style={
|
|
739
|
+
"width": "17.5%",
|
|
740
|
+
"display": "inline-block",
|
|
741
|
+
"vertical-align": "top",
|
|
742
|
+
"padding-right": "15px",
|
|
743
|
+
},
|
|
744
|
+
),
|
|
745
|
+
# Irreversible capacity slider column (17.5%)
|
|
746
|
+
html.Div(
|
|
747
|
+
[self.irreversible_capacity_slider()],
|
|
748
|
+
style={
|
|
749
|
+
"width": "17.5%",
|
|
750
|
+
"display": "inline-block",
|
|
751
|
+
"vertical-align": "top",
|
|
752
|
+
},
|
|
753
|
+
),
|
|
754
|
+
],
|
|
755
|
+
style={
|
|
756
|
+
"display": "flex",
|
|
757
|
+
"align-items": "flex-start",
|
|
758
|
+
"width": "100%",
|
|
759
|
+
"gap": "10px",
|
|
760
|
+
},
|
|
761
|
+
)
|
|
762
|
+
],
|
|
763
|
+
id=self.id_base,
|
|
764
|
+
style={
|
|
765
|
+
"border": "1px solid #ddd",
|
|
766
|
+
"border-radius": "5px",
|
|
767
|
+
"padding": "15px",
|
|
768
|
+
"margin": "10px 0px",
|
|
769
|
+
"background-color": "#f9f9f9",
|
|
770
|
+
"width": self.div_width,
|
|
771
|
+
"display": "none" if self.hidden else "block",
|
|
772
|
+
},
|
|
773
|
+
)
|
|
634
774
|
|
|
635
775
|
@property
|
|
636
776
|
def components(self):
|
|
637
777
|
"""
|
|
638
778
|
Get a dictionary mapping component types to their IDs.
|
|
639
|
-
|
|
779
|
+
|
|
640
780
|
Returns:
|
|
641
781
|
dict: Dictionary with component type keys mapping to their ID dictionaries.
|
|
642
782
|
"""
|
|
643
783
|
# Get base components from parent
|
|
644
784
|
base_components = super().components
|
|
645
|
-
|
|
785
|
+
|
|
646
786
|
# Add the additional capacity slider components
|
|
647
|
-
base_components.update(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
787
|
+
base_components.update(
|
|
788
|
+
{
|
|
789
|
+
"reversible_capacity_scaling_slider": self.reversible_capacity_slider.slider_id,
|
|
790
|
+
"reversible_capacity_scaling_input": self.reversible_capacity_slider.input_id,
|
|
791
|
+
"irreversible_capacity_scaling_slider": self.irreversible_capacity_slider.slider_id,
|
|
792
|
+
"irreversible_capacity_scaling_input": self.irreversible_capacity_slider.input_id,
|
|
793
|
+
}
|
|
794
|
+
)
|
|
795
|
+
|
|
654
796
|
return base_components
|
|
655
797
|
|
|
656
798
|
def get_all_inputs(self):
|
|
657
799
|
"""
|
|
658
800
|
Get Input objects for all component values.
|
|
659
|
-
|
|
801
|
+
|
|
660
802
|
Returns:
|
|
661
803
|
list: List containing Input objects for all components.
|
|
662
804
|
"""
|
|
663
805
|
# Get base inputs from parent
|
|
664
806
|
base_inputs = super().get_all_inputs()
|
|
665
|
-
|
|
807
|
+
|
|
666
808
|
# Add the additional capacity slider inputs
|
|
667
809
|
capacity_inputs = [
|
|
668
|
-
Input(self.reversible_capacity_slider.slider_id,
|
|
669
|
-
Input(self.reversible_capacity_slider.input_id,
|
|
670
|
-
Input(self.irreversible_capacity_slider.slider_id,
|
|
671
|
-
Input(self.irreversible_capacity_slider.input_id,
|
|
810
|
+
Input(self.reversible_capacity_slider.slider_id, "value"),
|
|
811
|
+
Input(self.reversible_capacity_slider.input_id, "value"),
|
|
812
|
+
Input(self.irreversible_capacity_slider.slider_id, "value"),
|
|
813
|
+
Input(self.irreversible_capacity_slider.input_id, "value"),
|
|
672
814
|
]
|
|
673
|
-
|
|
815
|
+
|
|
674
816
|
return base_inputs + capacity_inputs
|
|
675
817
|
|
|
676
818
|
def get_all_outputs(self):
|
|
677
819
|
"""
|
|
678
820
|
Get Output objects for updating all component values.
|
|
679
|
-
|
|
821
|
+
|
|
680
822
|
Returns:
|
|
681
823
|
list: List containing Output objects for all components.
|
|
682
824
|
"""
|
|
683
825
|
# Get base outputs from parent
|
|
684
826
|
base_outputs = super().get_all_outputs()
|
|
685
|
-
|
|
827
|
+
|
|
686
828
|
# Add the additional capacity slider outputs
|
|
687
829
|
capacity_outputs = [
|
|
688
|
-
Output(self.reversible_capacity_slider.slider_id,
|
|
689
|
-
Output(self.reversible_capacity_slider.input_id,
|
|
690
|
-
Output(self.irreversible_capacity_slider.slider_id,
|
|
691
|
-
Output(self.irreversible_capacity_slider.input_id,
|
|
830
|
+
Output(self.reversible_capacity_slider.slider_id, "value"),
|
|
831
|
+
Output(self.reversible_capacity_slider.input_id, "value"),
|
|
832
|
+
Output(self.irreversible_capacity_slider.slider_id, "value"),
|
|
833
|
+
Output(self.irreversible_capacity_slider.input_id, "value"),
|
|
692
834
|
]
|
|
693
|
-
|
|
694
|
-
return base_outputs + capacity_outputs
|
|
835
|
+
|
|
836
|
+
return base_outputs + capacity_outputs
|