Commit 7f23c2e0 authored by jhoogenboom's avatar jhoogenboom
Browse files

Reworked input/output file arguments

* All tools now write to stdout by default. Tools that support
  writing report files write those to stderr by default. The
  -o/--output and -r/--report options can be used to override
  these.
* Tools that operated on one sample at a time (bgcorrect,
  seqconvert, stuttermark) now support batch processing. The new
  -i/--input argument takes a list of files. In batch mode,
  the -o/--output argument can be used to specify a list of
  corresponding output files (which must be the same length). It
  is also possible to specify a format string to automatically
  generate file names. -o/--output defaults to "\1-\2.out" which is
  automatically expanded to "sampletag-toolname.out". The old
  positional arguments [IN] and [OUT] are maintained and allow for
  conveniently running the tools on a single sample file.
  [IN] is mutually exclusive with -i/--input and [OUT] is mutually
  exclusive with -o/--output. [OUT] now also accepts the filename
  format, but when not in batch mode, it still defaults to stdout.
  Note that by default, the sample tag is extracted from the input
  filenames by simply stripping the extension. This means a minimal
  batch processing command like "fdstools stuttermark -i *.csv"
  automatically creates a "...-stuttermark.out" file next to each
  CSV file in the current working directory.
* Libconvert now also supports only specifying an output file.
  This makes it easier to write the default FDSTools library to a
  new file. E.g., "fdstools libconvert mynewfile.txt" now creates
  "mynewfile.txt" if it does not exist, and writes the default
  library to it. Most helpful.
