def data(args):
    """
    %prog data data.bin samples.ids STR.ids meta.tsv

    Make data.tsv based on meta.tsv.
    """
    p = OptionParser(data.__doc__)
    p.add_option("--notsv", default=False, action="store_true",
                 help="Do not write data.tsv")
    opts, args = p.parse_args(args)

    if len(args) != 4:
        sys.exit(not p.print_help())

    databin, sampleids, strids, metafile = args
    final_columns, percentiles = read_meta(metafile)
    df, m, samples, loci = read_binfile(databin, sampleids, strids)

    # Clean the data
    m %= 1000  # Get the larger of the two alleles
    m[m == 999] = -1  # Missing data

    final = set(final_columns)
    remove = []
    for i, locus in enumerate(loci):
        if locus not in final:
            remove.append(locus)
            continue

    pf = "STRs_{}_SEARCH".format(timestamp())
    filteredstrids = "{}.STR.ids".format(pf)
    fw = open(filteredstrids, "w")
    print("\n".join(final_columns), file=fw)
    fw.close()
    logging.debug("Dropped {} columns; Retained {} columns (`{}`)".\
                    format(len(remove), len(final_columns), filteredstrids))

    # Remove low-quality columns!
    df.drop(remove, inplace=True, axis=1)
    df.columns = final_columns

    filtered_bin = "{}.data.bin".format(pf)
    if need_update(databin, filtered_bin):
        m = df.as_matrix()
        m.tofile(filtered_bin)
        logging.debug("Filtered binary matrix written to `{}`".format(filtered_bin))

    # Write data output
    filtered_tsv = "{}.data.tsv".format(pf)
    if not opts.notsv and need_update(databin, filtered_tsv):
        df.to_csv(filtered_tsv, sep="\t", index_label="SampleKey")
%prog data data.bin samples.ids STR.ids meta.tsv

    Make data.tsv based on meta.tsv.