changeset 0:be856549e863 draft default tip

planemo upload for repository https://github.com/Public-Health-Bioinformatics/flu_classification_suite commit b96b6e06f6eaa6ae8ef4c24630dbb72a4aed7dbe
author public-health-bioinformatics
date Thu, 04 Jul 2019 19:37:41 -0400
parents
children
files data/FluA_H3_antigenic_aa_indices.csv data/Flu_Clade_Definitions_H3_20171121.csv data/MAP_3C.2a_A_Hong_Kong_4801_2014_X-263B_EGG.fasta linelisting.py linelisting.xml test-data/FluA_H3_antigenic_aa_indices.csv test-data/Flu_Clade_Definitions_H3_20171121.csv test-data/MAP_3C.2a_A_Hong_Kong_4801_2014_X-263B_EGG.fasta test-data/fluA_H3_clade_assigned_antigenic_sites_extracted.fasta test-data/test_output.csv
diffstat 10 files changed, 405 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/FluA_H3_antigenic_aa_indices.csv	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,1 @@
+44,45,46,47,48,50,51,53,54,57,59,62,63,67,75,78,80,81,82,83,86,87,88,91,92,94,96,102,103,109,117,121,122,124,126,128,129,130,131,132,133,135,137,138,140,142,143,144,145,146,150,152,155,156,157,158,159,160,163,164,165,167,168,170,171,172,173,174,175,176,177,179,182,186,187,188,189,190,192,193,194,196,197,198,201,203,207,208,209,212,213,214,215,216,217,218,219,226,227,228,229,230,238,240,242,244,246,247,248,260,261,262,265,273,275,276,278,279,280,294,297,299,300,304,305,307,308,309,310,311,312
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/Flu_Clade_Definitions_H3_20171121.csv	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,12 @@
+3C.2a,1,3,I,144,S,145,S,159,Y,160,T,225,D,311,H,489,N,,,,,,,,,,,,,,,,,,,,
+3C.2a_+_T131K_+_R142K_+_R261Q,2,3,I,131,K,142,K,144,S,145,S,159,Y,160,T,225,D,261,Q,311,H,489,N,,,,,,,,,,,,,,
+3C.2a_+_N121K_+_S144K,2,3,I,121,K,144,K,145,S,159,Y,160,T,225,D,311,H,489,N,,,,,,,,,,,,,,,,,,
+3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H,2,3,I,31,S,53,N,142,G,144,R,145,S,159,Y,160,T,171,K,192,T,197,H,225,D,311,H,489,N,,,,,,,,
+3C.2a1,2,3,I,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,,,,,
+3C.2a1_+_N121K,3,3,I,121,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,,,
+3C.2a1_+_N121K_+_K92R_+_H311Q,4,3,I,92,R,121,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,Q,406,V,484,E,489,N,,,,,,,,,,
+3C.2a1_+_N121K_+_T135K,4,3,I,121,K,135,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,479,E,484,E,489,N,,,,,,,,
+3C.2a1_+_N121K_+_I140M,4,3,I,121,K,140,M,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,479,E,484,E,489,N,,,,,,,,
+3C.2a1_+_N121K_+_R142G,4,3,I,121,K,142,G,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,
+3C.2a1_+_N121K_+_R142G_+_I242V,5,3,I,121,K,142,G,144,S,145,S,159,Y,160,T,171,K,225,D,242,V,311,H,406,V,479,E,484,E,489,N,,,,,,
+3C.3a,1,128,A,138,S,142,G,145,S,159,S,225,D,,,,,,,,,,,,,,,,,,,,,,,,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/MAP_3C.2a_A_Hong_Kong_4801_2014_X-263B_EGG.fasta	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,4 @@
+>Clade_3C.2a_A/Hong_Kong/4801/2014_X-263B_EGG
+QNSSIEIDSQLENIQGQNKKLFVSKYSVPRTNNSNTGVTQNTSAIRSSSSRNTHLNYKAL
+NTMNNEQFDKLIVGTDKDIFPAQSRXKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKHS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linelisting.py	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+'''Reads in a fasta file of extracted antigenic sites and one containing a 
+reference flu antigenic map, reading them in as protein SeqRecords. Compares each amino
+acid of each sample antigenic map to corresponding sites in the reference and replaces
+identical amino acids with dots. Writes headers (including amino acid position numbers
+read in from the respective index array), the reference amino acid sequence and column
+headings required for non-aggregated line lists. Outputs headers and modified (i.e. dotted)
+sequences to a csv file.'''
+
+'''Author: Diane Eisler, Molecular Microbiology & Genomics, BCCDC Public Health Laboratory, Nov 2017'''
+
+import sys,string,os, time, Bio, re, argparse
+from Bio import Seq, SeqIO, SeqUtils, Alphabet, SeqRecord
+from Bio.SeqRecord import SeqRecord
+from Bio.Alphabet import IUPAC
+from Bio.Seq import Seq
+
+inputAntigenicMaps = sys.argv[1] #batch fasta file with antigenic map sequences
+refAntigenicMap = sys.argv[2] #fasta file of reference antigenic map sequence
+antigenicSiteIndexArray = sys.argv[3] #antigenic site index array csv file
+cladeDefinitionFile = sys.argv[4] #clade definition csv file
+outFileHandle = sys.argv[5] #user-specifed output filename
+
+lineListFile = open(outFileHandle,'w') #open a writable output file
+
+indicesLine = "" #comma-separated antigenic site positions
+cladeList = [] #list of clade names read from clade definition file
+ref_seq = "" #reference antigenic map (protein sequence)
+seqList = [] #list of aa sequences to compare to reference
+
+BC_list = [] #empty list for BC samples
+AB_list = [] #empty list for AB samples
+ON_list = [] #empty list for ON samples
+QC_list = [] #empty list for QC samples
+nonprov_list = [] #empty list for samples not in above 4 provinces
+#dictionary for location-separated sequence lists
+segregated_lists = {'1_BC':BC_list,'2_AB':AB_list,'3_ON':ON_list,'4_QC': QC_list, '5_nonprov': nonprov_list}
+uniqueSeqs = {} #empty dict with unique seqs as keys and lists of SeqRecords as values
+
+def replace_matching_aa_with_dot(record):
+    """Compare amino acids in record to reference sequence, replace matching symbols
+    with dots, and return record with modified amino acid sequence."""
+    orig_seq = str(record.seq) #get sequence string from SeqRecord
+    mod_seq = ""
+    #replace only those aa's matching the reference with dots
+    for i in range(0, len(orig_seq)):
+        if (orig_seq[i] == ref_seq[i]):
+            mod_seq = mod_seq  + '.'
+        else:
+            mod_seq  = mod_seq  + orig_seq[i]
+    #assign modified sequence to new SeqRecord and return it
+    rec = SeqRecord(Seq(mod_seq,IUPAC.protein), id = record.id, name = "", description = "")
+    return rec
+
+def extract_clade(record):
+    """Extract clade name (or 'No_Match') from sequence name and return as clade name. """
+    if record.id.endswith('No_Match'):
+        clade_name = 'No_Match'
+        end_index = record.id.index(clade_name)
+        record.id = record.id[:end_index -1]
+        return clade_name
+    else: #
+        for clade in cladeList:
+            if record.id.endswith(clade):
+                clade_name = clade
+                end_index = record.id.index(clade)
+                record.id = record.id[:end_index -1]
+                return clade_name
+    
+def sort_by_location(record):
+    """Search sequence name for province name or 2 letter province code and add SeqRecord to
+    province-specific dictionary."""
+    seq_name = record.id
+    if ('-BC-' in seq_name) or ('/British_Columbia/' in seq_name):
+        BC_list.append(record) #add Sequence record to BC_list
+    elif ('-AB-' in seq_name) or ('/Alberta/' in seq_name):
+        AB_list.append(record) #add Sequence record to AB_list
+    elif ('-ON-' in seq_name) or ('/Ontario/' in seq_name):
+        ON_list.append(record) #add Sequence record to ON_list
+    elif ('-QC-' in seq_name) or ('/Quebec/' in seq_name):
+        QC_list.append(record) #add Sequence record to QC_list
+    else:
+        nonprov_list.append(record) #add Sequence record to nonprov_list
+    return
+
+def extract_province(record):
+    """Search sequence name for province name or 2 letter province code and return province."""
+    seq_name = record.id
+    if ('-BC-' in seq_name) or ('/British_Columbia/' in seq_name):
+        province = 'British Columbia'
+    elif ('-AB-' in seq_name) or ('Alberta' in seq_name):
+        province = '/Alberta/'
+    elif ('-ON-' in seq_name) or ('/Ontario/' in seq_name):
+        province = 'Ontario'
+    elif ('-QC-' in seq_name) or ('/Quebec/' in seq_name):
+        province = 'Quebec'
+    else:
+        province = "other"
+    return province
+
+def get_sequence_length(record):
+    """Return the length of a sequence in a Sequence record."""
+    sequenceLength = len(str((record.seq)))
+    return sequenceLength
+
+def get_antigenic_site_substitutions(record):
+    """Count number of non-dotted amino acids in SeqRecord sequence and return as substitutions."""
+    sequenceLength = get_sequence_length(record)
+    seqString = str(record.seq)
+    matches = seqString.count('.')
+    substitutions = sequenceLength - matches
+    return substitutions
+
+def calculate_percent_id(record, substitutions):
+    """Calculate sequence identity to a reference (based on substitutions and sequence length) and return percent id."""
+    sequenceLength = get_sequence_length(record)
+    percentID = (1.00 - (float(substitutions)/float(sequenceLength)))
+    return percentID
+
+def output_linelist(sequenceList):
+    """Output a list of SeqRecords to a non-aggregated line list in csv format."""
+    for record in sequenceList:
+        #get province, clade from sequence record
+        province = extract_province(record)
+        clade = extract_clade(record)
+        #calculate number of substitutions and % id to reference
+        substitutions = get_antigenic_site_substitutions(record)
+        percentID = calculate_percent_id(record,substitutions)
+        name_part = (record.id).rstrip() + ','
+        clade_part = clade + ','
+        substitutions_part = str(substitutions) + ','
+        percID_part = str(percentID) + ','
+        col = " ," #empty column
+        sequence = str(record.seq).strip()
+        csv_seq = ",".join(sequence) +","
+        #write linelisted antigenic maps to csv file
+        comma_sep_line = name_part + col + clade_part + col + csv_seq + substitutions_part + percID_part + "\n"
+        lineListFile.write(comma_sep_line)
+    return
+	
+with open (antigenicSiteIndexArray,'r') as siteIndices:
+    """Read amino acid positions from antigenic site index array and print as header after one empty row."""
+    col = "," #empty column
+    #read items separated by comma's to position list
+    for line in siteIndices:
+        #remove whitespace from the end of each line
+        indicesLine = line.rstrip()
+    row1 = "\n"
+    #add comma-separated AA positions to header line
+    row2 = col + col + col + col + indicesLine + "\n"
+    #write first (empty) and 2nd (amino acid position) lines to linelist output file
+    lineListFile.write(row1)
+    lineListFile.write(row2)
+
+with open (refAntigenicMap,'r') as refMapFile:
+    """Read reference antigenic map from fasta and output amino acids, followed by column headers."""
+    #read sequences from fasta to SeqRecord, uppercase, and store sequence string to ref_seq
+    record = SeqIO.read(refMapFile,"fasta",alphabet=IUPAC.protein)
+    record = record.upper()
+    ref_seq = str(record.seq).strip() #store sequence in variable for comparison to sample seqs
+    col = "," #empty column
+    name_part = (record.id).rstrip() + ','
+    sequence = str(record.seq).strip()
+    csv_seq = ",".join(sequence)
+    #output row with reference sequence displayed above sample sequences
+    row3 = name_part + col + col + col + csv_seq + "\n"
+    lineListFile.write(row3)
+    #replaces digits in the indicesLine with empty strings
+    positions = indicesLine.split(',')
+    numPos = len(positions)
+    empty_indicesLine = ',' * numPos
+    #print column headers for sample sequences
+    row4 = "Sequence Name,N,Clade,Extra Substitutions," + empty_indicesLine + "Number of Amino Acid Substitutions in Antigenic Sites,% Identity of Antigenic Site Residues\n"
+    lineListFile.write(row4)
+    print("\nREFERENCE ANTIGENIC MAP: '%s' (%i amino acids)" % (record.id, len(record)))
+
+with open(cladeDefinitionFile,'r') as cladeFile:
+    """Read clade definition file and store clade names in a list."""
+    #remove whitespace from the end of each line and split elements at commas
+    for line in cladeFile:
+        elementList = line.rstrip().split(',')
+        name = elementList[0] #move 1st element to name field
+        cladeList.append(name)
+
+with open(inputAntigenicMaps,'r') as extrAntigMapFile:
+    """Read antigenic maps as protein SeqRecords and add to list."""
+    #read Sequences from fasta file, uppercase and add to seqList
+    for record in SeqIO.parse(extrAntigMapFile, "fasta", alphabet=IUPAC.protein):
+        record = record.upper()
+        seqList.append(record) #add Seq to list of Sequences
+
+#print number of sequences to be process as user check
+print("\nCOMPARING %i flu antigenic map sequences to the reference..." % len(seqList))
+#parse each antigenic map sequence object
+for record in seqList:
+    #assign Sequence to dictionaries according to location in name
+    sort_by_location(record)
+#sort dictionary keys that access province-segregated lists
+sorted_segregated_list_keys = sorted(segregated_lists.keys())
+print("\nSequence Lists Sorted by Province: ")
+#process each province-segregated SeqRecord list
+for listname in sorted_segregated_list_keys:
+    #acesss list of sequences by the listname key
+    a_list = segregated_lists[listname]
+    # sort original SeqRecords by record id (i.e. name)
+    a_list = [f for f in sorted(a_list, key = lambda x : x.id)]
+    mod_list = [] # empty temporary list
+    for record in a_list:
+        #replace matching amino acid symbols with dots
+        rec = replace_matching_aa_with_dot(record)
+        mod_list.append(rec) #populate a list of modified records
+    segregated_lists[listname] =  mod_list
+    print("\n'%s' List (Amino Acids identical to Reference Masked): " % (listname))
+    #output the list to csv as non-aggregated linelist
+    output_linelist(segregated_lists[listname])
+
+extrAntigMapFile.close()
+refMapFile.close()
+lineListFile.close()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linelisting.xml	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,35 @@
+<tool id="linelisting" name="Line List" version="0.0.1">
+  <requirements>
+    <requirement type="package" version="1.70">biopython</requirement>
+  </requirements>
+  <command detect_errors="exit_code"><![CDATA[
+    python $__tool_directory__/linelisting.py
+    '$input_fasta'
+    '$ref_fasta'
+    '$index_array_csv'
+    '$clade_def_csv'
+    '$output_file'
+  ]]></command>
+  <inputs>
+    <param name="input_fasta" format="fasta" type="data" label="Sample Sequences fasta."/>
+    <param name="ref_fasta" format="fasta" type="data" label="Reference Sequence fasta."/>
+    <param name="index_array_csv" format="csv" type="data" label="Antigenic Site Index Array File."/>
+    <param name="clade_def_csv" format="csv" type="data" label="Clade Definition File."/>
+  </inputs>
+  <outputs>
+    <data name="output_file" format="csv"/>
+  </outputs>
+  <tests>
+    <test>
+      <param name="input_fasta" value="fluA_H3_clade_assigned_antigenic_sites_extracted.fasta"/>
+      <param name="ref_fasta" value="MAP_3C.2a_A_Hong_Kong_4801_2014_X-263B_EGG.fasta" />
+      <param name="index_array_csv" value="FluA_H3_antigenic_aa_indices.csv" />
+      <param name="clade_def_csv" value="Flu_Clade_Definitions_H3_20171121.csv" />
+      <output name="output_file" value="test_output.csv"/>
+    </test>
+  </tests>
+  <help><![CDATA[
+  ]]></help>
+  <citations>
+  </citations>
+</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/FluA_H3_antigenic_aa_indices.csv	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,1 @@
+44,45,46,47,48,50,51,53,54,57,59,62,63,67,75,78,80,81,82,83,86,87,88,91,92,94,96,102,103,109,117,121,122,124,126,128,129,130,131,132,133,135,137,138,140,142,143,144,145,146,150,152,155,156,157,158,159,160,163,164,165,167,168,170,171,172,173,174,175,176,177,179,182,186,187,188,189,190,192,193,194,196,197,198,201,203,207,208,209,212,213,214,215,216,217,218,219,226,227,228,229,230,238,240,242,244,246,247,248,260,261,262,265,273,275,276,278,279,280,294,297,299,300,304,305,307,308,309,310,311,312
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/Flu_Clade_Definitions_H3_20171121.csv	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,12 @@
+3C.2a,1,3,I,144,S,145,S,159,Y,160,T,225,D,311,H,489,N,,,,,,,,,,,,,,,,,,,,
+3C.2a_+_T131K_+_R142K_+_R261Q,2,3,I,131,K,142,K,144,S,145,S,159,Y,160,T,225,D,261,Q,311,H,489,N,,,,,,,,,,,,,,
+3C.2a_+_N121K_+_S144K,2,3,I,121,K,144,K,145,S,159,Y,160,T,225,D,311,H,489,N,,,,,,,,,,,,,,,,,,
+3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H,2,3,I,31,S,53,N,142,G,144,R,145,S,159,Y,160,T,171,K,192,T,197,H,225,D,311,H,489,N,,,,,,,,
+3C.2a1,2,3,I,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,,,,,
+3C.2a1_+_N121K,3,3,I,121,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,,,
+3C.2a1_+_N121K_+_K92R_+_H311Q,4,3,I,92,R,121,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,Q,406,V,484,E,489,N,,,,,,,,,,
+3C.2a1_+_N121K_+_T135K,4,3,I,121,K,135,K,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,479,E,484,E,489,N,,,,,,,,
+3C.2a1_+_N121K_+_I140M,4,3,I,121,K,140,M,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,479,E,484,E,489,N,,,,,,,,
+3C.2a1_+_N121K_+_R142G,4,3,I,121,K,142,G,144,S,145,S,159,Y,160,T,171,K,225,D,311,H,406,V,484,E,489,N,,,,,,,,,,
+3C.2a1_+_N121K_+_R142G_+_I242V,5,3,I,121,K,142,G,144,S,145,S,159,Y,160,T,171,K,225,D,242,V,311,H,406,V,479,E,484,E,489,N,,,,,,
+3C.3a,1,128,A,138,S,142,G,145,S,159,S,225,D,,,,,,,,,,,,,,,,,,,,,,,,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/MAP_3C.2a_A_Hong_Kong_4801_2014_X-263B_EGG.fasta	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,4 @@
+>Clade_3C.2a_A/Hong_Kong/4801/2014_X-263B_EGG
+QNSSIEIDSQLENIQGQNKKLFVSKYSVPRTNNSNTGVTQNTSAIRSSSSRNTHLNYKAL
+NTMNNEQFDKLIVGTDKDIFPAQSRXKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKHS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/fluA_H3_clade_assigned_antigenic_sites_extracted.fasta	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,94 @@
+>A-ON-314-2017_3C.3a
+QNSSIEIDSQLENIQGQNKKLFVNKYNVPRTNNSNAGVTQNTSSIGSKSSRNTHLNSKAL
+NTMNNEQFDKLIVGTDKDISLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKQS
+
+>A-AB-399-2017_3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H
+QNSSIEINSQLENIQGQNKKLFVSKYNVPRTNNSNTGVTQNTSAIGSRSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDTFLAHSRTKRSAVIPNIGSIPSRIKGLLNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-QC-303-2017_3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H
+QNSSIEINSQLENIQGQNKKLFVSKYNVPRTNNSNTGVTQNTSAIGSRSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDTFLAHSRTKRSAVIPNIGSIPSRIKGLLNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-319-2017_3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H
+QNSSIEINSQLENIQGQNKKLFVSKYNVPRTNNSNTGVTQNTSAIGSRSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDTFLAHSRTKRSAVIPNIGSIPSRIKGLLNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-308-2017_3C.2a1_+_N121K_+_T135K
+QNSSIEIDSQLENIQDQNKKLFVSKHNVPRTKDSNTGVTQNKSAIRSSSSRNTHLNYTAL
+NTMNKEQFDKLIIGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-341-2017_3C.2a1_+_N121K_+_T135K
+QNSSIEIDSQLENIQDQNKKLFVSKHNVPRTKDSNTGVTQNKSAIRSSSSRNTHLNYTAL
+NTMNKEQFDKLIIGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-BC-024-2018_3C.2a1_+_N121K_+_T135K
+QNSSIEIDSQLENIQDQNKKLFVSKHNVPRTKNSNTGVTQNKSAIRSSSSRNTHLNYTAL
+NTMNKEQFDKLIIGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKHS
+
+>A-QC-309-2017_3C.2a1_+_N121K_+_K92R_+_H311Q
+QNSSIEIDSQLGNIQDQNKKLFVSRYNVPRTKDSNTGVTQNKSAIGSSSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKQS
+
+>A-BC-324-2017_3C.2a1_+_N121K_+_K92R_+_H311Q
+QNSSMEIDSQLGNIQGQNKKLFVSRYNVPRTKNSNTGVTQNKSAIGSSSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKQS
+
+>A-QC-315-2017_3C.2a1_+_N121K_+_K92R_+_H311Q
+QNSSIEIDSQLGNIQGQNKKLFVSRYNVPRTKNSNAGVTQNKSAIGSSSSRNTHLNYTAL
+NTMNKEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIRSSPGKKSEF
+VRIACRYVKQS
+
+>A-ON-016-2018_3C.2a_+_N121K_+_S144K
+QNSSIEIDSQLENIQGQNKKLFVSKYNVPRTKNSNTGVTQNKSAIRSKSSKNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-BC-325-2017_3C.2a_+_N121K_+_S144K
+QNSSIEIDSQLENIQGQNKKLFVSKYNVPRTKNSNTGVTQNKSAIRSKSSKNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-ON-003-2018_3C.2a_+_N121K_+_S144K
+QNSSIEIDSQLENIQGQNKKLFVSKYNVPRTKNSNTGVTQNKSAIRSKSSKNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-ON-309-2017_No_Match
+QNSSIEIDSQLENIQGQNKKLFVSKYNVPRTNNSNTGVKQNTSAIKSSSSRNTHLNYKAL
+NTMNNEQFDKLIVGTDKDIFLAQSKTKISAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-BC-330-2017_No_Match
+QNSSIEIDSQLENIQGQNKKLFVSKYNVPRTNNSNTGVKQNTSAIKSRSSRNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-415-2017_3C.2a_+_T131K_+_R142K_+_R261Q
+QNSSIEIDSQLENIQGQNKKLFVSRYNVPRTNNSNTGVKQNTSAIKSSSSRNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGFIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-400-2017_3C.2a_+_T131K_+_R142K_+_R261Q
+QNSSIEIDSQLENIQGQNKKLFVSRYNVPRTNNSNTGVKQNTSAIKSSSSRNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-AB-416-2017_3C.2a_+_T131K_+_R142K_+_R261Q
+QNSSIEIDSQLENIQGQNKKLFVSRYNVPRTNNSNTGVKQNTSAIKSSSSRNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
+
+>A-QC-316-2017_3C.2a_+_T131K_+_R142K_+_R261Q
+QNSSIEIDSQLENIQGQNKKLFVSRYNVPRTNNSNTGVKQNTSAIKSSSSRNTHLNYTAL
+NTMNNEQFDKLIVGTDKDIFLAQSRTKRSAVIPNIGSIPSRIKGILNSTIQSSPGKKSEF
+VRIACRYVKHS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test_output.csv	Thu Jul 04 19:37:41 2019 -0400
@@ -0,0 +1,23 @@
+
+,,,,44,45,46,47,48,50,51,53,54,57,59,62,63,67,75,78,80,81,82,83,86,87,88,91,92,94,96,102,103,109,117,121,122,124,126,128,129,130,131,132,133,135,137,138,140,142,143,144,145,146,150,152,155,156,157,158,159,160,163,164,165,167,168,170,171,172,173,174,175,176,177,179,182,186,187,188,189,190,192,193,194,196,197,198,201,203,207,208,209,212,213,214,215,216,217,218,219,226,227,228,229,230,238,240,242,244,246,247,248,260,261,262,265,273,275,276,278,279,280,294,297,299,300,304,305,307,308,309,310,311,312
+Clade_3C.2a_A/Hong_Kong/4801/2014_X-263B_EGG,,,,Q,N,S,S,I,E,I,D,S,Q,L,E,N,I,Q,G,Q,N,K,K,L,F,V,S,K,Y,S,V,P,R,T,N,N,S,N,T,G,V,T,Q,N,T,S,A,I,R,S,S,S,S,R,N,T,H,L,N,Y,K,A,L,N,T,M,N,N,E,Q,F,D,K,L,I,V,G,T,D,K,D,I,F,P,A,Q,S,R,X,K,R,S,A,V,I,P,N,I,G,S,I,P,S,R,I,K,G,I,L,N,S,T,I,R,S,S,P,G,K,K,S,E,F,V,R,I,A,C,R,Y,V,K,H,S
+Sequence Name,N,Clade,Extra Substitutions,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Number of Amino Acid Substitutions in Antigenic Sites,% Identity of Antigenic Site Residues
+A-BC-024-2018, ,3C.2a1_+_N121K_+_T135K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,D,.,.,.,.,.,.,.,.,.,H,N,.,.,.,.,K,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,I,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,10,0.9236641221374046,
+A-BC-324-2017, ,3C.2a1_+_N121K_+_K92R_+_H311Q, ,.,.,.,.,M,.,.,.,.,.,.,G,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,K,.,.,.,.,.,.,.,.,.,K,.,.,.,G,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,12,0.9083969465648855,
+A-BC-325-2017, ,3C.2a_+_N121K_+_S144K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,K,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,K,.,.,K,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,9,0.9312977099236641,
+A-BC-330-2017, ,No_Match, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,R,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,8,0.9389312977099237,
+A-AB-308-2017, ,3C.2a1_+_N121K_+_T135K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,D,.,.,.,.,.,.,.,.,.,H,N,.,.,.,.,K,D,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,I,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,11,0.916030534351145,
+A-AB-319-2017, ,3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H, ,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,G,.,R,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,L,.,H,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,11,0.916030534351145,
+A-AB-341-2017, ,3C.2a1_+_N121K_+_T135K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,D,.,.,.,.,.,.,.,.,.,H,N,.,.,.,.,K,D,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,I,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,11,0.916030534351145,
+A-AB-399-2017, ,3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H, ,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,G,.,R,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,L,.,H,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,11,0.916030534351145,
+A-AB-400-2017, ,3C.2a_+_T131K_+_R142K_+_R261Q, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,8,0.9389312977099237,
+A-AB-415-2017, ,3C.2a_+_T131K_+_R142K_+_R261Q, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,F,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,9,0.9312977099236641,
+A-AB-416-2017, ,3C.2a_+_T131K_+_R142K_+_R261Q, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,8,0.9389312977099237,
+A-ON-003-2018, ,3C.2a_+_N121K_+_S144K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,K,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,K,.,.,K,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,9,0.9312977099236641,
+A-ON-016-2018, ,3C.2a_+_N121K_+_S144K, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,K,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,K,.,.,K,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,9,0.9312977099236641,
+A-ON-309-2017, ,No_Match, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,K,T,.,I,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,8,0.9389312977099237,
+A-ON-314-2017, ,3C.3a, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,N,.,.,.,.,.,.,.,.,A,.,.,.,.,.,.,.,S,.,G,.,K,.,.,.,.,.,.,.,.,S,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,S,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,11,0.916030534351145,
+A-QC-303-2017, ,3C.2a_+_N31S_+_D53N_+_R142G_+_S144R_+_N171K_+_I192T_+_Q197H, ,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,N,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,G,.,R,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,T,.,L,.,H,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,11,0.916030534351145,
+A-QC-309-2017, ,3C.2a1_+_N121K_+_K92R_+_H311Q, ,.,.,.,.,.,.,.,.,.,.,.,G,.,.,.,D,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,K,D,.,.,.,.,.,.,.,.,K,.,.,.,G,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,13,0.9007633587786259,
+A-QC-315-2017, ,3C.2a1_+_N121K_+_K92R_+_H311Q, ,.,.,.,.,.,.,.,.,.,.,.,G,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,K,.,.,.,A,.,.,.,.,.,K,.,.,.,G,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,12,0.9083969465648855,
+A-QC-316-2017, ,3C.2a_+_T131K_+_R142K_+_R261Q, ,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,R,.,N,.,.,.,.,.,.,.,.,.,.,.,K,.,.,.,.,.,.,K,.,.,.,.,.,.,.,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,L,.,.,.,.,T,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,Q,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,8,0.9389312977099237,