<jupyter_start><jupyter_text>Map Mutations to Protein-Drug InteractionsHere we find and visualize the mutations at protein-drug binding sites<jupyter_code>from mmtfPyspark.datasets import drugBankDataset, customReportService, pdbjMineDataset
from ipywidgets import interact, IntSlider
import py3Dmol
import pandas as pd<jupyter_output><empty_output><jupyter_text>Input parameters<jupyter_code>cutoff_distance = 8  # cutoff distance for finding and visualizing interactions
mw_min = 250  # minimum molecular weight for drug molecules
input_file_name = 'mutations3d_ligand.csv'  # mutations mapped to protein-ligand binding sites
output_file_name = 'mutations3d_drug.csv'  # mutations mapped to protein-drug binding sites<jupyter_output><empty_output><jupyter_text>Read 'mutation3d_ligand.csv' file created in the previous step<jupyter_code>df = pd.read_csv(input_file_name)
df['pdbPosition'] = df['pdbPosition'].astype('str') # PDB residue numbers must be string to handle insertion codes
df['queryLigandNumber'] = df['queryLigandNumber'].astype('str')
df.head()<jupyter_output><empty_output><jupyter_text>Get InChiKey for ligands in PDB with molecular weight >= 250<jupyter_code>ccQuery = "SELECT c.id as ligand_id, c.formula_weight, d.descriptor as inchi_key FROM pdbj.chem_comp c \
           JOIN cc.pdbx_chem_comp_descriptor d ON d.comp_id = c.id \
           WHERE d.type = 'InChIKey' AND c.formula_weight >= " + str(mw_min)

