steer-core 0.1.26__py3-none-any.whl → 0.1.28__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.
@@ -1,836 +0,0 @@
1
- import dash as ds
2
- from dash import Input, Output, dcc, html
3
- from typing import Union, List, Dict
4
- from .SliderComponents import SliderWithTextInput
5
-
6
-
7
- class MaterialSelector:
8
- """
9
- A custom Dash component that combines material selection controls in a horizontal layout.
10
-
11
- This component creates a horizontal row containing:
12
- - A dropdown menu for selecting material names
13
- - An input box for specifying weight fraction of the material
14
- - Two SliderWithTextInput components for specific cost and density
15
-
16
- The component is designed for material composition interfaces where users need to
17
- select materials and specify their properties and proportions.
18
-
19
- Attributes:
20
- id_base (dict): Base identifier dictionary used to construct unique IDs for child components
21
- material_options (List[Dict]): List of material options for the dropdown
22
- default_material (str): Default selected material name
23
- default_weight_fraction (float): Default weight fraction value
24
- cost_config (dict): Configuration for the cost slider (min_val, max_val, step, etc.)
25
- density_config (dict): Configuration for the density slider (min_val, max_val, step, etc.)
26
- property_name (str): Property identifier used in component ID construction
27
- title (str): Display title for the component
28
- slider_disable (bool): Whether the sliders should be disabled
29
- dropdown_id (dict): Computed ID for the dropdown component
30
- weight_fraction_id (dict): Computed ID for the weight fraction input
31
- cost_slider (SliderWithTextInput): Cost slider component
32
- density_slider (SliderWithTextInput): Density slider component
33
-
34
- Example:
35
- >>> material_selector = MaterialSelector(
36
- ... id_base={'type': 'material', 'index': 0},
37
- ... material_options=[
38
- ... {'label': 'Aluminum', 'value': 'aluminum'},
39
- ... {'label': 'Steel', 'value': 'steel'},
40
- ... {'label': 'Carbon Fiber', 'value': 'carbon_fiber'}
41
- ... ],
42
- ... default_material='aluminum',
43
- ... default_weight_fraction=0.5,
44
- ... cost_config={
45
- ... 'min_val': 0.0,
46
- ... 'max_val': 100.0,
47
- ... 'step': 0.1,
48
- ... 'mark_interval': 10.0,
49
- ... 'default_val': 25.0,
50
- ... 'title': 'Cost ($/kg)'
51
- ... },
52
- ... density_config={
53
- ... 'min_val': 0.0,
54
- ... 'max_val': 10.0,
55
- ... 'step': 0.01,
56
- ... 'mark_interval': 1.0,
57
- ... 'default_val': 2.7,
58
- ... 'title': 'Density (g/cm³)'
59
- ... },
60
- ... property_name='material_1',
61
- ... title='Material 1'
62
- ... )
63
- >>> layout_element = material_selector() # Returns Dash HTML Div component
64
- """
65
-
66
- def __init__(
67
- self,
68
- id_base: dict,
69
- material_options: List[Dict] = None,
70
- slider_configs: dict = None,
71
- cost_config: dict = None,
72
- density_config: dict = None,
73
- title: str = "Material",
74
- default_material: str = None,
75
- default_weight_percent: float = 0,
76
- slider_disable: bool = False,
77
- div_width: str = "100%",
78
- hidden: bool = False,
79
- ):
80
- """
81
- Initialize the MaterialSelector component.
82
-
83
- Args:
84
- id_base (dict): Base dictionary for generating component IDs.
85
- material_options (List[Dict], optional): List of material options for dropdown.
86
- Each dict should have 'label' and 'value' keys.
87
- If None, defaults to empty list (no options).
88
- slider_configs (dict, optional): Output from create_slider_config with arrays where:
89
- - Index 0 = density configuration
90
- - Index 1 = cost configuration
91
- If provided, cost_config and density_config are ignored.
92
- If empty dictionary {}, uses sensible defaults with preset values.
93
- If None (default), uses sensible defaults with no initial values.
94
- cost_config (dict, optional): Legacy cost slider configuration. Ignored if slider_config provided.
95
- density_config (dict, optional): Legacy density slider configuration. Ignored if slider_config provided.
96
- title (str, optional): Title displayed for the component. Defaults to "Material".
97
- default_material (str, optional): Default selected material. If None, no material
98
- will be initially selected in the dropdown.
99
- default_weight_percent (float, optional): Default weight percentage (0.0-100.0). Defaults to 100.0.
100
- slider_disable (bool, optional): Whether to disable sliders. Defaults to False.
101
- div_width (str, optional): CSS width specification for the container div.
102
- Defaults to '100%'.
103
- hidden (bool, optional): Whether to hide the entire component. When True,
104
- the component will be rendered with display: none.
105
- Defaults to False.
106
- """
107
- self.id_base = id_base
108
- self.material_options = material_options or [] # Default to empty list if None
109
- self.default_material = default_material # Keep as None if not provided
110
- self.default_weight_percent = default_weight_percent
111
- self.cost_config = cost_config
112
- self.density_config = density_config
113
- self.title = title
114
- self.slider_disable = slider_disable
115
- self.div_width = div_width
116
- self.hidden = hidden
117
-
118
- # Generate component IDs
119
- self.dropdown_id = self._make_id("dropdown")
120
- self.weight_fraction_id = self._make_id("weight_fraction")
121
-
122
- # Normalize configurations to handle both legacy and create_slider_config formats
123
- if slider_configs is not None and slider_configs: # Check if not empty
124
- # Use slider_configs arrays (index 0 = density, index 1 = cost)
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
- )
131
- elif slider_configs is not None and not slider_configs: # Empty dictionary
132
- # Use sensible defaults for materials
133
- density_normalized = {
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,
140
- }
141
- cost_normalized = {
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,
148
- }
149
- else:
150
- # slider_configs is None - use sensible defaults with None values
151
- density_normalized = {
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
158
- }
159
- cost_normalized = {
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
166
- }
167
-
168
- # Create slider components
169
- cost_slider_kwargs = {
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%",
183
- }
184
- # Add marks if available
185
- if "marks" in cost_normalized:
186
- cost_slider_kwargs["marks"] = cost_normalized["marks"]
187
-
188
- self.cost_slider = SliderWithTextInput(**cost_slider_kwargs)
189
-
190
- density_slider_kwargs = {
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%",
204
- }
205
- # Add marks if available
206
- if "marks" in density_normalized:
207
- density_slider_kwargs["marks"] = density_normalized["marks"]
208
-
209
- self.density_slider = SliderWithTextInput(**density_slider_kwargs)
210
-
211
- def _normalize_config_from_arrays(
212
- self, config: dict, index: int, default_title: str
213
- ) -> dict:
214
- """
215
- Normalize slider configuration from create_slider_config output arrays.
216
-
217
- Args:
218
- config (dict): create_slider_config output with array values
219
- index (int): Index to extract from each array (0 = density, 1 = cost)
220
- default_title (str): Default title if not provided
221
-
222
- Returns:
223
- dict: Normalized configuration with min_val, max_val, step, mark_interval, title keys
224
- """
225
- normalized = {
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
230
- }
231
-
232
- # Get pre-computed marks if available, otherwise calculate mark_interval
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
236
- if len(marks) >= 2:
237
- # Calculate interval from first two marks
238
- mark_positions = sorted(marks.keys())
239
- normalized["mark_interval"] = mark_positions[1] - mark_positions[0]
240
- else:
241
- # Fallback: use step as mark interval
242
- normalized["mark_interval"] = normalized["step"]
243
- else:
244
- normalized["mark_interval"] = normalized["step"]
245
-
246
- # Add default value if available from grid values
247
- if "grid_slider_vals" in config and len(config["grid_slider_vals"]) > index:
248
- normalized["default_val"] = config["grid_slider_vals"][index]
249
- else:
250
- normalized["default_val"] = normalized["min_val"]
251
-
252
- return normalized
253
-
254
- def _normalize_config(self, config: dict, config_type: str) -> dict:
255
- """
256
- Normalize slider configuration to handle both legacy and create_slider_config formats.
257
-
258
- Args:
259
- config (dict): Either legacy format or create_slider_config output
260
- config_type (str): Type identifier ('cost' or 'density') for default title
261
-
262
- Returns:
263
- dict: Normalized configuration with min_val, max_val, step, mark_interval, title keys
264
- """
265
- # Check if this is a create_slider_config output (has min_vals, max_vals, etc.)
266
- if "min_vals" in config and "max_vals" in config:
267
- # This is create_slider_config output - use first element from arrays
268
- normalized = {
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
273
- }
274
-
275
- # Get pre-computed marks if available, otherwise calculate mark_interval
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
279
- if len(marks) >= 2:
280
- # Calculate interval from first two marks
281
- mark_positions = sorted(marks.keys())
282
- normalized["mark_interval"] = mark_positions[1] - mark_positions[0]
283
- else:
284
- # Fallback: use step as mark interval
285
- normalized["mark_interval"] = normalized["step"]
286
- else:
287
- normalized["mark_interval"] = normalized["step"]
288
-
289
- # Add default value if available from grid values
290
- if "grid_slider_vals" in config and len(config["grid_slider_vals"]) > 0:
291
- normalized["default_val"] = config["grid_slider_vals"][0]
292
- else:
293
- normalized["default_val"] = normalized["min_val"]
294
-
295
- else:
296
- # This is legacy format - use as-is but ensure all required keys exist
297
- normalized = config.copy()
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
-
303
- return normalized
304
-
305
- def _make_id(self, subtype: str):
306
- """
307
- Generate a unique ID dictionary for component sub-elements.
308
-
309
- Args:
310
- subtype (str): The specific component subtype.
311
-
312
- Returns:
313
- dict: Complete ID dictionary containing base ID information plus subtype.
314
- """
315
- return {**self.id_base, "subtype": subtype}
316
-
317
- def _make_dropdown(self):
318
- """
319
- Create and configure the material selection dropdown.
320
-
321
- Returns:
322
- dash.dcc.Dropdown: Configured dropdown component for material selection.
323
- """
324
- return dcc.Dropdown(
325
- id=self.dropdown_id,
326
- options=self.material_options,
327
- value=self.default_material, # Can be None for no initial selection
328
- disabled=self.slider_disable,
329
- style={"width": "100%", "margin-bottom": "10px"},
330
- )
331
-
332
- def _make_weight_fraction_input(self):
333
- """
334
- Create and configure the weight percentage input.
335
-
336
- Returns:
337
- dash.dcc.Input: Configured numeric input for weight percentage.
338
- """
339
- return dcc.Input(
340
- id=self.weight_fraction_id,
341
- type="number",
342
- value=self.default_weight_percent, # Use percentage directly
343
- min=0.0,
344
- max=100.0,
345
- step=0.1,
346
- disabled=self.slider_disable,
347
- style={"width": "100%", "margin-bottom": "10px"},
348
- )
349
-
350
- def __call__(self):
351
- """
352
- Generate the complete component layout as a callable object.
353
-
354
- Creates and returns a Dash HTML Div containing all components arranged
355
- in a horizontal layout with proper spacing and styling.
356
-
357
- Returns:
358
- dash.html.Div: Complete component layout with horizontal arrangement.
359
- """
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
- )
442
-
443
- @property
444
- def components(self):
445
- """
446
- Get a dictionary mapping component types to their IDs.
447
-
448
- Returns:
449
- dict: Dictionary with component type keys mapping to their ID dictionaries.
450
- """
451
- return {
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,
458
- }
459
-
460
- def get_all_inputs(self):
461
- """
462
- Get Input objects for all component values.
463
-
464
- Returns:
465
- list: List containing Input objects for all components.
466
- """
467
- return [
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"),
474
- ]
475
-
476
- def get_all_outputs(self):
477
- """
478
- Get Output objects for updating all component values.
479
-
480
- Returns:
481
- list: List containing Output objects for all components.
482
- """
483
- return [
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"),
490
- ]
491
-
492
-
493
- class ActiveMaterialSelector(MaterialSelector):
494
- """
495
- A custom Dash component for active material selection with capacity controls.
496
-
497
- This component extends MaterialSelector functionality by adding reversible and
498
- irreversible capacity sliders alongside the standard density and cost controls.
499
- It creates a horizontal row containing:
500
- - A dropdown menu for selecting material names
501
- - An input box for specifying weight percentage of the material
502
- - Four SliderWithTextInput components for:
503
- * Density
504
- * Specific cost
505
- * Reversible capacity scaling
506
- * Irreversible capacity scaling
507
-
508
- This component is designed for battery active material interfaces where users need to
509
- specify both physical properties (cost, density) and electrochemical scaling factors
510
- (reversible/irreversible capacity scaling).
511
- """
512
-
513
- def __init__(
514
- self,
515
- id_base: dict,
516
- material_options: List[Dict] = None,
517
- slider_configs: dict = None,
518
- title: str = "Active Material",
519
- default_material: str = None,
520
- default_weight_percent: float = 0,
521
- slider_disable: bool = False,
522
- div_width: str = "100%",
523
- hidden: bool = False,
524
- ):
525
- """
526
- Initialize the ActiveMaterialSelector component.
527
-
528
- Args:
529
- id_base (dict): Base dictionary for generating component IDs.
530
- material_options (List[Dict], optional): List of material options for dropdown.
531
- Each dict should have 'label' and 'value' keys.
532
- If None, defaults to empty list (no options).
533
- slider_configs (dict): Output from create_slider_config with arrays where:
534
- - Index 0 = density configuration
535
- - Index 1 = cost configuration
536
- - Index 2 = reversible capacity scaling configuration
537
- - Index 3 = irreversible capacity scaling configuration
538
- If empty dictionary {}, uses sensible defaults with preset values.
539
- If None (default), uses sensible defaults with no initial values.
540
- title (str, optional): Title displayed for the component. Defaults to "Active Material".
541
- default_material (str, optional): Default selected material. If None, no material
542
- will be initially selected in the dropdown.
543
- default_weight_percent (float, optional): Default weight percentage (0.0-100.0). Defaults to 100.0.
544
- slider_disable (bool, optional): Whether to disable sliders. Defaults to False.
545
- div_width (str, optional): CSS width specification for the container div.
546
- Defaults to '100%'.
547
- hidden (bool, optional): Whether to hide the entire component. When True,
548
- the component will be rendered with display: none.
549
- Defaults to False.
550
- """
551
- # Handle different slider_configs scenarios
552
- if slider_configs is not None and slider_configs:
553
- # Use provided configuration
554
- pass # slider_configs will be passed to parent
555
- elif slider_configs is not None and not slider_configs:
556
- # Empty dictionary - create sensible defaults with preset values
557
- from ..Utils.SliderControls import create_slider_config
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
577
- slider_configs = create_slider_config(min_vals, max_vals, default_vals)
578
- else:
579
- # slider_configs is None - create sensible defaults with None values
580
- # Create manual config since create_slider_config doesn't handle None values
581
- slider_configs = {
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
- ],
592
- }
593
-
594
- # Initialize the parent MaterialSelector with first two sliders (density, cost)
595
- super().__init__(
596
- id_base=id_base,
597
- material_options=material_options,
598
- slider_configs=slider_configs, # Parent will use indices 0 and 1
599
- title=title,
600
- default_material=default_material,
601
- default_weight_percent=default_weight_percent,
602
- slider_disable=slider_disable,
603
- div_width=div_width,
604
- hidden=hidden,
605
- )
606
-
607
- # Add the additional capacity sliders (indices 2 and 3)
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
- )
614
-
615
- # Create additional slider components
616
- reversible_capacity_slider_kwargs = {
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%",
630
- }
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
- )
638
-
639
- irreversible_capacity_slider_kwargs = {
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%",
653
- }
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
- )
661
-
662
- def __call__(self):
663
- """
664
- Generate the complete component layout as a callable object.
665
-
666
- Creates and returns a Dash HTML Div containing all components arranged
667
- in a horizontal layout with proper spacing and styling.
668
-
669
- Returns:
670
- dash.html.Div: Complete component layout with horizontal arrangement.
671
- """
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
- )
774
-
775
- @property
776
- def components(self):
777
- """
778
- Get a dictionary mapping component types to their IDs.
779
-
780
- Returns:
781
- dict: Dictionary with component type keys mapping to their ID dictionaries.
782
- """
783
- # Get base components from parent
784
- base_components = super().components
785
-
786
- # Add the additional capacity slider components
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
-
796
- return base_components
797
-
798
- def get_all_inputs(self):
799
- """
800
- Get Input objects for all component values.
801
-
802
- Returns:
803
- list: List containing Input objects for all components.
804
- """
805
- # Get base inputs from parent
806
- base_inputs = super().get_all_inputs()
807
-
808
- # Add the additional capacity slider inputs
809
- capacity_inputs = [
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"),
814
- ]
815
-
816
- return base_inputs + capacity_inputs
817
-
818
- def get_all_outputs(self):
819
- """
820
- Get Output objects for updating all component values.
821
-
822
- Returns:
823
- list: List containing Output objects for all components.
824
- """
825
- # Get base outputs from parent
826
- base_outputs = super().get_all_outputs()
827
-
828
- # Add the additional capacity slider outputs
829
- capacity_outputs = [
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"),
834
- ]
835
-
836
- return base_outputs + capacity_outputs