Skip to content

Commit 2fd7939

Browse files
update
1 parent 092eac4 commit 2fd7939

5 files changed

Lines changed: 385 additions & 233 deletions

File tree

boldigger/additional_data.py

Lines changed: 93 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from boldigger.boldblast_coi import slices
55
from bs4 import BeautifulSoup as BSoup
66

7+
78
## funtion to scan the BOLDresutls file and return a list
89
## of all unique Process ID's found, will also return the workbook
910
## ato later use it when saving the data
@@ -14,18 +15,29 @@ def retrieve_process_ids(xlsx_path):
1415
sheet = wb.active
1516

1617
## get type (coi or its/rbcl) and extract process ids
17-
if sheet.cell(row = 1, column = 11).value == 'Process ID':
18-
type = 'coi'
19-
process_ids = [sheet.cell(row = row, column = 11).value for row in range(2, sheet.max_row + 1) if sheet.cell(row = row, column = 11).value != None and sheet.cell(row = row, column = 11).value != '']
20-
elif sheet.cell(row = 1, column = 11).value == 'Similarity':
21-
type = 'its_rbcl'
22-
process_ids = [sheet.cell(row = row, column = 14).value for row in range(2, sheet.max_row + 1) if sheet.cell(row = row, column = 14).value != None and sheet.cell(row = row, column = 14).value != '']
18+
if sheet.cell(row=1, column=11).value == "Process ID":
19+
type = "coi"
20+
process_ids = [
21+
sheet.cell(row=row, column=11).value
22+
for row in range(2, sheet.max_row + 1)
23+
if sheet.cell(row=row, column=11).value != None
24+
and sheet.cell(row=row, column=11).value != ""
25+
]
26+
elif sheet.cell(row=1, column=11).value == "Similarity":
27+
type = "its_rbcl"
28+
process_ids = [
29+
sheet.cell(row=row, column=14).value
30+
for row in range(2, sheet.max_row + 1)
31+
if sheet.cell(row=row, column=14).value != None
32+
and sheet.cell(row=row, column=14).value != ""
33+
]
2334
else:
2435
raise ValueError
2536

2637
## remove duplicates and return
2738
return wb, list(unique_everseen(process_ids)), type
2839

40+
2941
## function to loop through the process IDs and call the BOLD API for additional data
3042
## will return a dict in form of {Process ID: [BOLD Record ID, BIN, Sex, Life stage, Country, Identifier, Identification method, Institution storing]}
3143
def get_data(process_ids, processbar):
@@ -34,114 +46,159 @@ def get_data(process_ids, processbar):
3446

3547
## open a new html session
3648
with requests_html.HTMLSession() as session:
37-
3849
## initialize the final dict output
3950
process_id_dict = {}
4051

4152
for id_pack in process_ids:
42-
4353
## request the data, retry if the request failes
4454
while True:
4555
try:
46-
resp = session.get('http://www.boldsystems.org/index.php/API_Public/specimen?ids=' + '|'.join(id_pack))
56+
resp = session.get(
57+
"http://www.boldsystems.org/index.php/API_Public/specimen?ids="
58+
+ "|".join(id_pack)
59+
)
4760
except:
4861
continue
4962
break
5063

5164
## use beautifulsoup to find all records in the response
52-
soup = BSoup(resp.text, 'html.parser')
53-
records = soup.find_all('record')
65+
soup = BSoup(resp.text, "xml")
66+
records = soup.find_all("record")
5467

5568
## loop through records to extract interesting data
5669
for count in range(len(records)):
57-
58-
tags = ['processid', 'record_id', 'bin_uri', 'sex', 'lifestage', 'country', 'identification_provided_by', 'identification_method', 'institution_storing']
70+
tags = [
71+
"processid",
72+
"record_id",
73+
"bin_uri",
74+
"sex",
75+
"lifestage",
76+
"country",
77+
"identification_provided_by",
78+
"identification_method",
79+
"institution_storing",
80+
]
5981

6082
## search the data encapsuled by each tag
61-
specimen_data = [records[count].find(tag) if records[count].find(tag) != None else '' for tag in tags]
83+
specimen_data = [
84+
records[count].find(tag) if records[count].find(tag) != None else ""
85+
for tag in tags
86+
]
6287

6388
## extract the texts from these tags
64-
specimen_data = [datapoint.text if datapoint != '' else '' for datapoint in specimen_data]
89+
specimen_data = [
90+
datapoint.text if datapoint != "" else ""
91+
for datapoint in specimen_data
92+
]
6593

6694
## append a link to the specimen page to the results if user is interested in looking up even more data
67-
specimen_data.append('http://www.boldsystems.org/index.php/MAS_DataRetrieval_OpenSpecimen?selectedrecordid=' + specimen_data[1])
95+
specimen_data.append(
96+
"http://www.boldsystems.org/index.php/MAS_DataRetrieval_OpenSpecimen?selectedrecordid="
97+
+ specimen_data[1]
98+
)
6899

69100
## put the data in a dictionary in form of processID: [listofinformation]
70101
process_dict = {specimen_data[0]: specimen_data[1:]}
71102

