Load a numpy 1-dimensional structured array with data from the sample
    columns of a VCF file.

    Parameters
    ----------

    vcf_fn: string or list
        Name of the VCF file or list of file names.
    region: string
        Region to extract, e.g., 'chr1' or 'chr1:0-100000'.
    fields: list or array-like
        List of fields to extract from the VCF.
    exclude_fields: list or array-like
        Fields to exclude from extraction.
    dtypes: dict or dict-like
        Dictionary cotaining dtypes to use instead of the default inferred ones
    arities: dict or dict-like
        Override the amount of values to expect.
    fills: dict or dict-like
        Dictionary containing field:fillvalue mappings used to override the
        default fill in values in VCF fields.
    vcf_types: dict or dict-like
        Dictionary containing field:string mappings used to override any
        bogus type declarations in the VCF header.
    count: int
        Attempt to extract a specific number of records.
    progress: int
        If greater than 0, log parsing progress.
    logstream: file or file-like object
        Stream to use for logging progress.
    condition: array
        Boolean array defining which rows to load.
    slice_args: tuple or list
        Slice of the underlying iterator, e.g., (0, 1000, 10) takes every
        10th row from the first 1000.
    verbose: bool
        Log more messages.
    cache: bool
        If True, save the resulting numpy array to disk, and load from the
        cache if present rather than rebuilding from the VCF.
    cachedir: string
        Manually specify the directory to use to store cache files.
    skip_cached: bool
        If True and cache file is fresh, do not load and return None.
    compress_cache: bool, optional
        If True, compress the cache file.
    truncate: bool, optional
        If True (default) only include variants whose start position is within
        the given region. If False, use default tabix behaviour.

    Examples
    --------

    >>> from vcfnp import calldata, view2d
    >>> c = calldata('fixture/sample.vcf')
    >>> c
    array([ ((True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, False, [0, 1], 0, 0, b'0/1', [3, 3])),
           ((True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, False, [0, 1], 0, 0, b'0/1', [3, 3])),
           ((True, True, [0, 0], 1, 48, b'0|0', [51, 51]), (True, True, [1, 0], 8, 48, b'1|0', [51, 51]), (True, False, [1, 1], 5, 43, b'1/1', [0, 0])),
           ((True, True, [0, 0], 3, 49, b'0|0', [58, 50]), (True, True, [0, 1], 5, 3, b'0|1', [65, 3]), (True, False, [0, 0], 3, 41, b'0/0', [0, 0])),
           ((True, True, [1, 2], 6, 21, b'1|2', [23, 27]), (True, True, [2, 1], 0, 2, b'2|1', [18, 2]), (True, False, [2, 2], 4, 35, b'2/2', [0, 0])),
           ((True, True, [0, 0], 0, 54, b'0|0', [56, 60]), (True, True, [0, 0], 4, 48, b'0|0', [51, 51]), (True, False, [0, 0], 2, 61, b'0/0', [0, 0])),
           ((True, False, [0, 1], 4, 0, b'0/1', [0, 0]), (True, False, [0, 2], 2, 17, b'0/2', [0, 0]), (False, False, [-1, -1], 3, 40, b'./.', [0, 0])),
           ((True, False, [0, 0], 0, 0, b'0/0', [0, 0]), (True, True, [0, 0], 0, 0, b'0|0', [0, 0]), (False, False, [-1, -1], 0, 0, b'./.', [0, 0])),
           ((True, False, [0, -1], 0, 0, b'0', [0, 0]), (True, False, [0, 1], 0, 0, b'0/1', [0, 0]), (True, True, [0, 2], 0, 0, b'0|2', [0, 0]))],
          dtype=[('NA00001', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))]), ('NA00002', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))]), ('NA00003', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])])
    >>> c['NA00001']
    array([(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
           (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
           (True, True, [0, 0], 1, 48, b'0|0', [51, 51]),
           (True, True, [0, 0], 3, 49, b'0|0', [58, 50]),
           (True, True, [1, 2], 6, 21, b'1|2', [23, 27]),
           (True, True, [0, 0], 0, 54, b'0|0', [56, 60]),
           (True, False, [0, 1], 4, 0, b'0/1', [0, 0]),
           (True, False, [0, 0], 0, 0, b'0/0', [0, 0]),
           (True, False, [0, -1], 0, 0, b'0', [0, 0])],
          dtype=[('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])
    >>> c2d = view2d(c)
    >>> c2d
    array([[(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, False, [0, 1], 0, 0, b'0/1', [3, 3])],
           [(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, False, [0, 1], 0, 0, b'0/1', [3, 3])],
           [(True, True, [0, 0], 1, 48, b'0|0', [51, 51]),
            (True, True, [1, 0], 8, 48, b'1|0', [51, 51]),
            (True, False, [1, 1], 5, 43, b'1/1', [0, 0])],
           [(True, True, [0, 0], 3, 49, b'0|0', [58, 50]),
            (True, True, [0, 1], 5, 3, b'0|1', [65, 3]),
            (True, False, [0, 0], 3, 41, b'0/0', [0, 0])],
           [(True, True, [1, 2], 6, 21, b'1|2', [23, 27]),
            (True, True, [2, 1], 0, 2, b'2|1', [18, 2]),
            (True, False, [2, 2], 4, 35, b'2/2', [0, 0])],
           [(True, True, [0, 0], 0, 54, b'0|0', [56, 60]),
            (True, True, [0, 0], 4, 48, b'0|0', [51, 51]),
            (True, False, [0, 0], 2, 61, b'0/0', [0, 0])],
           [(True, False, [0, 1], 4, 0, b'0/1', [0, 0]),
            (True, False, [0, 2], 2, 17, b'0/2', [0, 0]),
            (False, False, [-1, -1], 3, 40, b'./.', [0, 0])],
           [(True, False, [0, 0], 0, 0, b'0/0', [0, 0]),
            (True, True, [0, 0], 0, 0, b'0|0', [0, 0]),
            (False, False, [-1, -1], 0, 0, b'./.', [0, 0])],
           [(True, False, [0, -1], 0, 0, b'0', [0, 0]),
            (True, False, [0, 1], 0, 0, b'0/1', [0, 0]),
            (True, True, [0, 2], 0, 0, b'0|2', [0, 0])]],
          dtype=[('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])
    >>> c2d['genotype']
    array([[[ 0,  0],
            [ 0,  0],
            [ 0,  1]],
           [[ 0,  0],
            [ 0,  0],
            [ 0,  1]],
           [[ 0,  0],
            [ 1,  0],
            [ 1,  1]],
           [[ 0,  0],
            [ 0,  1],
            [ 0,  0]],
           [[ 1,  2],
            [ 2,  1],
            [ 2,  2]],
           [[ 0,  0],
            [ 0,  0],
            [ 0,  0]],
           [[ 0,  1],
            [ 0,  2],
            [-1, -1]],
           [[ 0,  0],
            [ 0,  0],
            [-1, -1]],
           [[ 0, -1],
            [ 0,  1],
            [ 0,  2]]], dtype=int8)
    >>> c2d['genotype'][3, :]
    array([[0, 0],
           [0, 1],
           [0, 0]], dtype=int8)

def calldata(vcf_fn, region=None, samples=None, ploidy=2, fields=None,
             exclude_fields=None, dtypes=None, arities=None, fills=None,
             vcf_types=None, count=None, progress=0, logstream=None,
             condition=None, slice_args=None, verbose=True, cache=False,
             cachedir=None, skip_cached=False, compress_cache=False,
             truncate=True):
    """
    Load a numpy 1-dimensional structured array with data from the sample
    columns of a VCF file.

    Parameters
    ----------

    vcf_fn: string or list
        Name of the VCF file or list of file names.
    region: string
        Region to extract, e.g., 'chr1' or 'chr1:0-100000'.
    fields: list or array-like
        List of fields to extract from the VCF.
    exclude_fields: list or array-like
        Fields to exclude from extraction.
    dtypes: dict or dict-like
        Dictionary cotaining dtypes to use instead of the default inferred ones
    arities: dict or dict-like
        Override the amount of values to expect.
    fills: dict or dict-like
        Dictionary containing field:fillvalue mappings used to override the
        default fill in values in VCF fields.
    vcf_types: dict or dict-like
        Dictionary containing field:string mappings used to override any
        bogus type declarations in the VCF header.
    count: int
        Attempt to extract a specific number of records.
    progress: int
        If greater than 0, log parsing progress.
    logstream: file or file-like object
        Stream to use for logging progress.
    condition: array
        Boolean array defining which rows to load.
    slice_args: tuple or list
        Slice of the underlying iterator, e.g., (0, 1000, 10) takes every
        10th row from the first 1000.
    verbose: bool
        Log more messages.
    cache: bool
        If True, save the resulting numpy array to disk, and load from the
        cache if present rather than rebuilding from the VCF.
    cachedir: string
        Manually specify the directory to use to store cache files.
    skip_cached: bool
        If True and cache file is fresh, do not load and return None.
    compress_cache: bool, optional
        If True, compress the cache file.
    truncate: bool, optional
        If True (default) only include variants whose start position is within
        the given region. If False, use default tabix behaviour.

    Examples
    --------

    >>> from vcfnp import calldata, view2d
    >>> c = calldata('fixture/sample.vcf')
    >>> c
    array([ ((True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, False, [0, 1], 0, 0, b'0/1', [3, 3])),
           ((True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, True, [0, 0], 0, 0, b'0|0', [10, 10]), (True, False, [0, 1], 0, 0, b'0/1', [3, 3])),
           ((True, True, [0, 0], 1, 48, b'0|0', [51, 51]), (True, True, [1, 0], 8, 48, b'1|0', [51, 51]), (True, False, [1, 1], 5, 43, b'1/1', [0, 0])),
           ((True, True, [0, 0], 3, 49, b'0|0', [58, 50]), (True, True, [0, 1], 5, 3, b'0|1', [65, 3]), (True, False, [0, 0], 3, 41, b'0/0', [0, 0])),
           ((True, True, [1, 2], 6, 21, b'1|2', [23, 27]), (True, True, [2, 1], 0, 2, b'2|1', [18, 2]), (True, False, [2, 2], 4, 35, b'2/2', [0, 0])),
           ((True, True, [0, 0], 0, 54, b'0|0', [56, 60]), (True, True, [0, 0], 4, 48, b'0|0', [51, 51]), (True, False, [0, 0], 2, 61, b'0/0', [0, 0])),
           ((True, False, [0, 1], 4, 0, b'0/1', [0, 0]), (True, False, [0, 2], 2, 17, b'0/2', [0, 0]), (False, False, [-1, -1], 3, 40, b'./.', [0, 0])),
           ((True, False, [0, 0], 0, 0, b'0/0', [0, 0]), (True, True, [0, 0], 0, 0, b'0|0', [0, 0]), (False, False, [-1, -1], 0, 0, b'./.', [0, 0])),
           ((True, False, [0, -1], 0, 0, b'0', [0, 0]), (True, False, [0, 1], 0, 0, b'0/1', [0, 0]), (True, True, [0, 2], 0, 0, b'0|2', [0, 0]))],
          dtype=[('NA00001', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))]), ('NA00002', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))]), ('NA00003', [('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])])
    >>> c['NA00001']
    array([(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
           (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
           (True, True, [0, 0], 1, 48, b'0|0', [51, 51]),
           (True, True, [0, 0], 3, 49, b'0|0', [58, 50]),
           (True, True, [1, 2], 6, 21, b'1|2', [23, 27]),
           (True, True, [0, 0], 0, 54, b'0|0', [56, 60]),
           (True, False, [0, 1], 4, 0, b'0/1', [0, 0]),
           (True, False, [0, 0], 0, 0, b'0/0', [0, 0]),
           (True, False, [0, -1], 0, 0, b'0', [0, 0])],
          dtype=[('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])
    >>> c2d = view2d(c)
    >>> c2d
    array([[(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, False, [0, 1], 0, 0, b'0/1', [3, 3])],
           [(True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, True, [0, 0], 0, 0, b'0|0', [10, 10]),
            (True, False, [0, 1], 0, 0, b'0/1', [3, 3])],
           [(True, True, [0, 0], 1, 48, b'0|0', [51, 51]),
            (True, True, [1, 0], 8, 48, b'1|0', [51, 51]),
            (True, False, [1, 1], 5, 43, b'1/1', [0, 0])],
           [(True, True, [0, 0], 3, 49, b'0|0', [58, 50]),
            (True, True, [0, 1], 5, 3, b'0|1', [65, 3]),
            (True, False, [0, 0], 3, 41, b'0/0', [0, 0])],
           [(True, True, [1, 2], 6, 21, b'1|2', [23, 27]),
            (True, True, [2, 1], 0, 2, b'2|1', [18, 2]),
            (True, False, [2, 2], 4, 35, b'2/2', [0, 0])],
           [(True, True, [0, 0], 0, 54, b'0|0', [56, 60]),
            (True, True, [0, 0], 4, 48, b'0|0', [51, 51]),
            (True, False, [0, 0], 2, 61, b'0/0', [0, 0])],
           [(True, False, [0, 1], 4, 0, b'0/1', [0, 0]),
            (True, False, [0, 2], 2, 17, b'0/2', [0, 0]),
            (False, False, [-1, -1], 3, 40, b'./.', [0, 0])],
           [(True, False, [0, 0], 0, 0, b'0/0', [0, 0]),
            (True, True, [0, 0], 0, 0, b'0|0', [0, 0]),
            (False, False, [-1, -1], 0, 0, b'./.', [0, 0])],
           [(True, False, [0, -1], 0, 0, b'0', [0, 0]),
            (True, False, [0, 1], 0, 0, b'0/1', [0, 0]),
            (True, True, [0, 2], 0, 0, b'0|2', [0, 0])]],
          dtype=[('is_called', '?'), ('is_phased', '?'), ('genotype', 'i1', (2,)), ('DP', '<u2'), ('GQ', 'u1'), ('GT', 'S3'), ('HQ', '<i4', (2,))])
    >>> c2d['genotype']
    array([[[ 0,  0],
            [ 0,  0],
            [ 0,  1]],
           [[ 0,  0],
            [ 0,  0],
            [ 0,  1]],
           [[ 0,  0],
            [ 1,  0],
            [ 1,  1]],
           [[ 0,  0],
            [ 0,  1],
            [ 0,  0]],
           [[ 1,  2],
            [ 2,  1],
            [ 2,  2]],
           [[ 0,  0],
            [ 0,  0],
            [ 0,  0]],
           [[ 0,  1],
            [ 0,  2],
            [-1, -1]],
           [[ 0,  0],
            [ 0,  0],
            [-1, -1]],
           [[ 0, -1],
            [ 0,  1],
            [ 0,  2]]], dtype=int8)
    >>> c2d['genotype'][3, :]
    array([[0, 0],
           [0, 1],
           [0, 0]], dtype=int8)

    """  # flake8: noqa

    loader = _CalldataLoader(vcf_fn, region=region, samples=samples,
                             ploidy=ploidy, fields=fields,
                             exclude_fields=exclude_fields, dtypes=dtypes,
                             arities=arities, fills=fills, vcf_types=vcf_types,
                             count=count, progress=progress,
                             logstream=logstream, condition=condition,
                             slice_args=slice_args, verbose=verbose,
                             cache=cache, cachedir=cachedir,
                             skip_cached=skip_cached,
                             compress_cache=compress_cache,
                             truncate=truncate)
    arr = loader.load()
    return arr