parent b30bdbbc
......@@ -41,6 +41,11 @@ DEF_TAG_EXPR = "^(.*?)(?:\.[^.]+)?$"
# This is the default of the -f command line option.
DEF_TAG_FORMAT = "\\1"
# Default formatting template to construct output file names for batch
# processing. \1 and \2 refer to sample tag and tool name.
# This is the default for the -o command line option with batch support.
DEF_OUTFILE_FORMAT = "\\1-\\2.out"
def call_variants(template, sequence, reverse_indices=False, cache=True,
debug=False):
......@@ -1025,39 +1030,15 @@ def add_allele_detection_args(parser):
#add_allele_detection_args
def add_sample_files_args(parser):
"""Add arguments for opening sample files to the given parser."""
parser.add_argument('filelist', nargs='*', metavar="FILE",
default=[sys.stdin], type=argparse.FileType('r'),
help="the sample data file(s) to process (default: read from stdin)")
group = parser.add_argument_group("sample tag parsing options")
group.add_argument('-e', '--tag-expr', metavar="REGEX", type=re.compile,
default=DEF_TAG_EXPR,
help="regular expression that captures (using one or more capturing "
"groups) the sample tags from the file names; by default, the "
"entire file name except for its extension (if any) is captured")
group.add_argument('-f', '--tag-format', metavar="EXPR",
default=DEF_TAG_FORMAT,
help="format of the sample tags produced; a capturing group reference "
"like '\\n' refers to the n-th capturing group in the regular "
"expression specified with -e/--tag-expr (the default of '\\1' "
"simply uses the first capturing group); with a single sample, "
"you can enter the sample tag here explicitly")
#add_sample_files_args
def add_output_args(parser, report=True):
group = parser.add_argument_group("output destination options")
group.add_argument('-o', '--output', metavar="FILE",
type=argparse.FileType('w'),
default=sys.stdout,
help="file to write output to (default: write to stdout)")
if report:
group.add_argument('-r', '--report', metavar="FILE",
type=argparse.FileType('w'),
default=sys.stderr,
help="file to write a report to (default: write to stderr)")
#add_output_args
def add_random_subsampling_args(parser):
group = parser.add_argument_group("random subsampling options (advanced)")
group.add_argument('-R', '--limit-reads', metavar="N", type=pos_int_arg,
default=sys.maxint,
help="simulate lower sequencing depth by randomly dropping reads down "
"to this maximum total number of reads for each sample")
group.add_argument('-x', '--drop-samples', metavar="N", type=float,
default=0, help="randomly drop this fraction of input samples")
#add_random_subsampling_args
def add_sequence_format_args(parser, default_format=None, force=False):
......@@ -1078,15 +1059,80 @@ def add_sequence_format_args(parser, default_format=None, force=False):
#add_sequence_format_args
def add_random_subsampling_args(parser):
group = parser.add_argument_group("random subsampling options (advanced)")
group.add_argument('-R', '--limit-reads', metavar="N", type=pos_int_arg,
default=sys.maxint,
help="simulate lower sequencing depth by randomly dropping reads down "
"to this maximum total number of reads for each sample")
group.add_argument('-x', '--drop-samples', metavar="N", type=float,
default=0, help="randomly drop this fraction of input samples")
#add_random_subsampling_args
def add_input_output_args(parser, single_in=False, batch_support=False,
report_out=False):
"""Add arguments for opening sample files to the given parser."""
# Input file options group.
if not single_in:
parser.add_argument('infiles', nargs='*', metavar="FILE",
default=[sys.stdin], type=argparse.FileType('r'),
help="the sample data file(s) to process (default: read from "
"stdin)")
elif not batch_support:
parser.add_argument('infile', nargs='?', metavar="IN",
default=sys.stdin, type=argparse.FileType('r'),
help="the sample data file to process (default: read from stdin)")
else:
mutex = parser.add_argument_group(
"input file options").add_mutually_exclusive_group()
mutex.add_argument('infile', nargs='?', metavar="IN",
default=sys.stdin, type=argparse.FileType('r'),
help="single sample data file to process (default: read from "
"stdin)")
mutex.add_argument("-i", "--input", dest="infiles", nargs="+",
metavar="IN", type=argparse.FileType('r'),
help="multiple sample data files to process (use with "
"-o/--output)")
# Output file options group.
group = parser.add_argument_group("output file options")
if batch_support and single_in:
mutex = group.add_mutually_exclusive_group()
mutex.add_argument('outfile', nargs='?', metavar="OUT",
default=sys.stdout,
help="the file to write the output to (default: write to stdout)")
mutex.add_argument('-o', '--output', dest="outfiles", nargs="+",
metavar="OUT",
help="list of names of output files to match with input files "
"specified with -i/--input, or a format string to construct "
"file names from sample tags; e.g., the default value is "
"'\\1-%s.out', which expands to 'sampletag-%s.out'" %
((parser.prog.rsplit(" ", 1)[-1],)*2))
elif batch_support:
group.add_argument('-o', '--output', dest="outfiles", nargs="+",
metavar="OUT",
default=[sys.stdout],
help="a single file name to write all output to (default: write "
"to stdout) OR a list of names of output files to match with "
"input files OR a format string to construct file names from "
"sample tags; e.g., the value '\\1-%s.out' expands to "
"'sampletag-%s.out'" % ((parser.prog.rsplit(" ", 1)[-1],)*2))
else:
group.add_argument('-o', '--output', dest="outfile", metavar="FILE",
type=argparse.FileType('w'),
default=sys.stdout,
help="file to write output to (default: write to stdout)")
if report_out:
group.add_argument('-r', '--report', metavar="FILE",
type=argparse.FileType('w'),
default=sys.stderr,
help="file to write a report to (default: write to stderr)")
# Sample tag parsing options group.
group = parser.add_argument_group("sample tag parsing options")
group.add_argument('-e', '--tag-expr', metavar="REGEX", type=re.compile,
default=DEF_TAG_EXPR,
help="regular expression that captures (using one or more capturing "
"groups) the sample tags from the file names; by default, the "
"entire file name except for its extension (if any) is captured")
group.add_argument('-f', '--tag-format', metavar="EXPR",
default=DEF_TAG_FORMAT,
help="format of the sample tags produced; a capturing group reference "
"like '\\n' refers to the n-th capturing group in the regular "
"expression specified with -e/--tag-expr (the default of '\\1' "
"simply uses the first capturing group); with a single sample, "
"you can enter the sample tag here explicitly")
#add_input_output_args
def get_tag(filename, tag_expr, tag_format):
......@@ -1098,16 +1144,74 @@ def get_tag(filename, tag_expr, tag_format):
#get_tag
def map_tags_to_files(filelist, tag_expr, tag_format):
tags_to_files = {}
for infile in filelist:
tag = get_tag(infile.name, tag_expr, tag_format)
if tag not in tags_to_files:
tags_to_files[tag] = [infile]
else:
tags_to_files[tag].append(infile)
return tags_to_files
#map_tags_to_files
def get_input_output_files(args, single=False, batch_support=False):
if single and not batch_support:
# One infile, one outfile. Return 2-tuple (infile, outfile).
if args.infile.isatty():
return False # No input specified.
return args.infile, args.outfile
if not single and not batch_support:
# N infiles, one outfile. Return 2-tuple ({tag: infiles}, out).
infiles = args.infiles if "infiles" in args \
and args.infiles is not None else [args.infile]
if len(infiles) == 1 and infiles[0].isatty():
return False # No input specified.
tags_to_files = {}
for infile in infiles:
tag = get_tag(infile.name, args.tag_expr, args.tag_format)
try:
tags_to_files[tag].append(infile)
except KeyError:
tags_to_files[tag] = [infile]
return tags_to_files, args.outfile
if single and batch_support:
# N infiles, N outfiles. Return generator of (tag, [ins], out).
# Each yielded tuple should cause a separate run of the tool.
infiles = args.infiles if "infiles" in args \
and args.infiles is not None else [args.infile]
if len(infiles) == 1 and infiles[0].isatty():
return False # No input specified.
outfiles = args.outfiles if "outfiles" in args \
and args.outfiles is not None else [args.outfile]
if len(outfiles) > 1 and len(outfiles) != len(infiles):
raise ValueError(
"Number of input files (%i) is not equal to number of output "
"files (%i)." % (len(infiles), len(outfiles)))
tags = [get_tag(infile.name, args.tag_expr, args.tag_format)
for infile in infiles]
if len(outfiles) == 1:
outfile = outfiles[0]
if outfile == sys.stdout and len(set(tags)) == 1:
# Write output of single sample to stdout.
return ((tag, infiles, outfile) for tag in set(tags))
# Write output of each sample to its own outfile.
if outfile == sys.stdout:
outfile = DEF_OUTFILE_FORMAT
return ((tag,
[infiles[i] for i in range(len(tags)) if tags[i]==tag],
open(outfile.replace("\\1", tag).replace("\\2",
args.tool), "w")) for tag in set(tags))
# Link each output file to each input file.
# Treating files with the same sample tag as separate samples.
return ((tags[i], [infiles[i]], open(outfiles[i], 'w'))
for i in range(len(tags)))
if not single and batch_support:
# N infiles, one or N outfiles.
# If one outfile, return ({tag: [infiles]}, outfile).
# If N outfiles, return generator of (tag, [infiles], outfile).
raise NotImplementedError("Multi-input with optional multi-output not supported yet.")
#get_input_output_files
def print_db(text, debug):
......
......@@ -11,11 +11,10 @@ called for this marker. If this happens for multiple markers in one
sample, no alleles are called for this sample at all.
"""
import argparse
import sys
from ..lib import get_column_ids, pos_int_arg, map_tags_to_files, \
add_sample_files_args, ensure_sequence_format, \
get_sample_data, add_sequence_format_args, add_output_args
from ..lib import pos_int_arg, add_input_output_args, get_input_output_files, \
ensure_sequence_format, get_sample_data, \
add_sequence_format_args
__version__ = "0.1dev"
......@@ -47,16 +46,16 @@ _DEF_MAX_ALLELES = 2
_DEF_MAX_NOISY = 2
def find_alleles(filelist, outfile, reportfile, tag_expr, tag_format,
min_reads, min_allele_pct, max_noise_pct, max_alleles,
max_noisy, stuttermark_column, seqformat, library):
def find_alleles(samples_in, outfile, reportfile, min_reads, min_allele_pct,
max_noise_pct, max_alleles, max_noisy, stuttermark_column,
seqformat, library):
if seqformat is not None and library is not None:
library = parse_library(library)
outfile.write("\t".join(["sample", "marker", "total", "allele"]) + "\n")
allelelist = {}
get_sample_data(
map_tags_to_files(filelist, tag_expr, tag_format),
samples_in,
lambda tag, data: find_alleles_sample(
data if stuttermark_column is None
else {key: data[key] for key in allelelist[tag]},
......@@ -152,7 +151,7 @@ def find_alleles_sample(data, outfile, reportfile, tag, min_reads,
def add_arguments(parser):
add_output_args(parser)
add_input_output_args(parser, False, False, True)
filtergroup = parser.add_argument_group("filtering options")
filtergroup.add_argument('-m', '--min-allele-pct', metavar="PCT",
type=float, default=_DEF_MIN_ALLELE_PCT,
......@@ -180,19 +179,19 @@ def add_arguments(parser):
"for which the value in this column does not start with ALLELE "
"are ignored")
add_sequence_format_args(parser)
add_sample_files_args(parser)
#add_arguments
def run(args):
if args.filelist == [sys.stdin] and sys.stdin.isatty():
files = get_input_output_files(args)
if not files:
raise ValueError("please specify an input file, or pipe in the output "
"of another program")
find_alleles(args.filelist, args.output, args.report, args.tag_expr,
args.tag_format, args.min_reads, args.min_allele_pct,
args.max_noise_pct, args.max_alleles, args.max_noisy,
args.stuttermark_column, args.sequence_format, args.library)
find_alleles(files[0], files[1], args.report, args.min_reads,
args.min_allele_pct, args.max_noise_pct, args.max_alleles,
args.max_noisy, args.stuttermark_column, args.sequence_format,
args.library)
#run
......
......@@ -9,11 +9,11 @@ columns) and the number of noise reads caused by the prescense of this
sequence (_add columns).
"""
import argparse
import sys
#import numpy as np # Only imported when actually running this tool.
from ..lib import parse_library, load_profiles, ensure_sequence_format, nnls, \
get_column_ids, add_sequence_format_args
get_column_ids, add_sequence_format_args, \
add_input_output_args, get_input_output_files
__version__ = "0.1dev"
......@@ -141,12 +141,7 @@ def match_profile(column_names, data, profile, convert_to_raw, library,
#match_profile
def match_profiles(profilefile, infile, outfile, libfile, seqformat, marker):
library = parse_library(libfile) if libfile else None
profiles = load_profiles(profilefile, library)
if marker:
profiles = {marker: profiles[marker]} if marker in profiles else {}
def match_profiles(infile, outfile, profiles, library, seqformat):
column_names, data = get_sample_data(
infile, convert_to_raw=seqformat=="raw", library=library)
colid_allele = get_column_ids(column_names, "allele")
......@@ -168,13 +163,7 @@ def add_arguments(parser):
parser.add_argument('profiles', metavar="PROFILES",
type=argparse.FileType('r'),
help="file containing background noise profiles to match")
parser.add_argument('infile', nargs='?', metavar="IN", default=sys.stdin,
type=argparse.FileType('r'),
help="the tab-separated data file to process (default: read from "
"stdin)")
parser.add_argument('outfile', nargs='?', metavar="OUT",
default=sys.stdout, type=argparse.FileType('w'),
help="the file to write the output to (default: write to stdout)")
add_input_output_args(parser, True, True, False)
filtergroup = parser.add_argument_group("filtering options")
filtergroup.add_argument('-M', '--marker', metavar="MARKER",
help="work only on MARKER")
......@@ -183,11 +172,24 @@ def add_arguments(parser):
def run(args):
if args.infile.isatty() and args.outfile.isatty():
gen = get_input_output_files(args, True, True)
if not gen:
raise ValueError("please specify an input file, or pipe in the output "
"of another program")
match_profiles(args.profiles, args.infile, args.outfile, args.library,
args.sequence_format, args.marker)
# Read library and profiles once.
library = parse_library(args.library) if args.library else None
profiles = load_profiles(args.profiles, library)
if args.marker:
profiles = {args.marker: profiles[args.marker]} \
if args.marker in profiles else {}
for tag, infiles, outfile in gen:
# TODO: Aggregate data from all infiles of each sample.
# This tool now only works properly with one infile per sample!
for infile in infiles:
match_profiles(infile, outfile, profiles, library,
args.sequence_format)
#run
......
......@@ -13,11 +13,10 @@ import time
import math
#import numpy as np # Only imported when actually running this tool.
from ..lib import get_column_ids, pos_int_arg, add_sample_files_args,\
add_allele_detection_args, map_tags_to_files, nnls,\
ensure_sequence_format, parse_allelelist, parse_library,\
get_sample_data, add_random_subsampling_args,\
add_sequence_format_args, add_output_args
from ..lib import pos_int_arg, add_input_output_args, get_input_output_files,\
add_allele_detection_args, nnls, add_sequence_format_args,\
parse_allelelist, parse_library, get_sample_data, \
add_random_subsampling_args
__version__ = "0.1dev"
......@@ -397,11 +396,10 @@ def preprocess_data(data, min_sample_pct):
#preprocess_data
def generate_profiles(filelist, tag_expr, tag_format, allelefile,
annotation_column, outfile, reportfile, min_pct, min_abs,
min_samples, min_sample_pct, seqformat, library,
crosstab, marker, homozygotes, limit_reads,
drop_samples):
def generate_profiles(samples_in, outfile, reportfile, allelefile,
annotation_column, min_pct, min_abs, min_samples,
min_sample_pct, seqformat, library, crosstab, marker,
homozygotes, limit_reads, drop_samples):
if reportfile:
t0 = time.time()
......@@ -412,7 +410,7 @@ def generate_profiles(filelist, tag_expr, tag_format, allelefile,
# Read sample data.
sample_data = {}
get_sample_data(map_tags_to_files(filelist, tag_expr, tag_format),
get_sample_data(samples_in,
lambda tag, data: sample_data.update({tag: data}),
allelelist, annotation_column, seqformat, library, marker,
homozygotes, limit_reads, drop_samples)
......@@ -495,7 +493,7 @@ def generate_profiles(filelist, tag_expr, tag_format, allelefile,
def add_arguments(parser):
add_output_args(parser)
add_input_output_args(parser, False, False, True)
parser.add_argument('-C', '--cross-tabular', action="store_true",
help="if specified, a space-efficient cross-tabular output format is "
"used instead of the default tab-separated columns format")
......@@ -523,18 +521,17 @@ def add_arguments(parser):
filtergroup.add_argument('-H', '--homozygotes', action="store_true",
help="if specified, only homozygous samples will be considered")
add_sequence_format_args(parser, "raw", True) # Force raw seqs.
add_sample_files_args(parser)
add_random_subsampling_args(parser)
#add_arguments
def run(args):
if args.filelist == [sys.stdin] and sys.stdin.isatty():
files = get_input_output_files(args)
if not files:
raise ValueError("please specify an input file, or pipe in the output "
"of another program")
generate_profiles(args.filelist, args.tag_expr, args.tag_format,
args.allelelist, args.annotation_column, args.output,
args.report, args.min_pct, args.min_abs,
generate_profiles(files[0], files[1], args.report, args.allelelist,
args.annotation_column, args.min_pct, args.min_abs,
args.min_samples, args.min_sample_pct,
args.sequence_format, args.library, args.cross_tabular,
args.marker, args.homozygotes, args.limit_reads,
......
......@@ -8,12 +8,10 @@ in the database of reference samples. The profiles obtained can be used
by bgcorrect to filter background noise from samples.
"""
import argparse
import sys
from ..lib import get_column_ids, pos_int_arg, add_sample_files_args,\
add_allele_detection_args, map_tags_to_files, adjust_stats,\
ensure_sequence_format, parse_allelelist, parse_library,\
get_sample_data, add_sequence_format_args, add_output_args,\
from ..lib import pos_int_arg, add_input_output_args, get_input_output_files,\
add_allele_detection_args, parse_allelelist, parse_library,\
get_sample_data, add_sequence_format_args, adjust_stats,\
add_random_subsampling_args
__version__ = "0.1dev"
......@@ -88,10 +86,9 @@ def filter_data(data, min_samples, min_sample_pct):
#filter_data
def compute_stats(filelist, tag_expr, tag_format, allelefile,
annotation_column, outfile, min_pct, min_abs, min_samples,
min_sample_pct, seqformat, library, marker, limit_reads,
drop_samples):
def compute_stats(samples_in, outfile, allelefile, annotation_column, min_pct,
min_abs, min_samples, min_sample_pct, seqformat, library,
marker, limit_reads, drop_samples):
# Parse library and allele list.
library = parse_library(library) if library is not None else None
......@@ -101,7 +98,7 @@ def compute_stats(filelist, tag_expr, tag_format, allelefile,
# Read sample data.
data = {}
get_sample_data(
map_tags_to_files(filelist, tag_expr, tag_format),
samples_in,
lambda tag, sample_data: add_sample_data(
data, sample_data,
{m: allelelist[tag][m].pop() for m in allelelist[tag]},
......@@ -133,7 +130,7 @@ def compute_stats(filelist, tag_expr, tag_format, allelefile,
def add_arguments(parser):
add_output_args(parser, False)
add_input_output_args(parser)
add_allele_detection_args(parser)
filtergroup = parser.add_argument_group("filtering options")
filtergroup.add_argument('-m', '--min-pct', metavar="PCT", type=float,
......@@ -158,17 +155,16 @@ def add_arguments(parser):
filtergroup.add_argument('-M', '--marker', metavar="MARKER",
help="work only on MARKER")
add_sequence_format_args(parser)
add_sample_files_args(parser)
add_random_subsampling_args(parser)
#add_arguments
def run(args):
if args.filelist == [sys.stdin] and sys.stdin.isatty():
files = get_input_output_files(args)
if not files:
raise ValueError("please specify an input file, or pipe in the output "
"of another program")
compute_stats(args.filelist, args.tag_expr, args.tag_format,
args.allelelist, args.annotation_column, args.output,
compute_stats(files[0], files[1], args.allelelist, args.annotation_column,
args.min_pct, args.min_abs, args.min_samples,
args.min_sample_pct, args.sequence_format, args.library,
args.marker, args.limit_reads, args.drop_samples)
......
......@@ -12,13 +12,12 @@ allelic read.
produce a DNA profile of an untidy laboratory worker.)
"""
import argparse
import sys
#import numpy as np # Only imported when actually running this tool.
from ..lib import get_column_ids, pos_int_arg, add_sample_files_args,\
add_allele_detection_args, map_tags_to_files, nnls,\
ensure_sequence_format, parse_allelelist, load_profiles,\
parse_library, get_sample_data, add_sequence_format_args
from ..lib import pos_int_arg, add_input_output_args, get_input_output_files,\
add_allele_detection_args, nnls, ensure_sequence_format,\
parse_allelelist, load_profiles, add_sequence_format_args,\
parse_library, get_sample_data
__version__ = "0.1dev"
......@@ -60,7 +59,7 @@ def add_sample_data(data, sample_data, sample_tag, alleles):
#add_sample_data
def blame(filelist, tag_expr, tag_format, allelefile, annotation_column, mode,
def blame(samples_in, outfile, allelefile, annotation_column, mode,
profilefile, num, seqformat, libfile, marker):
import numpy as np
library = parse_library(libfile) if libfile else None
......@@ -77,15 +76,15 @@ def blame(filelist, tag_expr, tag_format, allelefile, annotation_column, mode,
# Read sample data.
get_sample_data(
map_tags_to_files(filelist, tag_expr, tag_format),
samples_in,
lambda tag, sample_data: add_sample_data(
data, sample_data, tag,
{m: allelelist[tag][m] for m in data if m in allelelist[tag]}),
allelelist, annotation_column, "raw", library)
print("\t".join(["marker",
outfile.write("\t".join(["marker",
"allele" if mode == "common" else "sample",
"amount"]))
"amount"]) + "\n")
for marker in data:
if not data[marker]["sample_tags"]:
continue
......@@ -111,9 +110,9 @@ def blame(filelist, tag_expr, tag_format, allelefile, annotation_column, mode,
for i in np.argsort(A)[:-num-1:-1]: # Print the top N.
if A[i] == 0:
break
print("\t".join([marker, ensure_sequence_format(
outfile.write("\t".join([marker, ensure_sequence_format(
data[marker]["seqs"][i], seqformat, library=library,
marker=marker), str(A[i])]))
marker=marker), str(A[i])]) + "\n")
else:
# The rows with the highest maxima/sums correspond to the
# samples with the highest amounts of contaminant/s.
......@@ -121,8 +120,8 @@ def blame(filelist, tag_expr, tag_format, allelefile, annotation_column, mode,
for i in np.argsort(A)[:-num-1:-1]: # Print the top N.
if A[i] == 0:
break
print("\t".join(
[marker, data[marker]["sample_tags"][i], str(A[i])]))
outfile.write("\t".join(
[marker, data[marker]["sample_tags"][i], str(A[i])])+"\n")
#blame
......@@ -137,6 +136,7 @@ def add_arguments(parser):
"'highest' prints the top N samples with the highest single "
"contaminant per marker, and 'dirtiest' prints the top N samples "
"with the highest total amount of contaminants per marker")
add_input_output_args(parser)
add_allele_detection_args(parser)
filtergroup = parser.add_argument_group("filtering options")
filtergroup.add_argument('-n', '--num', metavar="N", type=pos_int_arg,
......@@ -145,17 +145,17 @@ def add_arguments(parser):
filtergroup.add_argument('-M', '--marker', metavar="MARKER",
help="work only on MARKER")
add_sequence_format_args(parser, "raw")
add_sample_files_args(parser)
#add_arguments