Skip to content

Commit d6efe1b

Browse files
authored
Merge pull request #496 from materialsproject/pourbaix3
Update control panel UI and correct filter solids help string
2 parents 330149a + fa71ef2 commit d6efe1b

File tree

1 file changed

+140
-49
lines changed

1 file changed

+140
-49
lines changed

crystal_toolkit/components/pourbaix.py

Lines changed: 140 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
MAX_PH = 16
4343
MIN_V = -4
4444
MAX_V = 4
45+
PANEL_LINE_HEIGHT = "2em"
4546

4647

4748
class PourbaixDiagramComponent(MPComponent):
@@ -127,6 +128,16 @@ class PourbaixDiagramComponent(MPComponent):
127128
}
128129
)
129130

131+
@staticmethod
132+
def create_centered_object(content):
133+
return html.Div(
134+
content,
135+
style={
136+
"display": "flex",
137+
"justifyContent": "center",
138+
},
139+
)
140+
130141
@staticmethod
131142
def get_figure(
132143
pourbaix_diagram: PourbaixDiagram, heatmap_entry=None, show_water_lines=True
@@ -440,11 +451,10 @@ def _sub_layouts(self) -> dict[str, Component]:
440451
default=self.default_state["filter_solids"],
441452
label="Filter Solids",
442453
help_str="Whether to filter solid phases by stability on the compositional phase diagram. "
443-
"The practical consequence of this is that highly oxidized or reduced phases that "
444-
"might show up in experiments due to kinetic limitations on oxygen/hydrogen evolution "
445-
"won't appear in the diagram, but they are not actually “stable” (and are frequently "
446-
"overstabilized from DFT errors). Hence, including only the stable solid phases generally "
447-
"leads to the most accurate Pourbaix diagrams.",
454+
"The practical consequence of this is that we only include materials that are predicted to "
455+
"be thermodynamically stable at RT within the limitations of DFT. Notably, there may be "
456+
"disagreements with experiments e.g., highly oxidized or reduced phases, which are kinetically "
457+
"stabilized through surface passivation.",
448458
),
449459
html.Div(
450460
[
@@ -454,23 +464,56 @@ def _sub_layouts(self) -> dict[str, Component]:
454464
id=self.id("invalid-comp-alarm"),
455465
message="Illegal composition entry!",
456466
),
457-
html.H5(
458-
"Composition",
459-
id=self.id("composition-title"),
460-
style={"fontWeight": "bold"},
467+
html.Div(
468+
[
469+
html.H5(
470+
"Composition Control",
471+
style={
472+
"fontWeight": "bold",
473+
"textAlign": "center",
474+
"flex": "0 0 100%",
475+
},
476+
),
477+
html.H5(
478+
"Composition of",
479+
id=self.id("composition-title"),
480+
# style={"fontWeight": "bold"},
481+
),
482+
],
483+
style={
484+
"line-height": PANEL_LINE_HEIGHT,
485+
"display": "flex",
486+
"flexWrap": "wrap",
487+
"justifyContent": "center",
488+
},
461489
),
462-
dcc.Input(
463-
id=self.id("comp-text"),
464-
type="text",
465-
# placeholder="composition e.g. 1:1:1",
490+
PourbaixDiagramComponent.create_centered_object(
491+
dcc.Input(
492+
id=self.id("comp-text"),
493+
className="input",
494+
type="text",
495+
style={
496+
"textAlign": "center",
497+
"width": "10rem",
498+
"marginRight": "0.2rem",
499+
"marginBottom": "0.2rem",
500+
"height": "36px",
501+
"fontSize": "14px",
502+
},
503+
),
466504
),
467-
html.Button(
468-
"Update",
469-
id=self.id("comp-btn"),
505+
ctl.Block(
506+
PourbaixDiagramComponent.create_centered_object(
507+
html.Div(
508+
id=self.id("display-composition"),
509+
)
510+
)
511+
),
512+
html.Hr(
513+
style={
514+
"backgroundColor": "#C5C5C6",
515+
}
470516
),
471-
ctl.Block(html.Div(id=self.id("display-composition"))),
472-
html.Br(),
473-
html.Br(),
474517
dcc.Store(id=self.id("elements-store")),
475518
],
476519
id=self.id("comp-panel"),
@@ -486,9 +529,22 @@ def _sub_layouts(self) -> dict[str, Component]:
486529
id=self.id("conc-panel"),
487530
style={"display": "none"},
488531
),
489-
html.Div(id=self.id("element_specific_controls")),
490-
]
532+
html.Div(
533+
id=self.id("element_specific_controls"),
534+
),
535+
PourbaixDiagramComponent.create_centered_object(
536+
html.Button(
537+
"Update",
538+
id=self.id("comp-conc-btn"),
539+
style={"display": "none"},
540+
),
541+
),
542+
],
543+
style={
544+
"backgroundColor": "#F1F1F5",
545+
},
491546
),
547+
html.Br(),
492548
self.get_bool_input(
493549
"show_heatmap", # kwarg_label
494550
# state=self.default_state,
@@ -629,6 +685,8 @@ def update_heatmap_choices(entries, mat_detials, filter_solids):
629685
Output(self.id("elements-store"), "data"),
630686
Output(self.id("comp-text"), "value"),
631687
Output(self.id("composition-title"), "children"),
688+
Output(self.id("comp-conc-btn"), "children"),
689+
Output(self.id("comp-conc-btn"), "style"),
632690
Input(self.id(), "data"),
633691
prevent_initial_call=True,
634692
)
@@ -651,57 +709,83 @@ def update_element_specific_sliders(
651709
# exclude O and H
652710
elements = elements - ELEMENTS_HO
653711

654-
comp_inputs = []
655712
conc_inputs = []
656713

657714
for element in sorted(elements):
658-
conc_input = html.Div(
659-
[
660-
self.get_numerical_input(
661-
f"conc-{element}",
662-
default=1e-6,
663-
min=MIN_CONCENTRATION,
664-
max=MAX_CONCENTRATION,
665-
label=f"Concentration of {element} ion",
666-
style={"width": "10rem", "fontSize": "14px"},
667-
)
668-
]
715+
conc_input = PourbaixDiagramComponent.create_centered_object(
716+
self.get_numerical_input(
717+
f"conc-{element}",
718+
default=1e-6,
719+
min=MIN_CONCENTRATION,
720+
max=MAX_CONCENTRATION,
721+
label=f"concentration of {element} ion",
722+
style={
723+
"width": "10rem",
724+
"fontSize": "14px",
725+
},
726+
)
669727
)
670728

671729
conc_inputs.append(conc_input)
672730

673731
comp_conc_controls = []
674-
comp_conc_controls += comp_inputs
675732

676733
ion_label = (
677-
"Set Ion Concentrations (M)"
734+
"Ion Concentrations Control"
678735
if len(elements) > 1
679-
else "Set Ion Concentration"
736+
else "Ion Concentration Control"
737+
)
738+
739+
comp_conc_controls.append(
740+
html.H5(
741+
ion_label,
742+
style={"fontWeight": "bold", "textAlign": "center"},
743+
),
744+
)
745+
comp_conc_controls.append(
746+
PourbaixDiagramComponent.create_centered_object(
747+
html.H6(
748+
f"💡 Set the range between {MIN_CONCENTRATION} and {MAX_CONCENTRATION} (M)"
749+
)
750+
)
680751
)
681-
comp_conc_controls.append(ctl.Label(ion_label))
682752

683753
comp_conc_controls += conc_inputs
684754

685-
#
755+
# comp_panel_style
686756
comp_panel_style = {"display": "none"}
687757
if len(elements) > 1:
688-
comp_panel_style = {"display": "block"}
758+
comp_panel_style = {
759+
"display": "block",
760+
}
689761

690-
#
762+
# elements store
691763
elements = [element.symbol for element in elements]
692764

693-
#
765+
# default_comp
694766
default_comp = ":".join(["1" for _ in elements])
695767

696-
#
697-
title = "Composition of " + ":".join(elements)
768+
# composition title
769+
title = "💡 Composition of " + ":".join(elements)
770+
771+
# update_string
772+
update_string = "Concentration update"
773+
if len(elements) > 1:
774+
update_string = "Composition & concentration update"
698775

699776
return (
700-
html.Div(comp_conc_controls),
777+
html.Div(
778+
comp_conc_controls,
779+
style={
780+
"line-height": PANEL_LINE_HEIGHT,
781+
},
782+
),
701783
comp_panel_style,
702784
elements,
703785
default_comp,
704786
title,
787+
update_string,
788+
{"display": "block", "height": "36px"},
705789
)
706790

707791
@cache.memoize(timeout=5 * 60)
@@ -715,26 +799,32 @@ def get_pourbaix_diagram(pourbaix_entries, **kwargs):
715799
Output(self.id("display-composition"), "children"),
716800
Input(self.id(), "data"),
717801
Input(self.id("display-composition"), "children"),
718-
Input(self.get_all_kwargs_id(), "value"),
719-
Input(self.id("comp-btn"), "n_clicks"),
802+
State(self.get_all_kwargs_id(), "value"),
803+
Input(self.id("comp-conc-btn"), "n_clicks"),
720804
State(self.id("elements-store"), "data"),
721805
State(self.id("comp-text"), "value"),
722806
Input(self.id("element_specific_controls"), "children"),
807+
Input(self.get_kwarg_id("filter_solids"), "value"),
808+
Input(self.get_kwarg_id("show_heatmap"), "value"),
809+
Input(self.get_kwarg_id("heatmap_choice"), "value"),
723810
prevent_initial_call=True,
724811
)
725812
def make_figure(
726813
pourbaix_entries,
727-
dependency,
814+
display_composition,
728815
kwargs,
729816
n_clicks,
730817
elements,
731818
comp_text,
732-
dependency2,
819+
element_specific_controls,
820+
filter_solids,
821+
show_heatmap,
822+
heatmap_choice,
733823
) -> go.Figure:
734824
if pourbaix_entries is None:
735825
raise PreventUpdate
736826

737-
# check if composition input
827+
# Only update
738828
if n_clicks:
739829
raw_comp_list = comp_text.split(":")
740830
else:
@@ -808,6 +898,7 @@ def make_figure(
808898
pourbaix_diagram,
809899
heatmap_entry=heatmap_entry,
810900
)
901+
811902
return (
812903
self.get_figure_div(figure=figure),
813904
False,

0 commit comments

Comments
 (0)