# HG changeset patch
# User azomics
# Date 1592862146 14400
# Node ID 3c0e4179be7a0301addb8c234008f60449c35601
# Parent  426650130311bb8516e2e9a830a3a6b7e059f1c2
"planemo upload for repository https://github.com/ImmPortDB/immport-galaxy-tools/tree/master/flowtools/merge_ds_flowtext commit 7858e5b085fc3c60c88fe87b2f343969d50d9b1e"
diff -r 426650130311 -r 3c0e4179be7a FCStxtMergeDownsample.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FCStxtMergeDownsample.py	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+
+######################################################################
+#                  Copyright (c) 2016 Northrop Grumman.
+#                          All rights reserved.
+######################################################################
+
+from __future__ import print_function
+from __future__ import division
+import sys
+import os
+import pandas as pd
+from argparse import ArgumentParser
+
+
+def is_number(s):
+    try:
+        float(s)
+        return True
+    except ValueError:
+        return False
+
+
+def is_integer(s):
+    try:
+        int(s)
+        return True
+    except ValueError:
+        return False
+
+
+def compare_headers(files):
+    headers = {}
+    for eachfile in files:
+        with open(eachfile, "r") as ef:
+            headers[eachfile] = ef.readline().strip().lower().split("\t")
+
+    hdgs_in_common = []
+    flag = {}
+
+    for ref_hdgs in headers[files[0]]:
+        flag[ref_hdgs] = 1
+
+        for ij in range(1, len(files)):
+            if ref_hdgs in headers[files[ij]]:
+                flag[ref_hdgs] += 1
+        if flag[ref_hdgs] == len(files):
+            hdgs_in_common.append(ref_hdgs)
+
+    if not hdgs_in_common:
+        sys.exit(9)
+    return(hdgs_in_common)
+
+
+def get_nb_lines(files):
+    tot_event = 0
+    for f in files:
+        df = pd.read_table(f)
+        tot_event += (len(df.index) - 1)
+    return(tot_event)
+
+
+def get_headers_index(list_headings, headings):
+    idxs = []
+    lhdgs = [x.lower() for x in headings]
+    for element in list_headings:
+        idxs.append(int(lhdgs.index(element)))
+    return(idxs)
+
+
+def merge_and_DS_txt(in_files, out_file, col_names, factor_ds):
+    """Concatenates together tab-separated files.
+    The output will have only the columns in common to all the files provided
+    as input, as determined by the headers.
+    All lines after the header line must contain only numbers.
+    Potential errors are logged to stderr. If the number of errors reaches 10,
+    the program stops.
+    If a downsampling factor is given, returns the indicated fraction of
+    random lines.
+    """
+
+    nb_errors = 0
+    max_error = 10
+
+    # get list of headers in common to all files
+    list_hdgs = compare_headers(in_files)
+    total_events = get_nb_lines(in_files)
+    total_final = total_events * ds_factor
+    nb_per_file = int(total_final / len(in_files))
+
+    with open(out_file, "w") as outf:
+        ff_order = []
+        # HEADERS:
+        with open(in_files[0], "r") as first_file:
+            headings_ff = first_file.readline().strip()
+            headings = headings_ff.split("\t")
+            # Get index of headers in common:
+            hdrs_idx = get_headers_index(list_hdgs, headings)
+
+            # If column to merge on were provided:
+            if col_names:
+                for ix in col_names:
+                    if ix not in hdrs_idx:
+                        nb_errors += 1
+                        sys.stderr.write(" ".join(["WARNING: column", str(ix), "in", in_files[0],
+                                                   "does not exist in all files or has a different header.\n"]))
+                        if nb_errors == max_error:
+                            exit_code = 4
+                            sys.stderr.write("Run aborted - too many errors.")
+                            os.remove(out_file)
+                hdrs_idx = col_names
+
+            # Print out to output file:
+            headings_to_write = []
+            for cti in range(0, len(headings)):
+                if cti in hdrs_idx:
+                    headings_to_write.append(headings[cti])
+                    ff_order.append(headings[cti])
+            outf.write("\t".join(headings_to_write) + "\n")
+
+        # DATA
+        for infile in in_files:
+            with open(infile, "r") as inf:
+                headings_inf = inf.readline().strip()
+                hdgs = headings_inf.split("\t")
+                # Get the index of columns to keep:
+                hdgs_idx = []
+                for ctc in ff_order:
+                    hdgs_idx.append(int(hdgs.index(ctc)))
+                if col_names:
+                    for iy in col_names:
+                        if iy not in hdgs_idx:
+                            nb_errors += 1
+                            sys.stderr.write(" ".join(["WARNING: column", str(iy), "in", infile,
+                                                       "does not exist in all files or has a different header.\n"]))
+                            if nb_errors == max_error:
+                                exit_code = 4
+                                sys.stderr.write("Run aborted - too many errors.")
+                                os.remove(out_file)
+                    hdgs_idx = col_names
+
+            df = pd.read_table(infile, usecols=hdrs_idx)
+            df_ds = df.sample(nb_per_file, replace=False)
+
+            for cols in df_ds.columns.values:
+                if df_ds[cols].count() != len(df_ds[cols]):
+                    sys.stderr.write(infile + "contains non-numeric data\n")
+
+                    with open(infile, "r") as checkfile:
+                        fl = checkfile.readline()
+                        count_lines = 1
+                        for checklines in checkfile:
+                            to_check = checklines.strip().split("\t")
+                            count_lines += 1
+                            for item in to_check:
+                                if not is_number(item):
+                                    sys.stderr.write(" ".join(["WARNING: line", str(count_lines),
+                                                               "in", infile, "contains non-numeric results\n"]))
+                    sys.exit(2)
+
+            df_ds = df_ds.ix[:, ff_order]
+            df_ds.to_csv(outf, sep="\t", header=False, index=False)
+
+    if nb_errors > 0:
+        exit_code = 3
+        if nb_errors == max_error:
+            exit_code = 4
+            sys.stderr.write("Run aborted - too many errors.")
+            os.remove(out_file)
+        sys.exit(exit_code)
+    return
+
+
+if __name__ == "__main__":
+    parser = ArgumentParser(
+             prog="FCStxtmerge",
+             description="Merge based on headers text-converted FCS files into one text file.")
+
+    parser.add_argument(
+            '-i',
+            dest="input_files",
+            required=True,
+            action='append',
+            help="File location for the text files.")
+
+    parser.add_argument(
+            '-o',
+            dest="output_file",
+            required=True,
+            help="Name of the output file.")
+
+    parser.add_argument(
+            '-c',
+            dest="columns",
+            help="Specify which column to keep in output file")
+
+    parser.add_argument(
+            '-d',
+            dest="downsampling_factor",
+            help="How much of each file to keep")
+
+    args = parser.parse_args()
+
+    # Get columns to merge on if any:
+    default_value_col = ["i.e.:1,2,5", "default", "Default"]
+    columns = []
+    if args.columns:
+        if args.columns not in default_value_col:
+            tmp_col = args.columns.split(",")
+            if len(tmp_col) == 1:
+                if not tmp_col[0].strip():
+                    columns = []
+                elif not is_integer(tmp_col[0].strip()):
+                    sys.exit(7)
+                else:
+                    columns.append(int(tmp_col[0].strip()) - 1)
+            else:
+                for c in range(0, len(tmp_col)):
+                    if not is_integer(tmp_col[c].strip()):
+                        sys.exit(6)
+                    else:
+                        columns.append(int(tmp_col[c].strip()) - 1)
+
+    # Get down sampling factor if any:
+    # Note: change '%' to 'X' because somehow that's what Galaxy passes?
+    default_value_ds = ["i.e.:0.1 or 10X", "default", "Default"]
+    ds_factor = 0.1
+    if args.downsampling_factor:
+        if args.downsampling_factor not in default_value_ds:
+            args.downsampling_factor = args.downsampling_factor.strip()
+            downsampling_factor = args.downsampling_factor.rstrip("X")
+            if is_number(downsampling_factor):
+                ds_factor = float(downsampling_factor)
+                if ds_factor > 1 and ds_factor <= 100:
+                    ds_factor = float(downsampling_factor) / 100
+                elif ds_factor > 100 or ds_factor <= 0:
+                    sys.stderr.write(str(ds_factor))
+                    sys.exit(8)
+            else:
+                sys.exit(8)
+
+    input_files = [f for f in args.input_files]
+    merge_and_DS_txt(input_files, args.output_file, columns, ds_factor)
diff -r 426650130311 -r 3c0e4179be7a FCStxtMergeDownsample.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FCStxtMergeDownsample.xml	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,183 @@
+
+  txt-converted FCS files into one text file based on headers
+  
+    pandas
+  
+  
+    
+    
+    
+    
+    
+    
+    
+  
+  
+  
+  
+    
+    
+    
+    
+  
+  
+    
+  
+  
+    
+      
+        
+          
+          
+          
+        
+      
+      
+      
+      
+    
+    
+      
+        
+          
+          
+          
+        
+      
+      
+      
+      
+    
+  
+  
+  
+  
+    10.1038/srep02327
+  
+
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/FCStxtMergeDownsample.py
--- a/merge_ds_flowtext/FCStxtMergeDownsample.py	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-#!/usr/bin/env python
-
-######################################################################
-#                  Copyright (c) 2016 Northrop Grumman.
-#                          All rights reserved.
-######################################################################
-
-from __future__ import print_function
-from __future__ import division
-import sys
-import os
-import pandas as pd
-from argparse import ArgumentParser
-
-
-def is_number(s):
-    try:
-        float(s)
-        return True
-    except ValueError:
-        return False
-
-
-def is_integer(s):
-    try:
-        int(s)
-        return True
-    except ValueError:
-        return False
-
-
-def compare_headers(files):
-    headers = {}
-    for eachfile in files:
-        with open(eachfile, "r") as ef:
-            headers[eachfile] = ef.readline().strip().lower().split("\t")
-
-    hdgs_in_common = []
-    flag = {}
-
-    for ref_hdgs in headers[files[0]]:
-        flag[ref_hdgs] = 1
-
-        for ij in range(1, len(files)):
-            if ref_hdgs in headers[files[ij]]:
-                flag[ref_hdgs] += 1
-        if flag[ref_hdgs] == len(files):
-            hdgs_in_common.append(ref_hdgs)
-
-    if not hdgs_in_common:
-        sys.exit(9)
-    return(hdgs_in_common)
-
-
-def get_headers_index(list_headings, headings):
-    idxs = []
-    lhdgs = [x.lower() for x in headings]
-    for element in list_headings:
-        idxs.append(int(lhdgs.index(element)))
-    return(idxs)
-
-
-def merge_and_DS_txt(in_files, out_file, col_names, factor_ds):
-    """Concatenates together tab-separated files.
-    The output will have only the columns in common to all the files provided
-    as input, as determined by the headers.
-    All lines after the header line must contain only numbers.
-    Potential errors are logged to stderr. If the number of errors reaches 10,
-    the program stops.
-    If a downsampling factor is given, returns the indicated fraction of
-    random lines.
-    """
-
-    nb_errors = 0
-    max_error = 10
-
-    # get list of headers in common to all files
-    list_hdgs = compare_headers(in_files)
-
-    with open(out_file, "w") as outf:
-        ff_order = []
-        # HEADERS:
-        with open(in_files[0], "r") as first_file:
-            headings_ff = first_file.readline().strip()
-            headings = headings_ff.split("\t")
-            # Get index of headers in common:
-            hdrs_idx = get_headers_index(list_hdgs, headings)
-
-            # If column to merge on were provided:
-            if col_names:
-                for ix in col_names:
-                    if ix not in hdrs_idx:
-                        nb_errors += 1
-                        sys.stderr.write(" ".join(["WARNING: column", str(ix), "in", in_files[0],
-                                                   "does not exist in all files or has a different header.\n"]))
-                hdrs_idx = col_names
-
-            # Print out to output file:
-            headings_to_write = []
-            for cti in range(0, len(headings)):
-                if cti in hdrs_idx:
-                    headings_to_write.append(headings[cti])
-                    ff_order.append(headings[cti])
-            outf.write("\t".join(headings_to_write) + "\n")
-
-        # DATA
-        for infile in in_files:
-            with open(infile, "r") as inf:
-                headings_inf = inf.readline().strip()
-                hdgs = headings_inf.split("\t")
-                # Get the index of columns to keep:
-                hdgs_idx = []
-                for ctc in ff_order:
-                    hdgs_idx.append(int(hdgs.index(ctc)))
-                if col_names:
-                    for iy in col_names:
-                        if iy not in hdgs_idx:
-                            nb_errors += 1
-                            sys.stderr.write(" ".join(["WARNING: column", str(iy), "in", infile,
-                                                       "does not exist in all files or has a different header.\n"]))
-                    hdgs_idx = col_names
-
-            df = pd.read_table(infile, usecols=hdrs_idx)
-            wc_file = len(df.index) - 1
-            df_ds = df.sample(int(wc_file * factor_ds), replace=False)
-
-            for cols in df_ds.columns.values:
-                if df_ds[cols].count() != len(df_ds[cols]):
-                    sys.stderr.write(infile + "contains non-numeric data\n")
-
-                    with open(infile, "r") as checkfile:
-                        fl = checkfile.readline()
-                        count_lines = 1
-                        for checklines in checkfile:
-                            to_check = checklines.strip().split("\t")
-                            count_lines += 1
-                            for item in to_check:
-                                if not is_number(item):
-                                    sys.stderr.write(" ".join(["WARNING: line", str(count_lines),
-                                                               "in", infile, "contains non-numeric results\n"]))
-                    sys.exit(2)
-
-            df_ds = df_ds.ix[:, ff_order]
-            df_ds.to_csv(outf, sep="\t", header=False, index=False)
-
-    if nb_errors > 0:
-        exit_code = 3
-        if nb_errors == max_error:
-            exit_code = 4
-            sys.stderr.write("Run aborted - too many errors.")
-            os.remove(out_file)
-        sys.exit(exit_code)
-    return
-
-
-if __name__ == "__main__":
-    parser = ArgumentParser(
-             prog="FCStxtmerge",
-             description="Merge based on headers text-converted FCS files into one text file.")
-
-    parser.add_argument(
-            '-i',
-            dest="input_files",
-            required=True,
-            action='append',
-            help="File location for the text files.")
-
-    parser.add_argument(
-            '-o',
-            dest="output_file",
-            required=True,
-            help="Name of the output file.")
-
-    parser.add_argument(
-            '-c',
-            dest="columns",
-            help="Specify which column to keep in output file")
-
-    parser.add_argument(
-            '-d',
-            dest="downsampling_factor",
-            help="How much of each file to keep")
-
-    args = parser.parse_args()
-
-    # Get columns to merge on if any:
-    default_value_col = ["i.e.:1,2,5", "default", "Default"]
-    columns = []
-    if args.columns:
-        if args.columns not in default_value_col:
-            tmp_col = args.columns.split(",")
-            if len(tmp_col) == 1:
-                if not tmp_col[0].strip():
-                    columns = []
-                elif not is_integer(tmp_col[0].strip()):
-                    sys.exit(7)
-                else:
-                    columns.append(int(tmp_col[0].strip()) - 1)
-            else:
-                for c in range(0, len(tmp_col)):
-                    if not is_integer(tmp_col[c].strip()):
-                        sys.exit(6)
-                    else:
-                        columns.append(int(tmp_col[c].strip()) - 1)
-
-    # Get down sampling factor if any:
-    # Note: change '%' to 'X' because somehow that's what Galaxy passes?
-    default_value_ds = ["i.e.:0.1 or 10X", "default", "Default"]
-    ds_factor = 1
-    if args.downsampling_factor:
-        if args.downsampling_factor not in default_value_ds:
-            args.downsampling_factor = args.downsampling_factor.strip()
-            downsampling_factor = args.downsampling_factor.rstrip("X")
-            if is_number(downsampling_factor):
-                ds_factor = float(downsampling_factor)
-                if ds_factor > 1:
-                    ds_factor = float(downsampling_factor) / 100
-                if ds_factor > 100:
-                    sys.exit(8)
-            else:
-                sys.exit(8)
-
-    input_files = [f for f in args.input_files]
-    merge_and_DS_txt(input_files, args.output_file, columns, ds_factor)
-    sys.exit(0)
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/FCStxtMergeDownsample.xml
--- a/merge_ds_flowtext/FCStxtMergeDownsample.xml	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-
-  txt-converted FCS files into one text file based on headers.
-  
-    numpy
-    pandas
-  
-  
-    
-    
-    
-    
-    
-    
-    
-  
-  
-  
-  
-    
-    
-    
-    
-  
-  
-    
-  
-  
-    
-      
-        
-          
-          
-          
-        
-      
-      
-      
-      
-    
-    
-      
-        
-          
-          
-          
-        
-      
-      
-      
-      
-    
-  
-  
-  
-  
-    10.1038/srep02327
-  
-
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/merge1.flowtext
--- a/merge_ds_flowtext/test-data/merge1.flowtext	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-CD4	CCR3	CD8	CCR7
-437	69	0	146
-551	129	169	292
-199	277	320	227
-83	138	335	194
-534	111	83	177
-499	0	0	224
-175	361	225	237
-216	310	270	294
-519	44	51	148
-550	200	0	127
-552	479	0	62
-525	121	0	138
-438	0	626	480
-139	227	293	259
-0	292	641	327
-30	147	483	386
-537	338	568	201
-156	228	734	408
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/merge2.flowtext
--- a/merge_ds_flowtext/test-data/merge2.flowtext	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-Forward Scatter	Side Scatter	FITC CD4
-340	115	509
-262	73	437
-894	1023	199
-316	76	50
-449	157	551
-388	97	534
-383	139	499
-394	144	83
-372	126	519
-788	1023	216
-1023	1023	289
-363	76	550
-668	1019	73
-420	211	552
-770	1023	175
-602	578	385
-418	105	561
-352	153	30
-383	190	156
-733	970	139
-451	120	537
-373	104	3
-358	185	0
-289	56	438
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input1.txt
--- a/merge_ds_flowtext/test-data/test1/input1.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-CD4	CCR3	CD8	CCR7
-551	129	169	292
-199	277	320	227
-437	69	0	146
-509	268	0	74
-50	0	60	129
-83	138	335	194
-499	0	0	224
-239	284	288	280
-534	111	83	177
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input2.txt
--- a/merge_ds_flowtext/test-data/test1/input2.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-CD4	CCR3	CD8	CCR7
-550	200	0	127
-519	44	51	148
-289	401	362	254
-175	361	225	237
-525	121	0	138
-385	286	222	131
-216	310	270	294
-552	479	0	62
-73	193	227	132
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input3.txt
--- a/merge_ds_flowtext/test-data/test1/input3.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-CD4	CCR3	CD8	CCR7
-438	0	626	480
-30	147	483	386
-156	228	734	408
-432	121	598	555
-537	338	568	201
-3	110	621	584
-561	0	610	562
-0	292	641	327
-139	227	293	259
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input1.txt
--- a/merge_ds_flowtext/test-data/test2/input1.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Forward Scatter	Side Scatter	FITC CD4	PE CCR3	PP CD8	APC CCR4
-449	157	551	129	169	292
-894	1023	199	277	320	227
-262	73	437	69	0	146
-340	115	509	268	0	74
-316	76	50	0	60	129
-394	144	83	138	335	194
-383	139	499	0	0	224
-800	1023	239	284	288	280
-388	97	534	111	83	177
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input2.txt
--- a/merge_ds_flowtext/test-data/test2/input2.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Forward Scatter	Side Scatter	FITC CD4	PE CXCR3	PP CD8	APC CCR5
-363	76	550	200	0	127
-372	126	519	44	51	148
-1023	1023	289	401	362	254
-770	1023	175	361	225	237
-384	111	525	121	0	138
-602	578	385	286	222	131
-788	1023	216	310	270	294
-420	211	552	479	0	62
-668	1019	73	193	227	132
diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input3.txt
--- a/merge_ds_flowtext/test-data/test2/input3.txt	Mon Feb 27 13:03:02 2017 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Forward Scatter	Side Scatter	FITC CD4	PE CD25	PP CD3	APC CD45RA
-289	56	438	0	626	480
-352	153	30	147	483	386
-383	190	156	228	734	408
-261	62	432	121	598	555
-451	120	537	338	568	201
-373	104	3	110	621	584
-418	105	561	0	610	562
-358	185	0	292	641	327
-733	970	139	227	293	259
diff -r 426650130311 -r 3c0e4179be7a test-data/merge1.flowtext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/merge1.flowtext	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,19 @@
+CD4	CCR3	CD8	CCR7
+432	121	598	555
+537	338	568	201
+438	0	626	480
+30	147	483	386
+561	0	610	562
+139	227	293	259
+385	286	222	131
+175	361	225	237
+525	121	0	138
+216	310	270	294
+289	401	362	254
+550	200	0	127
+83	138	335	194
+534	111	83	177
+437	69	0	146
+199	277	320	227
+509	268	0	74
+50	0	60	129
diff -r 426650130311 -r 3c0e4179be7a test-data/merge2.flowtext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/merge2.flowtext	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,1 @@
+Forward Scatter	Side Scatter	FITC CD4
diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input1.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test1/input1.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+CD4	CCR3	CD8	CCR7
+551	129	169	292
+199	277	320	227
+437	69	0	146
+509	268	0	74
+50	0	60	129
+83	138	335	194
+499	0	0	224
+239	284	288	280
+534	111	83	177
diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input2.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test1/input2.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+CD4	CCR3	CD8	CCR7
+550	200	0	127
+519	44	51	148
+289	401	362	254
+175	361	225	237
+525	121	0	138
+385	286	222	131
+216	310	270	294
+552	479	0	62
+73	193	227	132
diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input3.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test1/input3.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+CD4	CCR3	CD8	CCR7
+438	0	626	480
+30	147	483	386
+156	228	734	408
+432	121	598	555
+537	338	568	201
+3	110	621	584
+561	0	610	562
+0	292	641	327
+139	227	293	259
diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input1.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test2/input1.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+Forward Scatter	Side Scatter	FITC CD4	PE CCR3	PP CD8	APC CCR4
+449	157	551	129	169	292
+894	1023	199	277	320	227
+262	73	437	69	0	146
+340	115	509	268	0	74
+316	76	50	0	60	129
+394	144	83	138	335	194
+383	139	499	0	0	224
+800	1023	239	284	288	280
+388	97	534	111	83	177
diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input2.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test2/input2.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+Forward Scatter	Side Scatter	FITC CD4	PE CXCR3	PP CD8	APC CCR5
+363	76	550	200	0	127
+372	126	519	44	51	148
+1023	1023	289	401	362	254
+770	1023	175	361	225	237
+384	111	525	121	0	138
+602	578	385	286	222	131
+788	1023	216	310	270	294
+420	211	552	479	0	62
+668	1019	73	193	227	132
diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input3.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/test2/input3.txt	Mon Jun 22 17:42:26 2020 -0400
@@ -0,0 +1,10 @@
+Forward Scatter	Side Scatter	FITC CD4	PE CD25	PP CD3	APC CD45RA
+289	56	438	0	626	480
+352	153	30	147	483	386
+383	190	156	228	734	408
+261	62	432	121	598	555
+451	120	537	338	568	201
+373	104	3	110	621	584
+418	105	561	0	610	562
+358	185	0	292	641	327
+733	970	139	227	293	259