Repository 'naturalis_lca'
hg clone https://toolshed.g2.bx.psu.edu/repos/duijker.d/naturalis_lca

Changeset 1:6f4d82f89b79 (2025-09-26)
Previous changeset 0:33460e756f42 (2024-06-13)
Commit message:
planemo upload for repository https://github.com/naturalis/galaxy-tool-lca.git commit cb8b2d61f994fee43f3dba1a6768e777aea72e85
modified:
README.md
lca.py
lca.sh
lca.xml
added:
usage.md
b
diff -r 33460e756f42 -r 6f4d82f89b79 README.md
--- a/README.md Thu Jun 13 13:56:03 2024 +0000
+++ b/README.md Fri Sep 26 07:13:34 2025 +0000
[
b"@@ -1,178 +1,30 @@\n # galaxy-tool-lca\n-A tool to determine the lowest common ancestor from BLAST results with taxonomy. This approach is partly based on MEGAN's (Huson et al., 2007) LCA method. This tool is more flexible and easier to use then MEGAN, it does not specifically use taxonids or separated mapping files. Instead, the script handles files with the taxonomy present in the last column of the input file. Those input files can be generated with our BLAST pipeline (not been published yet) or you can create them manually. Determining the lowest common ancestor can help to identify sequences that do not have a significant good blast hit. The basis of the approach for the analyses goes into the folowing order:\n-<br /><br />\n-**Step 1, determine the top percentage based on bitscore:** <br />\n-Of all the blast hits a sub-selection will be made of the top hits based on a percentage of the bitscore. If the top percentage is set to 8% the top will be calculated like 0.92\\*bitscore best hit=top threshold. In this example, all hits with a bitscore above 294.4 will continue to the next step.   \n-\n-| Query | Subject | Identity percentage | Coverage | bitscore |\n-| --- | --- | --- | --- | --- |\n-| Otu1 | hit1 | 93 | 95 | 320 |\n-| Otu1 | hit2 | 93 | 95 | 320 |\n-| Otu1 | hit3 | 91 | 94 | 310 |\n-| Otu1 | hit4 | 90 | 95 | 301 |\n-| Otu1 | hit5 | 89 | 94 | 300 |\n-| Otu1 | hit6 | 85 | 95 | 290 |\n-| Otu1 | hit7 | 84 | 95 | 290 |\n-| Otu1 | hit8 | 81 | 90 | 281 |\n-| Otu1 | hit9 | 80 | 89 | 275 |\n-| Otu1 | hit10 | 79 | 88 | 274 |\n-\n-<br />\n-\n-**Step 2, filter on threshold:** <br />\n-From the top hits there will be filtered on identity, coverage and bitscore. Let's choose a threshold of 90 identity, 90 coverage and 250 bitscore. All hits with scores above the thresholds will go to the next step. \n-\n-| Query | Subject | Identity percentage | Coverage | bitscore |\n-| --- | --- | --- | --- | --- |\n-| Otu1 | hit1 | 93 | 95 | 320 |\n-| Otu1 | hit2 | 93 | 95 | 320 |\n-| Otu1 | hit3 | 91 | 94 | 310 |\n-| Otu1 | hit4 | 90 | 95 | 301 |\n-| Otu1 | hit5 | 89 | 94 | 300 |\n-\n-<br />\n-\n-**Step 3, determine the lowest common ancestor:** <br />\n-Of all the remaining hits the lowest common ancestor is determined. The script starts at species level, it checks if all the hits are coming from the same species. If not it checks at genus level and so on. \n+A tool to determine the lowest common ancestor from BLAST results with taxonomy. This approach is partly based on MEGAN's (Huson et al., 2007) LCA method. This tool does not specifically use taxonids or separated mapping files. Instead, the script handles files with the taxonomy present in the last column of the input file. Those input files can be generated with our BLAST pipeline or you can create them manually.\n \n-| Query | Subject | taxonomy |\n-| --- | --- | --- |\n-| Otu1 | hit1 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scarbroughia / Scarbroughia delicatula |\n-| Otu1 | hit2 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scarbroughia / Scarbroughia delicatula |\n-| Otu1 | hit3 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Schildia / Schildia fragilis |\n-| Otu1 | hit4 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scytomedes / Scytomedes haemorrhoidalis |\n-\n-With this example data and thresholds the identification of otu1 will be Asilidae. This is a basic explanation of the LCA approach, more advanced filter settings and output options are shown at the example commands.\n-<br />\n-\n-## Getting Started\n-### Prerequisites\n-python 2.7\n-### Download\n-```\n-git clone https://github.com/naturalis/galaxy-tool-lca\n-```\n+## Installation\n+### Manual\n+Clone this repo in your Galaxy ***Tools*** directory:  \n+`git clone https://github.com/naturalis/galaxy-tool-lca`  \n \n-## Usage\n-There is an example input file included in the example folder, this file will be used to execute the commands. The file consist of 11 columns, has a specific header and is tab separated.<br />\n-<br />\n-**Column "..b'ov 80 -t best_hit -tid 98 -tcov 100 -flh unknown \n-```\n-**Example 3 best hit species level identification output explanation:**<br />\n-Now we have an otu that is identified on species level. Also the last column of Otu9 is different than in the previous examples. The value "best hit" means that there is no lca analysis performed, but the species of the top hit is chosen for identification. If you look at the example.tabular file you can see that the top hit of otu9 has an identity above 98 and coverage equal to 100. \n-\n-| #query | #lca rank | #lca taxon | #kingdom | #phylum | #class | #order | #family | #genus | #species | #method |\n-| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n-| Otu6 | genus | Thelepus | Eukaryota | Annelida | Polychaeta | Terebellida | Terebellidae | Thelepus | no identification | lca |\n-| Otu9 | species | Myxine glutinosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine glutinosa | best hit |\n+`  - repo: https://github.com/naturalis/galaxy-tool-lca`  \n+&ensp;&ensp;`file: lca.xml`  \n+&ensp;&ensp;`version: master`  \n \n-**Example 4 best hit range:**<br />\n-In some cases the sequences in the reference database are wrongly morphological identified or contaminated by human or bacterial DNA. It can also happen that a certain marker (16S, CO1, ITS) is not distinctive enough. Many people choose the top hit as the identification for the input sequence without looking at the second hit while that it can even be a better choice. In these cases the following command can help to solve this. Notice the changed parameter ```-t best_hits_range```\n-```\n-python lca.py -i example/example.tabular -o output4_example.tabular -b 8 -id 80 -cov 80 -t best_hits_range -tid 98 -tcov 100 -flh unknown\n-```\n-**Example 4 best hit range output explanation:**<br />\n-After executing the command otu6 stays the same. Otu6 does not have hits above ```-tid 98 -tcov 100``` so the parameter ```-t best_hits_range``` has no effect here. If we look at otu9 you see that it occurs twice in the output with two extra columns. Otu9 had multiple hits above ```-tid 98 -tcov 100``` on two different species. In the blast output of otu9 there were 6 hits on the species *Myxine glutinosa* with an identity between 98.7 and 100%.   \n-\n-| #query | #lca rank | #lca taxon | #kingdom | #phylum | #class | #order | #family | #genus | #species | #method | #identity | #coverage |\n-| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n-| Otu6 | genus | Thelepus | Eukaryota | Annelida | Polychaeta | Terebellida | Terebellidae | Thelepus | no identification | lca |  |  |\n-| Otu9 | species | Myxine glutinosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine glutinosa | top hit (6) | 98.7-100.0 | 100.0-100.0 |\n-| Otu9 | species | Myxine limosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine limosa | top hit (4) | 98.1-98.7 | 100.0-100.0 |\n+Information on tool usage, parameters and examples can be found [here](https://github.com/naturalis/galaxy-tool-lca/blob/master/usage.md)  \n \n ## How to cite\n Beentjes KK, Speksnijder AGCL, Schilthuizen M, Hoogeveen M, Pastoor R, et al. (2019) Increased performance of DNA metabarcoding of macroinvertebrates by taxonomic sorting. PLOS ONE 14(12): e0226527. https://doi.org/10.1371/journal.pone.0226527\n \n ## Source\n Huson, D. H., Auch, A. F., Qi, J., & Schuster, S. C. (2007). MEGAN analysis of metagenomic data. Genome Research, 17(3), 377\xe2\x80\x93386. http://doi.org/10.1101/gr.5969107\n-\n-## Installing at the local Naturalis galaxy server\n-### Prerequisites\n-This tool uses specifically the BLAST output as input\n-### Installing\n-Installing the tool for use in Galaxy\n-```\n-cd /home/galaxy/Tools\n-```\n-```\n-git clone https://github.com/naturalis/galaxy-tool-lca\n-```\n-Add the following line to /home/galaxy/galaxy/config/tool_conf.xml\n-```\n-<tool file="/home/galaxy/Tools/galaxy-tool-lca/lca.xml" />\n-```\n'
b
diff -r 33460e756f42 -r 6f4d82f89b79 lca.py
--- a/lca.py Thu Jun 13 13:56:03 2024 +0000
+++ b/lca.py Fri Sep 26 07:13:34 2025 +0000
[
b'@@ -1,37 +1,39 @@\n-#!/usr/bin/python\n+#!/usr/bin/env python\n import argparse\n \n parser = argparse.ArgumentParser(description=\'\')\n parser.add_argument(\'-i\', \'--input_file\', metavar=\'galaxy blast output\', dest=\'input\', type=str,\n-            help=\'input data in galaxy blast format\', default=\'\', required=True)\n+                    help=\'input data in galaxy blast format\', default=\'\', required=True)\n parser.add_argument(\'-o\', \'--output_file\', metavar=\'output file\', dest=\'output\', type=str,\n-            help=\'results file in tabular\', required=True)\n-parser.add_argument(\'-b\', \'--bitscore\', metavar=\'bitscore top percentage treshold\', dest=\'top\', type=str,\n-            help=\'top hits to find the lowest common ancestor\', required=True)\n+                    help=\'results file in tabular\', required=True)\n+parser.add_argument(\'-b\', \'--bitscore\', metavar=\'bitscore top percentage threshold\', dest=\'top\', type=str,\n+                    help=\'top hits to find the lowest common ancestor\', required=True)\n parser.add_argument(\'-id\', metavar=\'identity\', dest=\'id\', type=str,\n-            help=\'identity treshold\', required=True)\n+                    help=\'identity threshold\', required=True)\n parser.add_argument(\'-cov\', metavar=\'coverage\', dest=\'cov\', type=str,\n-            help=\'coverage treshold\', required=True)\n-parser.add_argument(\'-t\',\'--tophit\', metavar=\'tophit\', dest=\'tophit\', type=str,\n-            help=\'Check de best hit first, if it is above the gives treshold the tophit will become the output\', required=False, choices=[\'only_lca\', \'best_hit\', "best_hits_range"], nargs=\'?\', default=\'only_lca\')\n+                    help=\'coverage threshold\', required=True)\n+parser.add_argument(\'-t\', \'--tophit\', metavar=\'tophit\', dest=\'tophit\', type=str,\n+                    help=\'Check de best hit first, if it is above the gives threshold the tophit will become the output\',\n+                    required=False, choices=[\'only_lca\', \'best_hit\', "best_hits_range"], nargs=\'?\', default=\'only_lca\')\n parser.add_argument(\'-tid\', metavar=\'top_hit_identity\', dest=\'topid\', type=str,\n-            help=\'identity treshold for the tophit\', required=False, default=\'100\')\n+                    help=\'identity threshold for the tophit\', required=False, default=\'100\')\n parser.add_argument(\'-tcov\', metavar=\'top_hit_coverage\', dest=\'topcoverage\', type=str,\n-            help=\'query coverage treshold for the tophit\', required=False,  default=\'100\')\n+                    help=\'query coverage threshold for the tophit\', required=False, default=\'100\')\n parser.add_argument(\'-fh\', metavar=\'filter hits\', dest=\'filterHitsParam\', type=str,\n-            help=\'filter out hit that contain unwanted taxonomy\', required=False, default="",nargs=\'?\')\n+                    help=\'filter out hits that contain unwanted taxonomy\', required=False, default="", nargs=\'?\')\n parser.add_argument(\'-flh\', metavar=\'filter lca hits\', dest=\'filterLcaHits\', type=str,\n-            help=\'do not use a String in de lca determination\', required=False, default="",nargs=\'?\')\n+                    help=\'do not use a String in de lca determination\', required=False, default="", nargs=\'?\')\n parser.add_argument(\'-fs\', metavar=\'filter on taxonomy source\', dest=\'filterSourceHits\', type=str,\n-            help=\'do not use hit when taxonomy from source\', required=False, default="",nargs=\'?\')\n+                    help=\'do not use hit when taxonomy from source\', required=False, default="", nargs=\'?\')\n parser.add_argument(\'-minbit\', dest=\'minbit\', type=str, required=False, nargs=\'?\', default="0")\n \n args = parser.parse_args()\n \n+\n def filter_check(filterParam, line):\n     """\n     This method checks if the input (line) does not contain a certain string that is present\n-    in filterParam. filterParam is a comma seperated string, it will be converted to a list by\n+    in filterParam. filterParam is a comma separated string, it will be converted to a list by\n     splitting it on the "," character. If a string present in filterParam is als'..b'est_hits_range":  # if there was no best hit, check the lca\n                 resultingTaxonomy = get_lca(otu_filtered)\n-                output.write(resultingTaxonomy+endLine)\n+                output.write(resultingTaxonomy + endLine)\n \n         else:\n             taxonomy = ["no identification", "no identification", "no identification", "no identification",\n                         "no identification", "no identification", "no identification"]\n             output.write(\n-                otu[0][0] + "\\tno identification\\tno identification\\t" + "\\t".join(taxonomy).strip() + "\\tfiltered out"+endLine)\n+                otu[0][0] + "\\tno identification\\tno identification\\t" + "\\t".join(\n+                    taxonomy).strip() + "\\tfiltered out" + endLine)\n+\n \n def linecount():\n     """\n@@ -256,22 +275,26 @@\n             pass\n     return i\n \n+\n def write_header():\n     """\n     Write a header line to the output file\n     """\n     with open(args.output, "a") as output:\n         if args.tophit == "best_hits_range":\n-            output.write("#Query\\t#lca rank\\t#lca taxon\\t#kingdom\\t#phylum\\t#class\\t#order\\t#family\\t#genus\\t#species\\t#method\\t#identity\\t#coverage\\n")\n+            output.write(\n+                "#Query\\t#lca rank\\t#lca taxon\\t#kingdom\\t#phylum\\t#class\\t#order\\t#family\\t#genus\\t#species\\t#method\\t#identity\\t#coverage\\n")\n         else:\n-            output.write("#Query\\t#lca rank\\t#lca taxon\\t#kingdom\\t#phylum\\t#class\\t#order\\t#family\\t#genus\\t#species\\t#method\\n")\n+            output.write(\n+                "#Query\\t#lca rank\\t#lca taxon\\t#kingdom\\t#phylum\\t#class\\t#order\\t#family\\t#genus\\t#species\\t#method\\n")\n+\n \n def lca():\n     """\n-    This method loops trough the BLAST output and all the hits per otu will be the input for the determine_taxonomy method.\n+    This method loops through the BLAST output and all the hits per otu will be the input for the determine_taxonomy method.\n     The first line starts with "Query ID", this is the header so it will not be used. Every line of the same otu is stored in the\n     otuLines variable. There are multible otus in one file, only the lines of the same otu need to go in the determine_taxonomy method.\n-    This works as followed: You loop trought the file (blast output) the loop just started so num is not equal to 1 so the else block\n+    This works as followed: You loop through the file (blast output) the loop just started so num is not equal to 1 so the else block\n     is used and the first line of otu1 and the name \'otu1\' will be added to the lists. The second line is still otu1 and otu is present in\n     the otuList so again the else block will be used. When the loop reaches otu2, otu 2 is not present in otuLines so the otu1 line go into\n     the determine_taxonomy(otuLines) method and the lists will be emptied and the lines of otu2 will now be stored in the list.\n@@ -281,13 +304,13 @@\n     with open(args.input, "r") as input:\n         otuList = []\n         otuLines = []\n-        for num, line in enumerate(input):#start loop\n-            if line.split("\\t")[0].strip() != "#Query ID":#not use the header\n+        for num, line in enumerate(input):  # start loop\n+            if line.split("\\t")[0].strip() != "#Query ID":  # not use the header\n                 if line.split("\\t")[0] not in otuList and num != 1 or num == lastLineCount:\n                     if num == lastLineCount:\n                         otuList.append(line.split("\\t")[0])\n                         otuLines.append(line.split("\\t"))\n-                    determine_taxonomy(otuLines)#find the lca for the query\n+                    determine_taxonomy(otuLines)  # find the lca for the query\n                     otuList = []\n                     otuLines = []\n                     otuList.append(line.split("\\t")[0])\n@@ -296,8 +319,10 @@\n                     otuList.append(line.split("\\t")[0])\n                     otuLines.append(line.split("\\t"))\n \n+\n def main():\n     lca()\n \n+\n if __name__ == "__main__":\n     main()\n'
b
diff -r 33460e756f42 -r 6f4d82f89b79 lca.sh
--- a/lca.sh Thu Jun 13 13:56:03 2024 +0000
+++ b/lca.sh Fri Sep 26 07:13:34 2025 +0000
b
@@ -1,3 +1,10 @@
 #!/bin/bash
 SCRIPTDIR=$(dirname "$(readlink -f "$0")")
 python $SCRIPTDIR"/lca.py" -i $1 -o $2 -b $3 -id $4 -cov $5 -t $6 -tid $7 -tcov $8 -fh $9 -flh "${10}" -minbit "${11}" -fs "${12}"
+
+# sanity check
+printf "Conda env: $CONDA_DEFAULT_ENV\n"
+printf "SCRIPTDIR: $SCRIPTDIR\n"
+printf "Python version: $(python --version |  awk '{print $2}')\n"
+printf "Bash version: ${BASH_VERSION}\n\n"
+
b
diff -r 33460e756f42 -r 6f4d82f89b79 lca.xml
--- a/lca.xml Thu Jun 13 13:56:03 2024 +0000
+++ b/lca.xml Fri Sep 26 07:13:34 2025 +0000
b
@@ -1,4 +1,4 @@
-<tool id="lca" name="lowest common ancestor" version="1.0">
+<tool id="lca" name="lowest common ancestor" version="1.1">
 <!-- <description>Find lowest common ancestor</description>-->
 <requirements>
         <requirement type="package" version="3.8.2">python</requirement> 
@@ -39,8 +39,8 @@
 </command>
  <macros>
  <macro name="best_hit_params">
- <param name="tophitid" type="float" label="Identity treshold" value="100" min="1" max="100"/>
- <param name="tophitcoverage" type="float" label="Query coverage treshold"  value="100" min="1" max="100"/>
+ <param name="tophitid" type="float" label="Identity threshold" value="100" min="1" max="100"/>
+ <param name="tophitcoverage" type="float" label="Query coverage threshold"  value="100" min="1" max="100"/>
  </macro>
  </macros>
 <inputs>
@@ -51,8 +51,8 @@
 <param name="coverage" type="float" label="Minimum coverage"  value="70" min="1" max="100"/>
  <conditional name="setting_mode">
  <param name="setting" type="select" multiple="false" label="Settings mode">
- <option value="best_hit" selected="true">Output the top hit as species identification if it is above the choosen treshold</option>
-                        <option value="best_hits_range">Output all top hits above treshold</option>
+ <option value="best_hit" selected="true">Output the top hit as species identification if it is above the chosen threshold</option>
+                        <option value="best_hits_range">Output all top hits above threshold</option>
  <option value="only_lca">Check lca on all hits</option>
  </param>
  <when value="best_hit">
@@ -62,10 +62,10 @@
  <expand macro="best_hit_params"/>
  </when>
  </conditional>
- <param name="filterhits" type="text" label="Dont use hits containing this taxonomy:" help="Comma seperated"  value="environmental"/>
-    <param name="filterlcahits" type="text" label="Ignore rank when containing:" help="Comma seperated" value="unknown"/>
- <param name="filtersource" type="select" multiple="true" label="Dont use hits with taxonomy from:">
-            <option value="BOLD">BOLD</option>
+ <param name="filterhits" type="text" label="Don't use hits containing this taxonomy:" help="Comma separated"  value="environmental"/>
+    <param name="filterlcahits" type="text" label="Ignore rank when containing:" help="Comma separated" value="unknown"/>
+ <param name="filtersource" type="select" multiple="true" label="Don't use hits with taxonomy from:">
+            <option value="BOLD" label="BOLD">BOLD</option>
             <option value="private_BOLD">private_BOLD</option>
             <option value="Genbank">Genbank</option>
         </param>
@@ -75,12 +75,12 @@
 <outputs>
  <data format="tabular" name="output" label="$input.display_name lca" />
 </outputs>
-<!-- <tests>
+<tests>
 <test>
 <param name="test_input" value="test_input.txt"/>
-<output name="test_outout" file="test_output.txt"/>
+<output name="test_output" file="test_output.txt"/>
 </test>
-</tests> -->
+</tests>
 <help>
 Find lca from blast output
 </help>
b
diff -r 33460e756f42 -r 6f4d82f89b79 usage.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usage.md Fri Sep 26 07:13:34 2025 +0000
[
b'@@ -0,0 +1,148 @@\n+## Getting Started\n+The LCA tool uses bitscore, identity percentage and the LCA script itself in the following order:\n+<br /><br />\n+**Step 1, determine the top percentage based on bitscore:** <br />\n+Of all the blast hits a sub-selection will be made of the top hits based on a percentage of the bitscore. If the top percentage is set to 8% the top will be calculated like 0.92\\*bitscore best hit=top threshold. In this example, all hits with a bitscore above 294.4 will continue to the next step.   \n+\n+| Query | Subject | Identity percentage | Coverage | bitscore |\n+| --- | --- | --- | --- | --- |\n+| Otu1 | hit1 | 93 | 95 | 320 |\n+| Otu1 | hit2 | 93 | 95 | 320 |\n+| Otu1 | hit3 | 91 | 94 | 310 |\n+| Otu1 | hit4 | 90 | 95 | 301 |\n+| Otu1 | hit5 | 89 | 94 | 300 |\n+| Otu1 | hit6 | 85 | 95 | 290 |\n+| Otu1 | hit7 | 84 | 95 | 290 |\n+| Otu1 | hit8 | 81 | 90 | 281 |\n+| Otu1 | hit9 | 80 | 89 | 275 |\n+| Otu1 | hit10 | 79 | 88 | 274 |\n+\n+<br />\n+\n+**Step 2, filter on threshold:** <br />\n+From the top hits there will be filtered on identity, coverage and bitscore. Let\'s choose a threshold of 90 identity, 90 coverage and 250 bitscore. All hits with scores above the thresholds will go to the next step. \n+\n+| Query | Subject | Identity percentage | Coverage | bitscore |\n+| --- | --- | --- | --- | --- |\n+| Otu1 | hit1 | 93 | 95 | 320 |\n+| Otu1 | hit2 | 93 | 95 | 320 |\n+| Otu1 | hit3 | 91 | 94 | 310 |\n+| Otu1 | hit4 | 90 | 95 | 301 |\n+| Otu1 | hit5 | 89 | 94 | 300 |\n+\n+<br />\n+\n+**Step 3, determine the lowest common ancestor:** <br />\n+Of all the remaining hits the lowest common ancestor is determined. The script starts at species level, it checks if all the hits are coming from the same species. If not it checks at genus level and so on. \n+\n+| Query | Subject | taxonomy |\n+| --- | --- | --- |\n+| Otu1 | hit1 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scarbroughia / Scarbroughia delicatula |\n+| Otu1 | hit2 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scarbroughia / Scarbroughia delicatula |\n+| Otu1 | hit3 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Schildia / Schildia fragilis |\n+| Otu1 | hit4 | Animalia / Arthropoda / Insecta / Diptera / Asilidae / Scytomedes / Scytomedes haemorrhoidalis |\n+\n+With this example data and thresholds the identification of otu1 will be Asilidae. This is a basic explanation of the LCA approach, more advanced filter settings and output options are shown at the example commands.\n+<br />\n+\n+## Usage\n+There is an example input file included in the example folder, this file will be used to execute the commands. The file consist of 11 columns, has a specific header and is tab separated.<br />\n+<br />\n+**Column explanation input file:**\n+\n+| Column name | Description |\n+| --- | --- |\n+| Query ID | Id of the input sequence (qseqid) |\n+| Subject | Means Subject Title (stitle) |\n+| Subject accession | Subject accession (sacc) |\n+| Subject Taxonomy ID | Unique Subject Taxonomy ID (staxid), this value can be any value and is not used to find the lca |\n+| Identity percentage | Identity percentage of hit () |\n+| Coverage | Means Query Coverage Per Subject (qcovs) |\n+| Evalue | Expected value of the hit (evalue) |\n+| Bitscore | Bit score of hit (bitscore) |\n+| Source | The source of where the taxonomy comes from, this value can be any value and is not used to find the lca |\n+| Taxonomy | This column contains the taxonomy of the hit in the order Kingdom / phylum / class / order / family / genus /species |\n+\n+The script itself has multiple parameter options.<br />\n+<br />\n+**Parameters:**\n+\n+| Parameter | Description |\n+| --- | --- |\n+| -i | Input file |\n+| -o | Output file |\n+| -b | Bitscore top percentage threshold |\n+| -id | Minimum identity threshold |\n+| -cov | Minimum coverage threshold |\n+| -t | Check the top hit first or perform an lca analysis on all hits. Options:[\'only_lca\', \'best_hit\', "best_hits_range"] |\n+| -tid | Identity threshold for the tophit, only used when -t'..b'in the first hit. \n+\n+| #query | #lca rank | #lca taxon | #kingdom | #phylum | #class | #order | #family | #genus | #species | #method |\n+| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n+| Otu6 | genus | Thelepus | Eukaryota | Annelida | Polychaeta | Terebellida | Terebellidae | Thelepus | no identification | lca |\n+| Otu16 | order | Polychaeta incertae sedis | Animalia | Annelida | Polychaeta | Polychaeta incertae sedis | no identification | no identification | no identification | lca |\n+\n+**Example 3 best hit species level identification:**<br />\n+This command performs an lca analysis if the top hit falls below the "top hit" thresholds. If the top blast hit (sorted on evalue) exceeds the thresholds the top hit is chosen and the input sequence gets a species level identification. Notice the change in parameters ```-t best_hit -tid 98 -tcov 100```. If the top hit has an identity above 98% and a coverage above or equal to 100% this hit will be the taxonomic identification and will be at species level.    \n+```\n+python lca.py -i example/example.tabular -o output3_example.tabular -b 8 -id 80 -cov 80 -t best_hit -tid 98 -tcov 100 -flh unknown \n+```\n+**Example 3 best hit species level identification output explanation:**<br />\n+Now we have an otu that is identified on species level. Also the last column of Otu9 is different than in the previous examples. The value "best hit" means that there is no lca analysis performed, but the species of the top hit is chosen for identification. If you look at the example.tabular file you can see that the top hit of otu9 has an identity above 98 and coverage equal to 100. \n+\n+| #query | #lca rank | #lca taxon | #kingdom | #phylum | #class | #order | #family | #genus | #species | #method |\n+| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n+| Otu6 | genus | Thelepus | Eukaryota | Annelida | Polychaeta | Terebellida | Terebellidae | Thelepus | no identification | lca |\n+| Otu9 | species | Myxine glutinosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine glutinosa | best hit |\n+\n+**Example 4 best hit range:**<br />\n+In some cases the sequences in the reference database are wrongly morphological identified or contaminated by human or bacterial DNA. It can also happen that a certain marker (16S, CO1, ITS) is not distinctive enough. Many people choose the top hit as the identification for the input sequence without looking at the second hit while that it can even be a better choice. In these cases the following command can help to solve this. Notice the changed parameter ```-t best_hits_range```\n+```\n+python lca.py -i example/example.tabular -o output4_example.tabular -b 8 -id 80 -cov 80 -t best_hits_range -tid 98 -tcov 100 -flh unknown\n+```\n+**Example 4 best hit range output explanation:**<br />\n+After executing the command otu6 stays the same. Otu6 does not have hits above ```-tid 98 -tcov 100``` so the parameter ```-t best_hits_range``` has no effect here. If we look at otu9 you see that it occurs twice in the output with two extra columns. Otu9 had multiple hits above ```-tid 98 -tcov 100``` on two different species. In the blast output of otu9 there were 6 hits on the species *Myxine glutinosa* with an identity between 98.7 and 100%.   \n+\n+| #query | #lca rank | #lca taxon | #kingdom | #phylum | #class | #order | #family | #genus | #species | #method | #identity | #coverage |\n+| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n+| Otu6 | genus | Thelepus | Eukaryota | Annelida | Polychaeta | Terebellida | Terebellidae | Thelepus | no identification | lca |  |  |\n+| Otu9 | species | Myxine glutinosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine glutinosa | top hit (6) | 98.7-100.0 | 100.0-100.0 |\n+| Otu9 | species | Myxine limosa | Eukaryota | Chordata | unknown class | Myxiniformes | Myxinidae | Myxine | Myxine limosa | top hit (4) | 98.1-98.7 | 100.0-100.0 |\n'