@@ -625,6 +625,188 @@ def _reset_all_tags(self, _=None):
625
625
self .input_selection = None
626
626
self .input_selection = deepcopy (self .selection )
627
627
628
+ class AddingFixedAtomsEditor (ipw .VBox ):
629
+ """Editor for adding tags to atoms."""
630
+
631
+ structure = traitlets .Instance (ase .Atoms , allow_none = True )
632
+ selection = traitlets .List (traitlets .Int (), allow_none = True )
633
+ input_selection = traitlets .List (traitlets .Int (), allow_none = True )
634
+ structure_node = traitlets .Instance (orm_Data , allow_none = True , read_only = True )
635
+
636
+ def __init__ (self , title = "" , ** kwargs ):
637
+ self .title = title
638
+
639
+ self ._status_message = StatusHTML ()
640
+ self .atom_selection = ipw .Text (
641
+ placeholder = "e.g. 1..5 8 10" ,
642
+ description = "Index of atoms" ,
643
+ value = "" ,
644
+ style = {"description_width" : "100px" },
645
+ layout = {"width" : "initial" },
646
+ )
647
+ self .from_selection = ipw .Button (description = "From selection" )
648
+ self .from_selection .on_click (self ._from_selection )
649
+ self .fixed = ipw .BoundedIntText (
650
+ description = "Fixed atoms" , value = 1 , min = 0 , max = 11 , layout = {"width" : "initial" }
651
+ )
652
+ self .add_fixed = ipw .Button (
653
+ description = "Update fixed atoms" ,
654
+ button_style = "primary" ,
655
+ layout = {"width" : "initial" },
656
+ )
657
+
658
+ self .reset_fixed = ipw .Button (
659
+ description = "Reset fixed atoms" ,
660
+ button_style = "primary" ,
661
+ layout = {"width" : "initial" },
662
+ )
663
+ self .reset_all_fixed = ipw .Button (
664
+ description = "Reset all fixed atoms" ,
665
+ button_style = "warning" ,
666
+ layout = {"width" : "initial" },
667
+ )
668
+ self .scroll_note = ipw .HTML (
669
+ value = "<p style='font-style: italic;'>Note: The table is scrollable.</p>" ,
670
+ layout = {"visibility" : "hidden" },
671
+ )
672
+ self .fixed_display = ipw .Output ()
673
+ self .add_fixed .on_click (self ._add_fixed )
674
+ self .reset_fixed .on_click (self ._reset_fixed )
675
+ self .reset_all_fixed .on_click (self ._reset_all_fixed )
676
+ self .atom_selection .observe (self ._display_table , "value" )
677
+ self .add_fixed .on_click (self ._display_table )
678
+ self .reset_fixed .on_click (self ._display_table )
679
+ self .reset_all_fixed .on_click (self ._display_table )
680
+
681
+ super ().__init__ (
682
+ children = [
683
+ ipw .HTML (
684
+ """
685
+ <p>
686
+ Fix x,y,z for selected atoms. <br>
687
+ For example, 0 1 0 for a given atoms means the atom can move only in y.
688
+ </p>
689
+ <p style="font-weight: bold; color: #1f77b4;">NOTE:</p>
690
+ <ul style="padding-left: 2em; list-style-type: disc;">
691
+ <li>Atom indices start from 1, not 0. This means that the first atom in the list is numbered 1, the second atom is numbered 2, and so on.</li>
692
+ </ul>
693
+ </p>
694
+ """
695
+ ),
696
+ ipw .HBox (
697
+ [
698
+ self .atom_selection ,
699
+ self .from_selection ,
700
+ self .fixed ,
701
+ ]
702
+ ),
703
+ self .fixed_display ,
704
+ self .scroll_note ,
705
+ ipw .HBox ([self .add_fixed , self .reset_fixed , self .reset_all_fixed ]),
706
+ self ._status_message ,
707
+ ],
708
+ ** kwargs ,
709
+ )
710
+
711
+ def _display_table (self , _ = None ):
712
+ """Function to control fixed_display
713
+ When given a list of atom in selection it will display a HTML table with Index, Element and fixed coordinates
714
+ """
715
+ selection = string_range_to_list (self .atom_selection .value )[0 ]
716
+ selection = [s for s in selection if s < len (self .structure )]
717
+ current_fixed = self .structure .get_fixed ()
718
+ chemichal_symbols = self .structure .get_chemical_symbols ()
719
+
720
+ if selection and (min (selection ) >= 0 ):
721
+ table_data = []
722
+ for index in selection :
723
+ fixed = current_fixed [index ]
724
+ symbol = chemichal_symbols [index ]
725
+ if fixed == 0 :
726
+ fixed = ""
727
+ table_data .append ([f"{ index + 1 } " , f"{ symbol } " , f"{ fixed } " ])
728
+
729
+ # Create an HTML table
730
+ table_html = "<table>"
731
+ table_html += "<tr><th>Index</th><th>Element</th><th>Fixed</th></tr>"
732
+ for row in table_data :
733
+ table_html += "<tr>"
734
+ for cell in row :
735
+ table_html += f"<td>{ cell } </td>"
736
+ table_html += "</tr>"
737
+ table_html += "</table>"
738
+
739
+ # Set layout to a fix size
740
+ self .fixed_display .layout = {
741
+ "overflow" : "auto" ,
742
+ "height" : "100px" ,
743
+ "width" : "150px" ,
744
+ }
745
+ with self .fixed_display :
746
+ clear_output ()
747
+ display (HTML (table_html ))
748
+ self .scroll_note .layout = {"visibility" : "visible" }
749
+ else :
750
+ self .fixed_display .layout = {}
751
+ with self .fixed_display :
752
+ clear_output ()
753
+ self .scroll_note .layout = {"visibility" : "hidden" }
754
+
755
+ def _from_selection (self , _ = None ):
756
+ """Set the atom selection from the current selection."""
757
+ self .atom_selection .value = list_to_string_range (self .selection )
758
+
759
+ def _add_fixed (self , _ = None ):
760
+ """Add fixed coordinates to the selected atoms."""
761
+ if not self .atom_selection .value :
762
+ self ._status_message .message = """
763
+ <div class="alert alert-info">
764
+ <strong>Please select atoms first.</strong>
765
+ </div>
766
+ """
767
+ else :
768
+ selection = string_range_to_list (self .atom_selection .value )[0 ]
769
+ new_structure = deepcopy (self .structure )
770
+ if not new_structure .get_fixed ().any ():
771
+ new_fixed = np .zeros (len (new_structure ))
772
+ else :
773
+ new_fixed = new_structure .get_fixed ()
774
+ new_fixed [selection ] = self .fixed .value
775
+ new_structure .set_fixed (new_fixed )
776
+ self .structure = None
777
+ self .structure = deepcopy (new_structure )
778
+ self .input_selection = None
779
+ self .input_selection = deepcopy (self .selection )
780
+
781
+ def _reset_fixed (self , _ = None ):
782
+ """Clear fixed coordinates from selected atoms."""
783
+ if not self .atom_selection .value :
784
+ self ._status_message .message = """
785
+ <div class="alert alert-info">
786
+ <strong>Please select atoms first.</strong>
787
+ </div>
788
+ """
789
+ else :
790
+ selection = string_range_to_list (self .atom_selection .value )[0 ]
791
+ new_structure = deepcopy (self .structure )
792
+ new_fixed = new_structure .get_fixed ()
793
+ new_fixed [selection ] = 0
794
+ new_structure .set_fixed (new_fixed )
795
+ self .structure = None
796
+ self .structure = deepcopy (new_structure )
797
+ self .input_selection = None
798
+ self .input_selection = deepcopy (self .selection )
799
+
800
+ def _reset_all_fixed (self , _ = None ):
801
+ """Clear all fixed coordinates."""
802
+ new_structure = deepcopy (self .structure )
803
+ new_fixed = np .zeros (len (new_structure ))
804
+ new_structure .set_fixed (new_fixed )
805
+ self .structure = None
806
+ self .structure = deepcopy (new_structure )
807
+ self .input_selection = None
808
+ self .input_selection = deepcopy (self .selection )
809
+
628
810
629
811
class PeriodicityEditor (ipw .VBox ):
630
812
"""Editor for changing periodicity of structures."""
0 commit comments