def filter_genes(data, min_counts=None, min_cells=None, max_counts=None, max_cells=None,<EOL>min_counts_u=None,  min_cells_u=None, max_counts_u=None, max_cells_u=None,<EOL>min_shared_counts=None, min_shared_cells=None, copy=False):
adata = data.copy() if copy else data<EOL>set_initial_size(adata)<EOL>layers = [layer for layer in ['<STR_LIT>', '<STR_LIT>'] if layer in adata.layers.keys()]<EOL>if min_shared_counts is not None or min_shared_cells is not None: layers.extend(['<STR_LIT>'])<EOL>for layer in layers:<EOL><INDENT>if layer is '<STR_LIT>':<EOL><INDENT>_min_counts, _min_cells, _max_counts, _max_cells = min_counts, min_cells, max_counts, max_cells<EOL><DEDENT>elif layer is '<STR_LIT>':<EOL><INDENT>_min_counts, _min_cells, _max_counts, _max_cells = min_counts_u, min_cells_u, max_counts_u, max_cells_u<EOL><DEDENT>else:  <EOL><INDENT>_min_counts, _min_cells, _max_counts, _max_cells = min_shared_counts, min_shared_cells, None, None<EOL><DEDENT>if layer in adata.layers.keys():<EOL><INDENT>X = adata.layers[layer]<EOL><DEDENT>else:  <EOL><INDENT>Xs, Xu = adata.layers['<STR_LIT>'], adata.layers['<STR_LIT>']<EOL>nonzeros = (Xs > <NUM_LIT:0>).multiply(Xu > <NUM_LIT:0>) if issparse(Xs) else (Xs > <NUM_LIT:0>) * (Xu > <NUM_LIT:0>)<EOL>X = nonzeros.multiply(Xs) + nonzeros.multiply(Xu) if issparse(nonzeros) else nonzeros * (Xs + Xu)<EOL><DEDENT>gene_subset = np.ones(adata.n_vars, dtype=bool)<EOL>if _min_counts is not None or _max_counts is not None:<EOL><INDENT>gene_subset, _ = filter(X, min_counts=_min_counts, max_counts=_max_counts)<EOL>adata._inplace_subset_var(gene_subset)<EOL><DEDENT>if _min_cells is not None or _max_cells is not None:<EOL><INDENT>gene_subset, _ = filter(X, min_cells=_min_cells, max_cells=_max_cells)<EOL>adata._inplace_subset_var(gene_subset)<EOL><DEDENT>s = np.sum(~gene_subset)<EOL>if s > <NUM_LIT:0>:<EOL><INDENT>logg.info('<STR_LIT>'.format(s), end='<STR_LIT:U+0020>')<EOL>if _min_cells is not None or _min_counts is not None:<EOL><INDENT>logg.info('<STR_LIT>', str(_min_cells) + '<STR_LIT>' + str(layer) + '<STR_LIT>' if _min_counts is None<EOL>else str(_min_counts) + '<STR_LIT>' + str(layer) + '<STR_LIT>', no_indent=True)<EOL><DEDENT>if max_cells is not None or max_counts is not None:<EOL><INDENT>logg.info('<STR_LIT>', str(_max_cells) + '<STR_LIT>' + str(layer) + '<STR_LIT>' if _max_counts is None<EOL>else str(_max_counts) + '<STR_LIT>' + str(layer) + '<STR_LIT>', no_indent=True)<EOL><DEDENT><DEDENT><DEDENT>return adata if copy else None<EOL>
Filter genes based on number of cells or counts.
    Keep genes that have at least `min_counts` counts or are expressed in at
    least `min_cells` cells or have at most `max_counts` counts or are expressed
    in at most `max_cells` cells.
    Only provide one of the optional parameters `min_counts`, `min_cells`,
    `max_counts`, `max_cells` per call.

    Parameters
    ----------
    data : :class:`~anndata.AnnData`, `np.ndarray`, `sp.spmatrix`
        The (annotated) data matrix of shape `n_obs` × `n_vars`. Rows correspond
        to cells and columns to genes.
    min_counts : `int`, optional (default: `None`)
        Minimum number of counts required for a gene to pass filtering.
    min_cells : `int`, optional (default: `None`)
        Minimum number of cells expressed required for a gene to pass filtering.
    max_counts : `int`, optional (default: `None`)
        Maximum number of counts required for a gene to pass filtering.
    max_cells : `int`, optional (default: `None`)
        Maximum number of cells expressed required for a gene to pass filtering.
    min_counts_u : `int`, optional (default: `None`)
        Minimum number of unspliced counts required for a gene to pass filtering.
    min_cells_u : `int`, optional (default: `None`)
        Minimum number of unspliced cells expressed required for a gene to pass filtering.
    max_counts_u : `int`, optional (default: `None`)
        Maximum number of unspliced counts required for a gene to pass filtering.
    max_cells_u : `int`, optional (default: `None`)
        Maximum number of unspliced cells expressed required for a gene to pass filtering.
    min_shared_counts: `int`, optional (default: `None`)
        Minimum number of counts (in cells expressed simultaneously in unspliced and spliced) required for a gene.
    min_shared_cells: `int`, optional (default: `None`)
        Minimum number of cells required for a gene to be expressed simultaneously in unspliced and spliced.
    copy : `bool`, optional (default: `False`)
        Determines whether a copy is returned.

    Returns
    -------
    Filters the object and adds `n_counts` to `adata.var`.