ligands = pdbjMineDataset.get_dataset(ccQuery).dropDuplicates().toPandas()
ligands.head()<jupyter_output><empty_output><jupyter_text>Join dataset on ligand id to add InchiKeys<jupyter_code>df = df.merge(ligands, left_on=['queryLigandId'], right_on=['ligand_id'], how='inner')
df = df.drop_duplicates()
df.head()<jupyter_output><empty_output><jupyter_text>Download open DrugBank dataset¶ For this demo we use the open DrugBank dataset. One disadvantage of the open DrugBank dataset is that in not only contains approved drugs, but many other compounds in pharmaceutical use such as ethanol, ATP, etc.<jupyter_code>drugs = drugBankDataset.get_open_drug_links() \
                       .filter("StandardInChIKey IS NOT NULL") \
                       .filter("CAS IS NOT NULL") \
                       .toPandas()<jupyter_output><empty_output><jupyter_text>The DrugBank password protected datasets contain more information (e.g., approval status). To use these datasets, you need to create a free DrugBank account and supply username/passwork to access these datasets. For this demo, we continue with the open drug bank dataset. [Create DrugBank account](https://www.drugbank.ca/public_users/sign_up)<jupyter_code># username = "<your DrugBank account username>"
# password = "<<PASSWORD> DrugBank account password>"
# drugs = drugBankDataset.get_drug_links("APPROVED", username,password) \
#                        .filter("StandardInChIKey IS NOT NULL") \
#                        .toPandas()<jupyter_output><empty_output><jupyter_text>Print some sample DrugBank data<jupyter_code>drugs.head()
df = df.merge(drugs, left_on=['inchi_key'], right_on=['StandardInChIKey'], how='inner')
df.head()<jupyter_output><empty_output><jupyter_text>Keep only unique ligands per structureHere we drop rows with the same structureId and ligandId.  Save protein-ligand mapping<jupyter_code>df.to_csv(output_file_name, index=False)<jupyter_output><empty_output><jupyter_text>View mutations grouped by protein chainUse the slider to view each protein chain. Turn labels off for an unobstructed view of the mutations. Interacting ligands are rendered as spheres with green carbon atoms.<jupyter_code>chains = df.groupby('structureChainId')
print("Chains:", list(chains.groups.keys()))
def view_grouped_mutations(grouped_df, cutoff_distance, *args):
    chainIds = list(grouped_df.groups.keys())

    def view3d(show_bio_assembly=False, show_surface=False, show_labels=True, i=0):
        group = grouped_df.get_group(chainIds[i])
        
        pdb_id, chain_id = chainIds[i].split('.')
        viewer = py3Dmol.view(query='pdb:' + pdb_id, options={'doAssembly': show_bio_assembly})

        # polymer style
        viewer.setStyle({'cartoon': {'colorscheme': 'chain', 'width': 0.6, 'opacity':0.9}})

        # highlight chain of interest in blue
        viewer.setStyle({'chain': chain_id},{'cartoon': {'color': 'blue'}})
   
        # non-polymer style
        viewer.setStyle({'hetflag': True}, {'stick':{'radius': 0.3, 'singleBond': False}})
        
        # don't display water molecules
        viewer.setStyle({'resn': ['HOH','DOD']}, {})
        
        rows = group.shape[0]
        for j in range(0, rows):
            # interacting residue info
            res_num = str(group.iloc[j]['pdbPosition'])
            mod_res = {'resi': res_num, 'chain': chain_id}
            
            # interacting ligand info
            lig_id = group.iloc[j]['queryLigandId']
            lig_chain = group.iloc[j]['queryLigandChainId']
            lig_num = group.iloc[j]['queryLigandNumber']
            lig_name = df.iloc[i]['Commonname']
            lig_res = {'resi': lig_num, 'chain': lig_chain}
            
            col = 'red'
            c_col = col + 'Carbon'
            viewer.addStyle(mod_res, {'stick':{'colorscheme':c_col, 'radius': 0.2}})
            viewer.addStyle(mod_res, {'sphere':{'color':col, 'opacity': 0.6}})   
            viewer.addStyle(lig_res, {'sphere': {'colorscheme': 'greenCarbon'}})
            
            if show_labels:
                label = group.iloc[j]['variationId']
                viewer.addLabel(label, {'fontSize':9,'fontColor': 'black','backgroundColor':'ivory'}, mod_res)
                viewer.addLabel(lig_name, {'fontSize':9}, lig_res)

        viewer.zoomTo({'chain': chain_id})
        
        if show_surface:
             viewer.addSurface(py3Dmol.SES,{'opacity':0.8,'color':'lightblue'},{'chain': chain_id})
                
        #print header
        print("PDB Id: " + pdb_id + " chain Id: " + chain_id)
        
        # print any specified additional columns from the dataframe
        for a in args:
            print(a + ": " + group.iloc[j][a])
                
        return viewer.show()
       
    s_widget = IntSlider(min=0, max=len(chainIds)-1, description='Structure', continuous_update=False)
    
    return interact(view3d, show_bio_assembly=False, show_surface=False, show_labels=True, i=s_widget)<jupyter_output><empty_output><jupyter_text>Turn off scrolling in the viewer cell below<jupyter_code>%%javascript 
IPython.OutputArea.prototype._should_scroll = function(lines) {return false;}
view_grouped_mutations(chains, cutoff_distance);<jupyter_output><empty_output><jupyter_text>View one mutation at a timeUse the slider to view each mutation. Surrounding residues within the `cutoff_distance` are rendered as orange sticks. Interacting ligands are rendered as spheres with green carbon atoms.<jupyter_code>def view_single_mutation(df, cutoff_distance, *args):

    def view3d(show_bio_assembly=False, show_surface=False, show_labels=True, i=0):        
        pdb_id, chain_id = df.iloc[i]['structureChainId'].split('.')
        
        viewer = py3Dmol.view(query='pdb:' + pdb_id, options={'doAssembly': show_bio_assembly})

        # polymer style
        viewer.setStyle({'cartoon': {'colorscheme': 'chain', 'width': 0.6, 'opacity':0.7}})
       
        # highlight chain of interest in blue
        viewer.setStyle({'chain': chain_id},{'cartoon': {'color': 'blue', 'width': 0.6, 'opacity':0.5}})
        
        # non-polymer style
        viewer.setStyle({'hetflag': True}, {'stick':{'radius': 0.3, 'singleBond': False}})
        
        # don't display water molecules
        viewer.setStyle({'resn': ['HOH','DOD']}, {})
        
        # interacting residue info
        res_num = str(df.iloc[i]['pdbPosition'])
        mod_res = {'resi': res_num, 'chain': chain_id}
        
        # interacting ligand info
        label = df.iloc[i]['variationId']  
        
        lig_id = df.iloc[i]['queryLigandId']
        lig_chain = df.iloc[i]['queryLigandChainId']
        lig_num = df.iloc[i]['queryLigandNumber']
        lig_name = df.iloc[i]['Commonname']
        lig_res = {'resi': lig_num, 'chain': lig_chain}
        lig_label = lig_id + "-" + lig_chain + lig_num + " " + lig_name
        
        col = 'red'
        c_col = col + 'Carbon'
#        viewer.addStyle(mod_res, {'stick':{'colorscheme': c_col, 'radius': 0.2}})
        viewer.addStyle(mod_res, {'sphere':{'color': col, 'opacity': 0.8}})  # TODO opacity has no effect

        if show_labels:
            viewer.addLabel(label, {'fontSize':12,'fontColor': 'black','backgroundColor':'ivory'}, mod_res) 
            viewer.addLabel(lig_label, {'fontSize':10}, lig_res) 
            
        # select neigboring residues by distance
        surroundings = {'chain': chain_id, 'resi': res_num, 'byres': True, 'expand': cutoff_distance}
        
        # residues surrounding mutation site
        viewer.addStyle(surroundings,{'stick':{'colorscheme':'orangeCarbon', 'radius': 0.15}})

        # interacting ligand style
        viewer.addStyle(lig_res, {'sphere': {'colorscheme': 'greenCarbon'}})   
        
    
        if show_surface:
             viewer.addSurface(py3Dmol.SES, {'opacity':0.8,'color':'lightblue'}, {'chain': chain_id})
         
        viewer.zoomTo(surroundings)
        
        # print header
        print("PDB Id:", pdb_id, "chain Id:" , chain_id, "residue:", res_num, "ligand:", lig_id + lig_num, "mutation:", label)
        
        # print any specified additional columns from the dataframe
        for a in args:
            print(a + ": " + df.iloc[i][a])
                
        return viewer.show()
       
    s_widget = IntSlider(min=0, max=len(df)-1, description='Structure', continuous_update=False)
    
    return interact(view3d, show_bio_assembly=False, show_surface=False, show_labels=True, i=s_widget)
view_single_mutation(df, cutoff_distance, 'DrugBankID', 'Commonname');<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12674511368169125, 'fraction_numerical': 0.006382130035899481, 'mean_word_length': 3.4752342704149934, 'pattern_counts': {'":': 2, '<': 52, '<?xml version=': 0, '>': 54, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '515590', 'license': 'Apache-2.0', 'n_tokens_mistral': 3257, 'n_tokens_neox': 3133, 'n_words': 702, 'path': 'pipeline1/5-MapToDrugInteractions.ipynb', 'repo_name': 'upendrak/mmtf-genomics', 'size': '10022'}