-
Notifications
You must be signed in to change notification settings - Fork 0
/
HybridTopologyViewer.py
executable file
·2640 lines (1826 loc) · 81.9 KB
/
HybridTopologyViewer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
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
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python3
from logging.config import dictConfig
import os
from inspect import signature
from random import randrange
import threading
import pymol
import sys
from tkinter.tix import CheckList
import traceback
import csv
import re
from pymol import cmd
import numpy as np
'''
Opens PyMOL with a given pdb-input file and creates
a selection of all the different rgroups, the backbone,
proteins and solvents.
After PyMOL has started up, there is also the possibility to call additional functions from the terminal
When adding new arguments to functions, be sure to update 'variable_dict' in 'read_input' as well. Its keys are used and kwargs.
Also check the expected input types and adjust them in the corresponding lists in 'check_inputs'.
Author: Rene Gall
'''
# List of aminoacids
AA_LIST = ["ALA", "ARG", "ASN", "ASP", "CYS", "GLU", "GLN", "GLY", "HIS", "ILE", "LEU", "LYS", "MET", "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL"]
# List of unnatural aminoacids (can be expanded for additional aa)
AA_UNNAT_LIST = ['CYSH', 'HIE', 'HISB', 'CYX', 'NME', 'ACE']
aa_list = [aa.lower() for aa in AA_LIST + AA_UNNAT_LIST]
IONS = ['CL', 'cl', 'cl-', 'NA' 'na', 'na+', 'MG', 'mg', 'mg+']
# Default input_dict
INPUT_DICT_DEFAULT = {"file": None,
"ptp_file": None,
"representation_molecule": 'sticks',
"representation_solvent": '',
"representation_protein": 'cartoon',
"representation_singleatom": 'nb_sphere',
"peptide_atom_number": [],
"combine_aa_to_protein": True,
"core_bound_to_rgroup": True,
"verbose": True}
# Colors for PyMOL
HELIX_COLOR = '0xF00080' # magenta
SHEET_COLOR = '0xFFFF00' # yellow
LOOP_COLOR = '0xFFFFFF' # white
MOLECULE_COLOR = [[200, 200, 200], [50, 50, 50]] # grey
ADDITIONAL_SELECTION_COLOR = [[192, 250, 188], [113, 225, 105]] # green
def add_entry_to_dict(dict_add: dict, dict_key, dict_value) -> None:
'''
Usage
-----------
Add an element to a dictionary. If the key is already present, it will be added to the key as an additional entry,
otherwise a new key is created and the entry added.
Parameters
-----------
dict_add: dict
The dictionary the value is added to
dict_key:
key to which the value is added.
dict_value:
value to be added
'''
# Check if key exists:
if dict_key in dict_add.keys():
dict_add[dict_key].append(dict_value)
return
# Key does not exist
# Check if value is a list
if isinstance(dict_value, list):
dict_add[dict_key] = [dict_value]
return
# Value not a list
dict_add[dict_key] = dict_value
return
def atom_dict_to_list(atom_dict: dict,
skip_solvent: bool = True, skip_protein: bool = True) -> list:
'''
Usage
---------
Takes the atom dict and turns it into a list. The list index corresponds to the atom and
the entry to the molecule name
Parameters:
---------
atom_dict: dict
dictionary containing the names and atom indices of the molecules
skip_solvent: bool (Default: True)
Skips all molecules with "solv_" in name.
skip_protein: bool (Default: True)
Skips all molecules with "PROTEIN_" in name.
Returns
---------
list of atom dictionary
'''
atom_molecule_list = [0]
# Loop through molecules
for molecule in atom_dict:
# Check for solvent
if skip_solvent and "solv_" in molecule:
continue
# Check for protein
if skip_protein and "protein_" in molecule:
continue
# Loop through atoms
for atom in atom_dict[molecule]:
# Write atoms to list
atom_molecule_list.append(molecule)
return atom_molecule_list
def check_file(filepath: str) -> str:
'''
Usage
-----------
Checks if the filename is absolute or not and if the file exists. If it exists, the absolute path is returned.
Parameters
-----------
filename: str
Filename to check
Returns
-----------
returns the absolut path to the file
'''
# Check if filepath is absolute, else add current directory
if not os.path.isabs(filepath):
print('# No absolute path given. Using the current directory.')
filepath = os.path.join(os.getcwd(), filepath)
# Check if file exists
if not os.path.isfile(filepath):
print(f"# The given file '{filepath}' does not exist. Please check the filename and path and try again. Program terminated.")
exit(1)
# File exists, return full absolute path
return filepath
def check_input(check_dict: dict) -> None:
'''
Usage
-----------
Checks if all inputs are of the correct type
Parameters
-----------
check_dict: dict
Dictionarry to check
Returns
-----------
raises SystemExit if something is missing or wrong
'''
# Check if filename was given
if 'file' not in check_dict.keys() or check_dict['file'] == '':
print('# No filename was given. Program terminated.')
# Check, if all entries have correct types.
bool_types = ['combine_aa_to_protein', 'core_bound_to_rgroup', 'rgroup_lowest_number', 'verbose']
str_types = ['file', 'representation_molecule', 'representation_solvent', 'representation_protein', 'representation_singleatom']
list_types = ['peptide_atom_number', 'coreatom_in_lower_atomindex']
for entries in check_dict.keys():
# Check for bools
if entries in bool_types:
if not isinstance(check_dict[entries], bool):
print(f"# Bool expected for '{entries}'. '{type(check_dict[entries])}' gotten. Program terminated.")
exit(1)
# Check for strings
elif entries in str_types:
if not isinstance(check_dict[entries], str):
print(f"# String expected for '{entries}'. '{type(check_dict[entries])}' gotten. Program terminated.")
exit(1)
# Check for lists
elif entries in list_types:
if not isinstance(check_dict[entries], list):
print(f"# List expected for '{entries}'. '{type(check_dict[entries])}' gotten. Program terminated.")
exit(1)
return
def clean_up_dictionary(clean_up_dict: dict, default_dict: dict=None, clean_up_value = None,
set_bools: bool = True) -> None:
'''
Usage
-----------
Removes all keys with the clean up value and sets them to the default ones. If none is given, delete the elements instead.
Also sets bools that were strings to real bools and lists to lists.
Parameters
-----------
clean_up_dict: dict
Dictionarry to clean up
default_dict: dict (default: None)
dictionary that contains the default values to be set.
clean_up_value (default: None):
Value which note a key to delete
set_bools: bool (Default: True)
Decides if the strings "True" and "False" should be converted to real bools.
'''
for entries in list(clean_up_dict.keys()):
# Check for entries with noted value
if clean_up_dict[entries] == clean_up_value:
# If default dictionary is given, replace entries, else delete them
if default_dict is not None:
clean_up_dict[entries] = default_dict[entries]
continue
del clean_up_dict[entries]
continue
# Change bools
if set_bools:
change_bool = clean_up_dict[entries]
# Check if Bool in string
if change_bool == "True":
clean_up_dict[entries] = True
continue
elif change_bool == "False":
clean_up_dict[entries] = False
continue
return
def combine_elements_to_list(list_to_change:list) -> list:
'''
Usage
-----------
Takes a list which has separated elements of a list (i. e. list=['x', 'y', '[1', '2', '3]']) and combines them into a list
Parameters:
-----------
list_to_change: list
list containing a split list
Returns:
-----------
redone list
'''
new_list = [] # New list to be created
list_in_list = [] # Save list of lists.
list_found = False
for element in list_to_change:
# Check for list characters (i. e. '[' and ']')
if element[0] == '[' and element[-1] == ']':
list_in_list.append(element[1:-1])
new_list.append(list_in_list)
continue
if element[0] == '[':
# new list found. Add element between bracket and comma
list_in_list.append(element[1:-1])
list_found = True
continue
if element[-1] == ']':
# End of list
list_in_list.append(element[:-1])
list_found = False
# Add list to new list
new_list.append(list_in_list)
# Reset list in list
list_in_list = []
continue
# Add element if currently in list (remove comma at)
if list_found:
list_in_list.append(element[:-1])
continue
# No list element
new_list.append(element)
return new_list
def create_connection_table(connection_table: list,
main_atom: int, connected_atoms: int) -> None:
'''
Usage
-----------
Add atoms to the connection table. The connections are saved in the index positions, the elements between are filled with 0
Parameters
-----------
connection_table: list
list to add connections to.
main_atom: int
is the atom, to which the connected atoms are connected. The number corresponds to the index in the list
conneted_atoms: int
The connected atoms.
'''
# Check, if main atom already in list
if len(connection_table) > main_atom:
connection_table[main_atom].append(connected_atoms)
# Main atom not yet in list.
else:
# Add 0 to all unconnected indices
while len(connection_table) != main_atom:
connection_table.append(0)
connection_table.append([connected_atoms])
return
def distribute_colors(min_color: list, max_color: list,
length: int) -> list:
'''
Usage
----------
Takes in two lists of rgb-values and evenly distributes the colors
Parameters
----------
min_color: list
lower bound of the color ranges
max_color:
upper bound of the color ranges
length: int
amount of points to be distributed.
returns
-------
list of list with each rgb-value
'''
# Get distributed colors
red = np.linspace(min_color[0], max_color[0], length)
green = np.linspace(min_color[1], max_color[1], length)
blue = np.linspace(min_color[2], max_color[2], length)
# combine lists
color_list = []
for color in range(0, length):
color_list.append([red[color], green[color], blue[color]])
return color_list
def expand_connection_table(connection_table: list) -> list:
'''
Usage
----------
Fills out all the connections in the connection table with every connection
Parameters
----------
connection_table: list
connection_table to be expanded
returns
-------
expanded connection table
'''
# expanded table, first element to 0. List index corresponds to atomindex
# Get maximal value from connection table to create new list
max_value = max_value_nested_list(connection_table)
connection_table_expanded = [[] for _ in range(0, max_value + 1)]
# Loop over all atoms in the connection table
for atoms, connections in enumerate(connection_table):
# Skip if connections are 0
if connections == 0:
continue
# Check if atom included in the connected atom
for connected_atoms in connections:
if not atoms in connection_table_expanded[connected_atoms]:
connection_table_expanded[connected_atoms].append(atoms)
# Add connection to current atom
connection_table_expanded[atoms].append(connected_atoms)
return connection_table_expanded
def get_connections(atom_index: str,
connection_table: list, atom_molecule_list: list, rgroup_connected_atoms: list = []) -> list:
'''
Usage
----------
Looks through all connections of a given atom and returns all connected atoms except for core atoms
Parameters
----------
atom_index: str
index of atom to be checked
connection_table: list
contains the connection table
atom_molecule_list: list
List of atom dict, where the atom indices are the list indices and the values the corresponding molecule
rgroup_connected_atoms: list (Default: [])
List of r-group connected atoms to be excluded.
returns
-------
List of connections
'''
# Get current molecule and only add connections within this molecule
current_molecule = atom_molecule_list[atom_index]
# Start with first connection
connections = [atom_index]
# Loop over all connections in list
for atoms in connections:
# Skip atoms without connections in table
if connection_table[atoms] == 0:
continue
# Loop over connected atoms
for connected_atoms in connection_table[atoms]:
# Add to list if not already in and not a core atom and not from different molecule
if connected_atoms not in connections and connected_atoms not in rgroup_connected_atoms and atom_molecule_list[connected_atoms] == current_molecule:
connections.append(connected_atoms)
return list(connections)
def get_rgroup_connections(atom_dict: dict, connection_table: list,
verbose: bool = True, **kwargs) -> list:
'''
Usage
----------
Search for a core structure in a rgroup-core-system
Parameters
----------
atom_dict: dict
dictionarry containing all molecule names as keys and corresponding atoms as lists
connection_table: list
contains the connection table
verbose: bool (default True):
Tells the user what the program is doing
returns
-------
list of rgroup connected atoms
'''
if verbose:
print("# Looking for r-group connected atoms.")
# Store atoms which are connected to multiple r-groups
rgroup_connected_atoms = []
# Convert dictionary to list, where the index is the atom and the entry the corresponding molecule
atom_molecule_list = atom_dict_to_list(atom_dict)
# Loop through connection table
for i, connected_atoms_list in enumerate(connection_table):
# Skip lines with 0
if connected_atoms_list == 0:
continue
# Get current molecule and stop if r-groups are finished (no more entries in the shortened atom list)
if i > len(atom_molecule_list):
break
current_molecule = atom_molecule_list[i]
# Check if connections belong to different molecule and add atom to r-group connecting atoms
for connections in connected_atoms_list:
if atom_molecule_list[connections] != current_molecule:
rgroup_connected_atoms.append(i)
break
# Check if r-group connecting atoms were found
if len(rgroup_connected_atoms):
# r-group connecting atoms found. Going on to separate r-groups and cores
if verbose:
print(f"# The r-group connected atoms '{rgroup_connected_atoms}' were found. Going on to separate r-groups from cores.")
# No r-group connecting atoms were found. Aborting separation.
else:
if verbose:
print("# No r-group connected atoms could be found. No separation between r-group and potential cores possible. Continuing with program.")
# Return core atoms
return rgroup_connected_atoms
def read_ptp(filename):
'''
Usage
----------
Reads information in the perturbed topology file to figure out the atom
type codes of all atoms (in each of their perturbed states)
Parameters
----------
filename: str
path to the ptp file
returns
-------
atom_type:
numpy array of the atom type codes (for all atoms in all perturbed states)
dummy_iac:
atom type code of the dummy atoms
'''
read = False
data = []
for line in open(filename, 'r'):
if 'ATOM' in line: read = True
if 'END' in line: read = False
if '#' in line or not read: continue
data.append(line.split())
num_atoms = int(data[1][0])
num_states = int(data[1][1])
# Then go through the data line by line to find the atom types assigned to each state
atom_types = []
for atom in data:
if len(atom) < num_states *2 + 4:
continue # don't read lines that are not atoms (potential comments, header, etc.)
atom_types.append(atom[2:-2:2])
# convert the data to numpy array
atom_types = np.array(atom_types, dtype=int)
# Take the dummy atom type code as the maximum number (gromos convention)
dummy_iac = np.max(atom_types)
return atom_types, dummy_iac
def assign_to_groups_from_ptp(atom_dict, atom_types, dummy_iac):
'''
Usage
----------
Sets all values in the atom_dict properly based on the atom type information
read from the ptp file
Parameters
----------
atom_dict: dict
dictionarry containing all molecule names as keys and corresponding atoms as lists
returns
-------
atom_dict: dict
updated atom_dict
'''
# Number of ligands = number of perturbed states
num_ligs = len(atom_types[0])
print ('num_ligs= ' + str(num_ligs))
lig_keys = [k for k in atom_dict.keys() if k[0] == 'l']
# Clear all current ligand selections
for k in lig_keys:
atom_dict[k] = []
atom_dict['core'] = []
for i, atom in enumerate(atom_types):
if np.alltrue(atom != dummy_iac):
atom_dict['core'].append(i+1)
for k in lig_keys:
atom_dict[k].append(i+1)
else:
for j, k in zip(atom, lig_keys):
if j != dummy_iac:
atom_dict[k].append(i+1)
return atom_dict
def max_value_nested_list(check_list: list) -> int:
'''
Usage
-----------
Finds the highest integer in a nested list containing lists and integers.
Parameters:
-----------
check_list: list
list of lists to be searched through
'''
max_value = 0
for index, values in enumerate(check_list):
# Check if entry is integer or list
if isinstance(values, int):
if values > max_value:
max_value = values
continue
continue
# Get highest element in each list
if max(values) > max_value:
max_value = max(values)
continue
return max_value
def pymol_additional_function(atom_dict: dict, rgroup_connected_atoms_list: list, input_dict: dict) -> None:
'''
Usage
---------
Lets the user enter a command from the terminal to execute additional functions in PyMOL
Parameters:
---------
atom_dict: dict
dictionary containing the names and atom indices of the molecules
rgroup_connected_atoms_list: list
list with all the core atoms
input_dict: dict
dictionary with all user defined inputs
'''
print("# Everything loaded. Additional commands possible. For help, please enter 'help'.\n")
# Dict with all possible functions to call, including their parameters
possible_functions = {'change_atoms' : 'Input: atoms_to_change (list), selection_they_are_in (str), selection_to_move_to (str, optional)\n\t\t\t\tThe atomindices of the atoms which should be removed from the given selection can be entered.\n\t\t\t\tIf they should be moved to a different selection, the new selection can be added as well (all atoms go to the same new selection).',
'change_representation' : '\tInput: selection_name (str), representation (str)\n\t\t\t\tChanges the given selection to the given representation.',
'create': '\t\t\tInput: new_name (str), selection_name (str, optional), atom_index (str, optional) \n\t\t\t\tThe selection names and or atom indices may be given to create a new selection. Please enter selections befor atom indices',
'hide': "\t\t\tInput: selection_name (list) \n\t\t\t\tWill hide the given selection names. If all should be hidden enter 'all'",
'hide_id': '\t\t\tInputs: selection_name (list)\n\t\t\t\tWill hide the atom ID of the given selections',
'print_rgroup_connections': '\tPrints a list of found r-group connecting atoms.',
'remove_additional_selections': 'Input: None\n\t\t\t\tDeletes all additional sections while keeping changes made to the original selections (like atom swapping). However, a renamed selection will be deleted as well.',
'rename': '\t\t\tInputs: name_to_change (str), name_to_change_into (str)\n\t\t\tUsed, if a selection should be renamed. The first name is the name of the current selection, the second name the new one.',
'restart': '\t\t\tInput: None\n\t\t\t\the PyMOL-Session will be reset to the inital startup, meaning all changes to selection names, new selections and atom swaps will be unmade.',
'show_id':'\t\t\tInputs: selection_name (list)\n\t\t\t\tWill show the atom ID of the given selections.',
'show_protein_residues': "\tInputs: list_of_residuenumbers (list), representation (str, optional)\n\t\t\t\tThe given protein residues will be selected and shown (only enter the numbers, e.g. ALA46 -> 46).\n\t\t\t\tUseful for showing certain residues in cartoon mode. Without representation input, the default one or the one given for 'representation_molecule' is chosen.",
'show': "\t\tInput: selection_name (list), representation 'rep_xxx' (str, optional)\n\t\t\t\tThe given representations will be made visible with the given selection. This also works to change the current representation. If all selections should be changed, enter 'all'.\n\t\t\t\tThe representation has to be given last and must start with 'rep_'If no representation is given, the user defined representation or the default one will be taken.",
'sort': '\t\t\tInput: None\n\t\t\t\tWill sort all current selections in PyMOL in descending order.',
'quit': "\t\t\tInput: None\n\t\t\t\tWill terminate the PyMOL-session and end the program. Regular termination by closing PyMOL is also possible."
}
# Stay in response mode
while True:
try:
# Get user input
command_input = input()
# Check for help command
if 'help' in command_input or command_input == "":
print("\n#####################################################################################")
print("Additional commands can now be eyntered.\nThe possible functions are:\n\n")
for function, info in possible_functions.items():
print(function + "\t" + info + '\n')
print("\nThe individual inputs to the functions (if necessary) can be given without commas, except lists. They should be given as usual with [1, 2, ..., ]")
print("#####################################################################################\n")
continue
# Extract inputs
input_list = command_input.rsplit()
# Get length
input_length = len(input_list)
# Get command
command = input_list[0]
# Check if inputfunction is in dict
if command not in possible_functions.keys():
print("# Function '" + input_list[0] + "' not known. Please check and try again or enter 'help' for a list of all functions.")
continue
# Check which function is called
# CHANGE_ATOMS
if command == 'change_atoms':
# Get inputs back into list
input_list = combine_elements_to_list(input_list)
# Check number of inputs
if len(input_list) < 3:
print("# Please enter the atom indices to change and the current selection")
continue
if len(input_list) == 3:
pymol_change_atoms_in_selection([input_list[1]], input_list[2])
else:
pymol_change_atoms_in_selection(input_list[1], input_list[2], input_list[3])
# CHANGE_REPRESENTATION
elif command == 'change_representation':
# Check inputs
if len(input_list) < 3:
print("# Please provide a selection and a representation.")
continue
pymol_change_representation(input_list[1], input_list[2])
# CREATE
elif command == 'create':
# Get inputs back into list
input_list = combine_elements_to_list(input_list)
# Check inputs
if len(input_list) < 3:
print("# Please provide at least the new selection and one atom or selection.")
continue
pymol_create_new_selection(input_list[1], input_list[2:], atom_dict.keys())
# HIDE_ID
elif command == 'hide_id':
# Check inputs
if len(input_list) < 2:
print("# Please provide at least one selection.")
continue
pymol_hide_id(input_list[1:])
# HIDE
elif command == 'hide':
# Check inputs
if len(input_list) < 2:
print("# Please provide at least one selection.")
continue
pymol_hide_selections(input_list[1:])
# PRINT_RGROUP_CONNECTIONS
elif command == 'print_rgroup_connections':
pymol_print_rgroup_connected_atoms(rgroup_connected_atoms_list)
# REMOVE_ADDITIONAL_SELECTIONS
elif command == 'remove_additional_selections':
print("# All additional selections will be deleted and only the original ones and changes made to them will be kept. Continue (y/n)?")
if input() == 'y':
pymol_remove_additional_selections(atom_dict)
# RENAME
elif command == 'rename':
# Check if two names are given
if input_length < 3:
print("# Please enter the old and the new name.")
continue
elif input_length > 3:
print("# Please only enter one old and one new name.")
continue
pymol_rename_selection(input_list[1], input_list[2])
# RESTART
elif command == 'restart':
print("# All changes made during the PyMOL-Session will be undone. Continue (y/n)?")
if input() == 'y':
pymol_restart(atom_dict, input_dict)
# SHOW_ID
elif command == 'show_id':
# Check inputs
if len(input_list) < 2:
print("# Please provide at least one selection.")
continue
pymol_show_id(input_list[1:])
# SHOW_PROTEIN_RESIDUE
elif command == 'show_protein_residues':
# Get inputs back into list
input_list = combine_elements_to_list(input_list)
# Check inputs
if len(input_list) < 2:
print("# Please enter at least a list of residue numbers and optionally the preferred representation.")
continue
# Check for optional representation
if len(input_list) == 3:
pymol_show_protein_residues(input_list[1], input_list[2])
else:
pymol_show_protein_residues(input_list[1], input_dict['representation_molecule'])
# SHOW
elif command == 'show':
# Check inputs
if len(input_list) < 2:
print("# Please provide at least one selection.")
continue
# Check if representation is also given
if input_list[-1][0:4] == 'rep_':
pymol_show_selections(input_list[1:-1], input_list[-1][4:])
else:
pymol_show_selections(input_list[1:])
# SORT
elif command == 'sort':
pymol_sort_selection()
# QUIT
elif command == "quit":
print("# Program is terminating.")
cmd.quit()
return
print("# Command executed. Waiting for next command.")
except Exception:
print("\n#####################################################################################")
print("# Unfortunately something went wrong with the previous command. Please try again. The following message specifies the issue:")
print("#####################################################################################\n")
traceback.print_exception(*sys.exc_info())
print("\n# Waiting for next command.")
return
def pymol_change_atoms_in_selection(atom_index: list, current_selection: str, new_selection: str = None) -> None:
'''
Usage
-----------
Takes a list of atom indices and deletes them from the current selection. If a new selection is given, they are copied into the new one
Parameters
-----------
atom_index: list
list of atoms to be changed
current_selections: str
name of selection the atoms are currently in
new_selection: str (Default: None)
name of new selection, the old atoms should be moved into.
'''
selections = cmd.get_names('all')
# Check if selection is available
if current_selection not in selections:
print(f"# The selection '{current_selection}' is not available. Please check and try again.")
return
# Check if new selection is given and it is available
if new_selection is not None and new_selection not in selections:
print(f"# The selection '{current_selection}' is not available. Please check and try again.")
return
# Hide old atoms