3636
3737HEIGHT = 550 # in px
3838WIDTH = 700 # in px
39- MIN_CONCENTRATION = 1e-8
39+ MIN_CONCENTRATION = 1e-6
4040MAX_CONCENTRATION = 5
4141MIN_PH = - 2
4242MAX_PH = 16
@@ -571,7 +571,7 @@ def clean_formula(formula):
571571 # Subscript coefficients
572572 return re .sub (r"([A-Za-z\(\)])([\d\.]+)" , r"\1<sub>\2</sub>" , clean_formula )
573573
574- def get_figure_div (self , figure ):
574+ def get_figure_div (self , figure = None ):
575575 """
576576 Intentionally update the graph by wrapping it in an `html.Div` instead of directly modifying `go.Figure` or `dcc.Graph`.
577577 This is because, after resetting the axes (e.g., zooming in/out), the updated axes may not match the original ones.
@@ -584,11 +584,17 @@ def get_figure_div(self, figure):
584584 figure = go .Figure (layout = {** PourbaixDiagramComponent .empty_plot_style })
585585
586586 return html .Div (
587- dcc .Graph (
588- figure = figure ,
589- responsive = True ,
590- config = {"displayModeBar" : False , "displaylogo" : False },
591- ),
587+ [
588+ html .H5 (
589+ "💡 Zoom in by selecting an area of interest, and double-click to return to the original view." ,
590+ style = {"textAlign" : "right" },
591+ ),
592+ dcc .Graph (
593+ figure = figure ,
594+ responsive = True ,
595+ config = {"displayModeBar" : False , "displaylogo" : False },
596+ ),
597+ ]
592598 )
593599
594600 @property
@@ -629,6 +635,7 @@ def _sub_layouts(self) -> dict[str, Component]:
629635 "Update" ,
630636 id = self .id ("comp-btn" ),
631637 ),
638+ ctl .Block (html .Div (id = self .id ("display-composition" ))),
632639 html .Br (),
633640 html .Br (),
634641 dcc .Store (id = self .id ("elements-store" )),
@@ -647,7 +654,6 @@ def _sub_layouts(self) -> dict[str, Component]:
647654 style = {"display" : "none" },
648655 ),
649656 html .Div (id = self .id ("element_specific_controls" )),
650- ctl .Block (html .Div (id = self .id ("display-composition" ))),
651657 ]
652658 ),
653659 self .get_bool_input (
@@ -694,7 +700,6 @@ def _sub_layouts(self) -> dict[str, Component]:
694700 id = self .id ("graph-panel" ),
695701 ),
696702 )
697- # html.H5("Zoom in by selecting an area of interest, and double-click to return to the original view.")
698703
699704 return {"graph" : graph , "options" : options }
700705
@@ -840,7 +845,7 @@ def update_element_specific_sliders(
840845 min = MIN_CONCENTRATION ,
841846 max = MAX_CONCENTRATION ,
842847 label = f"Concentration of { element } ion" ,
843- style = {"width" : "10rem" },
848+ style = {"width" : "10rem" , "fontSize" : "14px" },
844849 )
845850 ]
846851 )
@@ -856,7 +861,7 @@ def update_element_specific_sliders(
856861 comp_conc_controls += comp_inputs
857862
858863 ion_label = (
859- "Set Ion Concentrations"
864+ "Set Ion Concentrations (M) "
860865 if len (elements ) > 1
861866 else "Set Ion Concentration"
862867 )
@@ -964,9 +969,8 @@ def update_element_specific_sliders(entries, heatmap_choice, show_heatmap):
964969 external_link = (
965970 f"https://next-gen.materialsproject.org/materials/{mpid_wo_function}"
966971 )
967-
968972 return html.Div(comp_conc_controls), False, external_link
969- """
973+
970974
971975 @app.callback(
972976 Output(self.id("display-composition"), "children"),
@@ -997,6 +1001,7 @@ def update_displayed_composition(dependency): # **kwargs):
9971001 )
9981002
9991003 return html.Small(f"Pourbaix composition set to {unicodeify(formula)}.")
1004+ """
10001005
10011006 @cache .memoize (timeout = 5 * 60 )
10021007 def get_pourbaix_diagram (pourbaix_entries , ** kwargs ):
@@ -1006,16 +1011,24 @@ def get_pourbaix_diagram(pourbaix_entries, **kwargs):
10061011 Output (self .id ("graph-panel" ), "children" ),
10071012 Output (self .id ("invalid-comp-alarm" ), "displayed" ),
10081013 Output (self .id ("invalid-conc-alarm" ), "displayed" ),
1014+ Output (self .id ("display-composition" ), "children" ),
10091015 Input (self .id (), "data" ),
10101016 Input (self .id ("display-composition" ), "children" ),
10111017 Input (self .get_all_kwargs_id (), "value" ),
10121018 Input (self .id ("comp-btn" ), "n_clicks" ),
10131019 State (self .id ("elements-store" ), "data" ),
10141020 State (self .id ("comp-text" ), "value" ),
1021+ Input (self .id ("element_specific_controls" ), "children" ),
10151022 prevent_initial_call = True ,
10161023 )
10171024 def make_figure (
1018- pourbaix_entries , dependency , kwargs , n_clicks , elements , comp_text
1025+ pourbaix_entries ,
1026+ dependency ,
1027+ kwargs ,
1028+ n_clicks ,
1029+ elements ,
1030+ comp_text ,
1031+ dependency2 ,
10191032 ) -> go .Figure :
10201033 # show_heatmap, heatmap_choice, filter_solids
10211034
@@ -1030,27 +1043,26 @@ def make_figure(
10301043
10311044 if len (raw_comp_list ) != len (elements ):
10321045 logger .error ("Invalid composition input!" )
1033- return (
1034- self .get_figure_div (),
1035- True ,
1036- False ,
1037- )
1046+ return (self .get_figure_div (), True , False , "" )
10381047 try :
10391048 # avoid direct type casting because string inputs may raise errors
10401049 comp_list = [float (t ) for t in raw_comp_list ]
1050+ comp_dict = {el : comp for comp , el in zip (comp_list , elements )}
1051+ comp = Composition (comp_dict )
1052+ formula = Composition (
1053+ comp .get_integer_formula_and_factor ()[0 ]
1054+ ).reduced_formula
1055+
10411056 except Exception :
10421057 logger .error ("Invalid composition input!" )
1043- return (
1044- self .get_figure_div (),
1045- True ,
1046- False ,
1047- )
1058+ return (self .get_figure_div (), True , False , "" )
10481059
10491060 kwargs = self .reconstruct_kwargs_from_state ()
10501061
10511062 pourbaix_entries = self .from_data (pourbaix_entries )
10521063
10531064 # Get heatmap id
1065+ heatmap_entry = None
10541066 if kwargs .get ("show_heatmap" ) and kwargs .get ("heatmap_choice" ):
10551067 # get Entry object based on the heatmap_choice, which is entry_id string
10561068 heatmap_entry = next (
@@ -1065,36 +1077,29 @@ def make_figure(
10651077 for element , coeff in heatmap_entry .composition .items ()
10661078 if element not in ELEMENTS_HO
10671079 }
1080+ """
10681081 else:
10691082 heatmap_entry = None
10701083
10711084 # otherwise, user sets comp_dict
10721085 comp_dict = {}
10731086 # e.g. kwargs contains {"comp-Ag": 0.5, "comp-Fe": 0.5},
10741087 # essentially {slider_name: slider_value}
1075- """
1076- for key, val in kwargs.items():
1077- if "comp" in key: # keys are encoded like "comp-Ag"
1078- el = key.split("-")[1]
1079- comp_dict[el] = val
1080- """
1088+
10811089 comp_dict = {}
10821090 for comp_val, element in zip(comp_list, elements):
10831091 comp_dict[element] = comp_val
10841092
10851093 comp_dict = comp_dict or None
1094+ """
10861095 conc_dict = {}
10871096 # e.g. kwargs contains {"conc-Ag": 1e-6, "conc-Fe": 1e-4},
10881097 # essentially {slider_name: slider_value}
10891098 for key , val in kwargs .items ():
10901099 if "conc" in key : # keys are encoded like "conc-Ag"
10911100 if val is None :
10921101 # if the input is out of pre-defined range, Input will get None
1093- return (
1094- self .get_figure_div (),
1095- False ,
1096- True ,
1097- )
1102+ return (self .get_figure_div (), False , True , "" )
10981103
10991104 el = key .split ("-" )[1 ]
11001105 conc_dict [el ] = val
@@ -1122,6 +1127,7 @@ def make_figure(
11221127 self .get_figure_div (figure = figure ),
11231128 False ,
11241129 False ,
1130+ html .Small (f"Pourbaix composition set to { unicodeify (formula )} ." ),
11251131 )
11261132
11271133 # TODO
0 commit comments