72103
## update the final output
73104
process_id_dict.update(process_dict)
74105

75-
processbar.UpdateBar(round(100 / len(process_ids) * (process_ids.index(id_pack) + 1)))
106+
processbar.UpdateBar(
107+
round(100 / len(process_ids) * (process_ids.index(id_pack) + 1))
108+
)
76109

77110
return process_id_dict
78111

112+
79113
## function to save the additional data to the input file
80114
def save_results(workbook, additional_data, xlsx_path, type):
81-
82115
sheet = workbook.active
83116

84117
## headers to add to the resultfile
85-
headers = ['Record ID', 'BOLD BIN', 'Sex', 'Life stage', 'Country', 'Identifier', 'Identification Method', 'Institution storing', 'Specimen page url']
118+
headers = [
119+
"Record ID",
120+
"BOLD BIN",
121+
"Sex",
122+
"Life stage",
123+
"Country",
124+
"Identifier",
125+
"Identification Method",
126+
"Institution storing",
127+
"Specimen page url",
128+
]
86129

87130
## first empty column depends on the type either 12 oder 15
88-
start = 12 if type == 'coi' else 15
131+
start = 12 if type == "coi" else 15
89132

90133
## write the header row
91134
for i in range(start, start + len(headers)):
92-
sheet.cell(row = 1, column = i).value = headers[i - start]
135+
sheet.cell(row=1, column=i).value = headers[i - start]
93136

94137
## add the additional data to the resultfile
95138
for row in range(2, sheet.max_row + 1):
96139
for column in range(start, start + len(headers)):
97-
if sheet.cell(row = row, column = start - 1).value in additional_data.keys():
98-
sheet.cell(row = row, column = column).value = additional_data[sheet.cell(row = row, column = start - 1).value][column - start]
140+
if sheet.cell(row=row, column=start - 1).value in additional_data.keys():
141+
sheet.cell(row=row, column=column).value = additional_data[
142+
sheet.cell(row=row, column=start - 1).value
143+
][column - start]
99144

100145
workbook.save(xlsx_path)
101146

147+
102148
## main function to controll the flow
103149
def main(xlsx_path):
104-
105150
## define a layout for the new window
106151
layout = [
107-
[sg.Text('Download status', size = (15, 1), key = 'bar_des'), sg.ProgressBar(100, orientation = 'h', size = (20, 20), key = 'bar')],
108-
[sg.Multiline(size = (50, 10), key = 'out', autoscroll = True)]
152+
[
153+
sg.Text("Download status", size=(15, 1), key="bar_des"),
154+
sg.ProgressBar(100, orientation="h", size=(20, 20), key="bar"),
155+
],
156+
[sg.Multiline(size=(50, 10), key="out", autoscroll=True)],
109157
]
110158

111159
## run the download loop only once. After that only run event loop
112-
window = sg.Window('Additional data download', layout)
113-
bar = window['bar']
160+
window = sg.Window("Additional data download", layout)
161+
bar = window["bar"]
114162
ran = False
115163

116164
while True:
117-
118-
event, values = window.read(timeout = 10)
165+
event, values = window.read(timeout=10)
119166
## start inner loop only once
120-
window['out'].print("%s: Extracting process ID's." % datetime.datetime.now().strftime("%H:%M:%S"))
167+
window["out"].print(
168+
"%s: Extracting process ID's."
169+
% datetime.datetime.now().strftime("%H:%M:%S")
170+
)
121171
window.Refresh()
122172

123173
if not ran:
124-
125174
## catch any wrong file formats here to avoid crash
126175
try:
127176
wb, process_ids, type = retrieve_process_ids(xlsx_path)
128177
except ValueError:
129-
window['out'].print('Wrong file format. Close to continue.')
178+
window["out"].print("Wrong file format. Close to continue.")
130179

131180
## collect the data from BOLD
132-
window['out'].print('%s: Downloading additional data.' % datetime.datetime.now().strftime("%H:%M:%S"))
181+
window["out"].print(
182+
"%s: Downloading additional data."
183+
% datetime.datetime.now().strftime("%H:%M:%S")
184+
)
133185
window.Refresh()
134186
additional_data = get_data(process_ids, bar)
135187

136188
## saving the data according to type
137-
window['out'].print('%s: Saving the results.' % datetime.datetime.now().strftime("%H:%M:%S"))
189+
window["out"].print(
190+
"%s: Saving the results." % datetime.datetime.now().strftime("%H:%M:%S")
191+
)
138192
window.Refresh()
139193
save_results(wb, additional_data, xlsx_path, type)
140194

141195
ran = True
142196

143197
## get events (just closing) and values
144-
window['out'].print('%s: Done. Close to continue.' % datetime.datetime.now().strftime("%H:%M:%S"))
198+
window["out"].print(
199+
"%s: Done. Close to continue."
200+
% datetime.datetime.now().strftime("%H:%M:%S")
201+
)
145202
window.Refresh()
146203
event, values = window.read()
147204

0 commit comments

Comments
 (0)