code: def filter_genes(data, min_counts=None, min_cells=None, max_counts=None, max_cells=None,
                   min_counts_u=None,  min_cells_u=None, max_counts_u=None, max_cells_u=None,
                   min_shared_counts=None, min_shared_cells=None, copy=False):
      adata = data.copy() if copy else data
      set_initial_size(adata)
      layers = [layer for layer in ['spliced', 'unspliced'] if layer in adata.layers.keys()]
      if min_shared_counts is not None or min_shared_cells is not None: layers.extend(['shared'])
      for layer in layers:
          if layer is 'spliced':
              _min_counts, _min_cells, _max_counts, _max_cells = min_counts, min_cells, max_counts, max_cells
          elif layer is 'unspliced':
              _min_counts, _min_cells, _max_counts, _max_cells = min_counts_u, min_cells_u, max_counts_u, max_cells_u
          else:
              _min_counts, _min_cells, _max_counts, _max_cells = min_shared_counts, min_shared_cells, None, None
          if layer in adata.layers.keys():
              X = adata.layers[layer]
          else:
              Xs, Xu = adata.layers['spliced'], adata.layers['unspliced']
              nonzeros = (Xs > 0).multiply(Xu > 0) if issparse(Xs) else (Xs > 0) * (Xu > 0)
              X = nonzeros.multiply(Xs) + nonzeros.multiply(Xu) if issparse(nonzeros) else nonzeros * (Xs + Xu)
          gene_subset = np.ones(adata.n_vars, dtype=bool)
          if _min_counts is not None or _max_counts is not None:
              gene_subset, _ = filter(X, min_counts=_min_counts, max_counts=_max_counts)
              adata._inplace_subset_var(gene_subset)
          if _min_cells is not None or _max_cells is not None:
              gene_subset, _ = filter(X, min_cells=_min_cells, max_cells=_max_cells)
              adata._inplace_subset_var(gene_subset)
          s = np.sum(~gene_subset)
          if s > 0:
              logg.info('Filtered out {} genes that are detected'.format(s), end=' ')
              if _min_cells is not None or _min_counts is not None:
                  logg.info('in less than', str(_min_cells) + ' cells (' + str(layer) + ').' if _min_counts is None
                            else str(_min_counts) + ' counts (' + str(layer) + ').', no_indent=True)
              if max_cells is not None or max_counts is not None:
                  logg.info('in more than ', str(_max_cells) + ' cells(' + str(layer) + ').' if _max_counts is None
                            else str(_max_counts) + ' counts (' + str(layer) + ').', no_indent=True)
      return adata if copy else None