Download scripts/getDataFromSAbDab-nano.py from OneScience-Group/NABP-LSTM-Att: direct link, hf CLI and curl.
- Browser
- Download file 13.2 kB
-
https://huggingface.co/OneScience-Group/NABP-LSTM-Att/resolve/main/scripts/getDataFromSAbDab-nano.py
- Command line
-
hf download hf://OneScience-Group/NABP-LSTM-Att/scripts/getDataFromSAbDab-nano.py
-
curl -L -o getDataFromSAbDab-nano.py https://huggingface.co/OneScience-Group/NABP-LSTM-Att/resolve/main/scripts/getDataFromSAbDab-nano.py
13.2 kB
| #This script aims to get the data of Nanobodies and their binding antigens from SAbDab-nano database to 3 csv folders | |
| # each folder contacin number of csvs based on fvs number | |
| import requests | |
| import csv | |
| import pandas as pd | |
| from bs4 import BeautifulSoup | |
| import os | |
| import re | |
| from _bootstrap import DATA_DIR, use_project_root | |
| use_project_root() | |
| def getAllRecords(): | |
| print("Calling All structures page ... ") | |
| url = requests.get(baseUrl+allRecordsEndPoint) | |
| htmltext = url.text | |
| data = pd.read_html(htmltext)[0] | |
| print(str(data.count()["PDB"]) + " PDBs is loaded now, lets save them....") | |
| return data | |
| def writeDataToCSV(recordType, data): | |
| fvsNumber = int(data["basic_data"]["Number of Fvs"]) | |
| empty_6_items = ["","","","","",""] | |
| empty_3_items = ["","",""] | |
| file_dir = str(DATA_DIR / recordType / (str(fvsNumber) + '.csv')) | |
| if recordType == "nano": | |
| headers = ['pdb', 'Hchain', 'Hchain_sequence', 'Heavy subgroup', | |
| 'Species', 'In complex?','scFv?','Has constant domain?', | |
| 'CDRH1', 'CDRH2','CDRH3', | |
| 'Antigen chain_1', 'Antigen chain_2', 'Antigen chain_3', | |
| 'antigen_type','antigen_name','Antigen species', | |
| 'Antigen sequence_1', 'Antigen sequence_2','Antigen sequence_3', | |
| 'HL', 'HC1', 'HC2','LC1','LC2','dc','Method','Resolution','Has constant region' | |
| ] | |
| else: | |
| headers = ['pdb', 'Hchain', 'Lchain', 'Hchain_sequence','Lchain_sequence', 'Heavy subgroup', | |
| 'Light subgroup', 'Species', 'In complex?','scFv?','Has constant domain?', | |
| 'CDRH1', 'CDRH2','CDRH3','CDRL1', 'CDRL2','CDRL3', | |
| 'Antigen chain_1', 'Antigen chain_2', 'Antigen chain_3', | |
| 'antigen_type','antigen_name','Antigen species', | |
| 'Antigen sequence_1', 'Antigen sequence_2','Antigen sequence_3', | |
| 'HL', 'HC1', 'HC2','LC1','LC2','dc','Method','Resolution','Light chain type','Has constant region' | |
| ] | |
| with open(file_dir, 'a', encoding='UTF8', newline='') as b: | |
| wr = csv.writer(b) | |
| is_empty = os.stat(file_dir).st_size == 0 | |
| if is_empty: | |
| wr.writerow(headers) | |
| for i in range(fvsNumber): | |
| cdrSec = data["fv_"+str(i)].get("CDR Sequences (chothia definition)") | |
| antigenDetailsSec = data["fv_"+str(i)].get("Antigen Details") | |
| orientationSec = data["fv_"+str(i)].get("Orientation Angles (from ABangle)") | |
| if recordType == "nano": | |
| rowData = [ | |
| data["basic_data"].get("PDB"), | |
| data["fv_"+str(i)]["Fv Details"].get("Heavy chain"), | |
| data["fv_"+str(i)].get("heavyChainSeq"), | |
| data["fv_"+str(i)]["Fv Details"].get("Heavy subgroup"), | |
| data["fv_"+str(i)]["Fv Details"].get("Species"), | |
| data["fv_"+str(i)]["Fv Details"].get("In complex?"), | |
| data["fv_"+str(i)]["Fv Details"].get("scFv?"), | |
| data["fv_"+str(i)]["Fv Details"].get("Has constant domain?"), | |
| ] | |
| else: | |
| rowData = [ | |
| data["basic_data"].get("PDB"), | |
| data["fv_"+str(i)]["Fv Details"].get("Heavy chain"), | |
| data["fv_"+str(i)]["Fv Details"].get("Light chain"), | |
| data["fv_"+str(i)].get("heavyChainSeq"), | |
| data["fv_"+str(i)].get("lightChainSeq"), | |
| data["fv_"+str(i)]["Fv Details"].get("Heavy subgroup"), | |
| data["fv_"+str(i)]["Fv Details"].get("Light subgroup"), | |
| data["fv_"+str(i)]["Fv Details"].get("Species"), | |
| data["fv_"+str(i)]["Fv Details"].get("In complex?"), | |
| data["fv_"+str(i)]["Fv Details"].get("scFv?"), | |
| data["fv_"+str(i)]["Fv Details"].get("Has constant domain?"), | |
| ] | |
| antiGenChain1 = antiGenChain2 = antiGenChain3 = "" | |
| antiGenSeq1 = antiGenSeq2 = antiGenSeq3 = "" | |
| if antigenDetailsSec != None: | |
| antiGenString = data["fv_"+str(i)]["Antigen Details"]["Antigen chains"] | |
| if antiGenString != None: | |
| antiGenChains = antiGenString.split(",") | |
| if int(len(antiGenChains)) >= 1: | |
| antiGenChain1 = antiGenChains[0] | |
| if int(len(antiGenChains)) >= 2: | |
| antiGenChain2 = antiGenChains[1] | |
| if int(len(antiGenChains)) >= 3: | |
| antiGenChain3 = antiGenChains[2] | |
| antiGenstring = data["fv_"+str(i)]["Antigen Details"]["Antigen sequence"] | |
| if antiGenstring != None: | |
| antiGenSeqs = antiGenstring.split("/") | |
| if int(len(antiGenSeqs)) >= 1: | |
| antiGenSeq1 = antiGenSeqs[0] | |
| if int(len(antiGenSeqs)) >= 2: | |
| antiGenSeq2 = antiGenSeqs[1] | |
| if int(len(antiGenSeqs)) >= 3: | |
| antiGenSeq3 = antiGenSeqs[2] | |
| if cdrSec != None and recordType != "nano": | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH1")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH2")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH3")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRL1")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRL2")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRL3")) | |
| if cdrSec != None and recordType == "nano": | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH1")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH2")) | |
| rowData.append(data["fv_"+str(i)]["CDR Sequences (chothia definition)"].get("CDRH3")) | |
| if cdrSec == None and recordType == "nano": | |
| rowData.extend(empty_3_items) | |
| if cdrSec == None and recordType != "nano": | |
| rowData.extend(empty_6_items) | |
| rowData.append(antiGenChain1) | |
| rowData.append(antiGenChain2) | |
| rowData.append(antiGenChain3) | |
| if antigenDetailsSec != None: | |
| rowData.append(data["fv_"+str(i)]["Antigen Details"].get("Antigen type")) | |
| rowData.append(data["fv_"+str(i)]["Antigen Details"].get("Antigen name")) | |
| rowData.append(data["fv_"+str(i)]["Antigen Details"].get("Antigen species")) | |
| else: | |
| rowData.extend(empty_3_items) | |
| rowData.append(antiGenSeq1) | |
| rowData.append(antiGenSeq2) | |
| rowData.append(antiGenSeq3) | |
| if orientationSec != None: | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("HL"))) | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("HC1"))) | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("HC2"))) | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("LC1"))) | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("LC2"))) | |
| rowData.append(removeUnit(data["fv_"+str(i)]["Orientation Angles (from ABangle)"].get("dc"))) | |
| else: | |
| rowData.extend(empty_6_items) | |
| rowData.append(data["basic_data"].get("Method")) | |
| rowData.append(removeUnit(data["basic_data"].get("Resolution"))) | |
| if recordType != "nano": | |
| rowData.append(data["basic_data"].get("Light chain type")) | |
| rowData.append(data["basic_data"].get("Has constant region")) | |
| # print(rowData) | |
| with open(file_dir, 'a', encoding='UTF8', newline='') as body: | |
| writer = csv.writer(body) | |
| writer.writerow(rowData) | |
| def getFvData(pdbFvDiv): | |
| # tables with table-alignment classes are heavy and light chain seqs | |
| fvData = {} | |
| seqTableNumber = 0 | |
| for table in pdbFvDiv.find_all('table', class_='table-results'): | |
| tableData = {} | |
| for i, row in enumerate(table.find_all('tr')): | |
| if i == 0: | |
| header = row.find('th').text.strip() | |
| else: | |
| tds = [row.findAll('td')] | |
| for td in tds : | |
| tableData[td[0].string] = td[1].string | |
| fvData[header] = tableData | |
| for table in pdbFvDiv.find_all('table', class_='table-alignment'): | |
| for i, row in enumerate(table.find_all('tr')): | |
| if i == 0: | |
| # skip headers row | |
| continue | |
| else: | |
| if seqTableNumber == 0: | |
| heavyChainSeq = row.find_all("td") | |
| heavyChainSeqData = "" | |
| for chain in heavyChainSeq: | |
| heavyChainSeqData += chain.text | |
| fvData["heavyChainSeq"] = heavyChainSeqData | |
| else: | |
| lightChainSeq = row.find_all("td") | |
| lightChainSeqData = "" | |
| for chain in lightChainSeq: | |
| lightChainSeqData += chain.text | |
| fvData["lightChainSeq"] = lightChainSeqData | |
| seqTableNumber += 1 | |
| return fvData | |
| def getRecordType(data): | |
| heavyChainCounter = 0 | |
| lightChainCounter = 0 | |
| # if all fvs have heavy chain only and light chain is always none then it's nano | |
| # if all fvs have both heavy and light chains then anti | |
| # else combined | |
| i = -1 | |
| for fvs in data.items(): | |
| i+=1 | |
| if i == 0: | |
| # skip basic_data | |
| continue | |
| for fv in fvs: | |
| if isinstance(fv, dict): | |
| if fv['Fv Details']['Heavy chain'] != None: | |
| heavyChainCounter+=1 | |
| if fv['Fv Details']['Light chain'] != None: | |
| lightChainCounter+=1 | |
| if heavyChainCounter == lightChainCounter == int(data["basic_data"]["Number of Fvs"]): | |
| global antiBodiesCounter | |
| antiBodiesCounter+=1 | |
| return "anti" | |
| elif heavyChainCounter == int(data["basic_data"]["Number of Fvs"]) and lightChainCounter == 0: | |
| global nanoBodiesCounter | |
| nanoBodiesCounter+=1 | |
| return "nano" | |
| else: | |
| global combinedBodiesCounter | |
| combinedBodiesCounter+=1 | |
| return "combined" | |
| def removeUnit(value): | |
| if value == None: | |
| return value | |
| else: | |
| newValue = re.findall(r"[-+]?(?:\d*\.*\d+)", value) | |
| return newValue[0] | |
| os.makedirs('./conf/data/nano') | |
| os.makedirs('./conf/data/anti') | |
| os.makedirs('./conf/data/combined') | |
| baseUrl = "https://opig.stats.ox.ac.uk/" | |
| allRecordsEndPoint = "webapps/sabdab-sabpred/sabdab/nanobodies/?all=true" | |
| antiBodiesCounter = 0 | |
| nanoBodiesCounter = 0 | |
| combinedBodiesCounter = 0 | |
| failedBodiesCounter = 0 | |
| recordsCount = 0 | |
| allRecords = getAllRecords() | |
| for index, row in allRecords.iterrows(): | |
| try: | |
| recordsCount+=1 | |
| print("Record number "+str(recordsCount) + ": Calling "+row['PDB']+" page to be saved ... ") | |
| pdbEndpoint = "webapps/sabdab-sabpred/sabdab/structureviewer/?pdb="+row['PDB'] | |
| # pdbEndpoint = "webapps/sabdab-sabpred/sabdab/structureviewer/?pdb=1g9e" | |
| url = requests.get(baseUrl+pdbEndpoint) | |
| soup = BeautifulSoup(url.content, "html.parser") | |
| # get basic details table | |
| pdbDetailsTableDiv = soup.find(id="details") | |
| pdbDetailsTableRows = pdbDetailsTableDiv.find('table').find_all('tr') | |
| wholeData = {} | |
| tds = [row.findAll('td') for row in pdbDetailsTableRows] | |
| wholeData["basic_data"] = { td[0].string: td[1].string for td in tds } | |
| # loop on fvs to get its data | |
| for fvIndex in range(int(wholeData["basic_data"]["Number of Fvs"])): | |
| #collapse_0 is the first fv, collapse_1 is the second fv and so on | |
| collapseDivId = "collapse_"+str(fvIndex) | |
| pdbFvDiv = soup.find(id=collapseDivId) | |
| fvData = getFvData(pdbFvDiv) | |
| wholeData["fv_"+str(fvIndex)] = fvData | |
| recordType = getRecordType(wholeData) | |
| writeDataToCSV(recordType, wholeData) | |
| except Exception as e: | |
| with open('errors.txt', 'a') as log: | |
| log.write(row['PDB']+ " falied to be loaded > "+str(e)) | |
| failedBodiesCounter+=1 | |
| log.write('\n') | |
| print(row['PDB']+" Failed, Fail number: "+str(failedBodiesCounter)+ " till now") | |
| continue | |
| print("I am done with follwing scraps") | |
| print("Nanobodies counter is " + str(nanoBodiesCounter)) | |
| print("Antibodies counter is " + str(antiBodiesCounter)) | |
| print("Combined counter is " + str(combinedBodiesCounter)) | |
| print("Total fails counter is " + str(failedBodiesCounter)) | |