mirror of
http://43.156.76.180:8026/YuuMJ/EukPhylo.git
synced 2025-12-27 07:00:24 +08:00
189 lines
6.5 KiB
Python
189 lines
6.5 KiB
Python
'''
|
|
#Author, date: Uploaded by Adri Grow, 2023
|
|
#Intent: To get the NCBI taxonomic classification of organisms.
|
|
#Dependencies: Python3, esearch
|
|
#Inputs: Spreadsheet with ten digit codes in the first column and the genus and species names in the second column.
|
|
#Outputs: Spreadsheet with taxonomy.
|
|
#Example: python GetTaxonomy.py --input_file <path to .csv file>
|
|
'''
|
|
|
|
import os
|
|
import sys
|
|
from subprocess import check_output
|
|
from time import sleep
|
|
|
|
|
|
output_handle = 'output_taxonomies.csv'
|
|
|
|
|
|
def bad_script_call():
|
|
|
|
print('\nPlease input a spreadsheet with ten digit codes in the first column and the genus and species names in the second column. Preferably, the genus and species name will be separated by a space and there will be no extraneous characters in the second column\n\n\tpython get_taxonomy.py --input_file <path to .csv file>\n')
|
|
exit()
|
|
|
|
|
|
def get_args():
|
|
|
|
input_path = ''
|
|
|
|
try:
|
|
if(sys.argv[1] == '--input_file'):
|
|
input_path= sys.argv[2]
|
|
else:
|
|
bad_script_call()
|
|
except IndexError:
|
|
bad_script_call()
|
|
|
|
if(input_path != ''):
|
|
return input_path
|
|
else:
|
|
bad_script_call()
|
|
|
|
|
|
#Deterministic function to return the genus + species name given a line in the input spreadsheet
|
|
def get_name(line):
|
|
name = line.split(',')[1]
|
|
if(len(name.split(' ')) > 1):
|
|
if(name.split(' ')[1].strip() == 'sp' or name.split(' ')[1].strip() == 'sp.'):
|
|
name = name.split(' ')[0]
|
|
else:
|
|
name = name.split(' ')[0] + ' ' + name.split(' ')[1]
|
|
elif(len(name.split('_')) > 1):
|
|
if(name.split('_')[1].strip() == 'sp' or name.split('_')[1].strip() == 'sp.'):
|
|
name = name.split('_')[0]
|
|
else:
|
|
name = name.split('_')[0] + ' ' + name.split('_')[1]
|
|
elif(len(name.split('-')) > 1):
|
|
if(name.split('-')[1].strip() == 'sp' or name.split('-')[1].strip() == 'sp.'):
|
|
name = name.split('-')[0]
|
|
else:
|
|
name = name.split('-')[0] + ' ' + name.split('-')[1]
|
|
|
|
return name.split('\n')[0].split('\r')[0].split('(')[0]
|
|
|
|
|
|
#Returning all of the genus + species names in the input spreadsheet
|
|
def parse_taxaselection(input_path):
|
|
taxa = {}
|
|
for lines in open(input_path, 'r'):
|
|
for i, line in enumerate(lines.split('\r')):
|
|
if(len(line.split(',')) > 1 and not ('Clade' in line and 'Taxa' in line)):
|
|
taxa.update({ get_name(line) : line.split(',')[0].strip() })
|
|
|
|
return taxa
|
|
|
|
|
|
#This function queries Entrez Search with the genus and species name and returns the taxonomy for each name if available
|
|
def get_taxonomy(taxa):
|
|
|
|
#A rough list of most common clades for reference when multiple taxonomies are returned. Feel free to add to this, just keep the format of the names.
|
|
clades = { 'op_' : 'opisthokont', 'op_fu_' : 'fung', 'op_me_' : 'metazoa', 'pl_' : 'archaeplastid', 'pl_gr_' : 'green alga', 'pl_rh_' : 'red alga', 'pl_gl_' : 'glaucophyt', 'sr_ap_' : 'apicomplexa', 'sr_ci_' : 'ciliat', 'sr_rh_' : 'rhizari', 'sr_di_' : 'dinoflagell', 'sr_st_' : 'stramenopil', 'ba_' : 'bacteria', 'ba_cy_' : 'cyanobacteria', 'ba_ad_' : 'acidobacteria', 'ba_pa_' : 'alphaproteobacteria', 'ba_pb_' : 'betaproteobacteria', 'ba_pg_' : 'gammaproteobacteria', 'ba_pd' : 'deltaproteobacteria', 'za_' : 'archea', 'ex_' : 'excavata', 'am_' : 'amoeb', 'am_tu_' : 'tubilinea', 'am_di_' : 'discosea', 'op_fb_' : 'fung', 'op_mb_' : 'metazoa', 'pl_rb_' : 'red alga', 'sr_ab_' : 'apicomplexa', 'sr_cb_' : 'ciliat', 'sr_rb_' : 'rhizari', 'sr_db_' : 'dinoflagell', 'sr_sb_' : 'stramenopil', 'am_tb' : 'tubilinea', 'am_db' : 'discosea' }
|
|
|
|
taxonomies = {}
|
|
|
|
for taxon in taxa:
|
|
code = taxa[taxon].lower()
|
|
|
|
print('\nFetching taxonomy for taxon ' + taxon + '\n')
|
|
try:
|
|
output = str(check_output('esearch -db taxonomy -query "' + taxon + '" | efetch -format xml', shell = True, executable='/bin/bash'))
|
|
#sleep(2)
|
|
|
|
taxonomy_strings = []
|
|
|
|
for line in output.split('<'):
|
|
if('lineage' in line.lower() and 'lineageex' not in line.lower()):
|
|
if('cellular organisms' in line.split('>')[1].split('\n')[0]):
|
|
taxonomy_strings.append(line.split('>')[1].split('\n')[0])
|
|
|
|
except:
|
|
continue
|
|
|
|
|
|
|
|
hits = 0
|
|
#If multiple taxonomies were returned
|
|
if(len(taxonomy_strings) > 1):
|
|
relevant_taxonomies = []
|
|
#Check whether the relevant minor clade has a keyword
|
|
if(code[:6] in clades):
|
|
keyword = clades[code[:6]]
|
|
for taxonomy in taxonomy_strings:
|
|
#Get the taxonomy that contains the keyword
|
|
if(keyword in taxonomy.lower()):
|
|
hits += 1
|
|
relevant_taxonomies.append(taxonomy)
|
|
#If the minor clade does not have a keyword, check whether the major clade has a keyword
|
|
elif(code[:3] in clades):
|
|
keyword = clades[code[:3]]
|
|
for taxonomy in taxonomy_strings:
|
|
#Get the taxonomy that contains the keyword
|
|
if(keyword in taxonomy.lower()):
|
|
hits += 1
|
|
relevant_taxonomies.append(taxonomy)
|
|
else:
|
|
hits = 2
|
|
|
|
if(hits > 1):
|
|
final_string = 'MULTIPLE TAXONOMIES: ' + ' | '.join(relevant_taxonomies)
|
|
else:
|
|
final_string = relevant_taxonomies[0]
|
|
elif(len(taxonomy_strings) == 0):
|
|
final_string = 'NO TAXONOMY RETURNED'
|
|
else:
|
|
final_string = taxonomy_strings[0]
|
|
|
|
print(final_string)
|
|
|
|
taxonomies.update({ taxon : final_string })
|
|
|
|
return taxonomies
|
|
|
|
|
|
#Writing the output spreadsheet with taxonomies using the input spreadsheet as a template
|
|
def write_spreadsheet(taxonomies, input_path):
|
|
|
|
with open(output_handle, 'w') as o:
|
|
for lines in open(input_path, 'r'):
|
|
for i, line in enumerate(lines.split('\r')):
|
|
if(len(line.split(',')) > 1 and not ('Clade' in line and 'Taxa' in line)):
|
|
if(get_name(line) in taxonomies):
|
|
line_split = line.strip().split(',')
|
|
line_split.append(taxonomies[get_name(line)])
|
|
|
|
o.write(','.join(line_split) + '\n')
|
|
else:
|
|
o.write(line + '\n')
|
|
|
|
|
|
#This is a one-time-use function to add taxonomy to a specific spreadsheet (R2G and BB counts)
|
|
def add_to_seq_count_spreadsheet():
|
|
|
|
used = []
|
|
|
|
with open('seq_counts_taxaselection.csv', 'w') as o:
|
|
for lines in open(output_handle, 'r'):
|
|
for count_lines in open('seq_counts_selection.csv', 'r'):
|
|
for count_line in count_lines.split('\r'):
|
|
for i, line in enumerate(lines.split('\r')):
|
|
if(count_line.split(',')[0] in line and count_line.split(',')[0] not in used):
|
|
used.append(count_line.split(',')[0])
|
|
o.write(count_line + ',' + line.split(',')[1] + ',' + line.split(',')[6] + '\n')
|
|
|
|
|
|
def main():
|
|
|
|
input_path = get_args()
|
|
|
|
taxa = parse_taxaselection(input_path)
|
|
|
|
taxonomies = get_taxonomy(taxa)
|
|
|
|
write_spreadsheet(taxonomies, input_path)
|
|
|
|
#You will probably never need to use this function
|
|
#add_to_seq_count_spreadsheet()
|
|
|
|
|
|
main()
|