Repository: scverse/scanpy

Issue:
Recipes with plotting option throw import error
Some of the preprocessing recipes have a `plot` argument, but as far as I can tell, they'll only throw an error. `recipe_zheng17` and `recipe_seurat` have the lines:

```python
    if plot:
        from .. import plotting as pl  # should not import at the top of the file
        pl.filter_genes_dispersion(filter_result, log=True)
```

But `plotting` doesn't have the function `filter_genes_dispersion` exposed. Here's an example of the error using `scanpy` pulled from github, but the same issue occurs on the release on pypi:

```python
In [1]: import numpy as np
   ...: import pandas as pd
   ...: import scanpy.api as sc
   ...: 
   ...: sc.settings.verbosity = 3  # verbosity: errors (0), warnings (1), info (2), hints (3)
   ...: sc.settings.set_figure_params(dpi=80)  # low dpi (dots per inch) yields small inline figures
   ...: sc.logging.print_versions()
/Users/isaac/miniconda3/envs/scanpy/lib/python3.5/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
adatascanpy==1.0.4+91.ge9ae4ff anndata==0.6 numpy==1.14.3 scipy==1.1.0 pandas==0.22.0 scikit-learn==0.19.1 statsmodels==0.8.0 

In [2]: adata = sc.read("./data/pbmc3k_filtered_gene_bc_matrices/hg19/matrix.mtx").T
--> This might be very slow. Consider passing `cache=True`, which enables much faster reading from a cache file.
In [3]: sc.pp.recipe_zheng17(adata, plot=True)
running recipe zheng17
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-c19f237f1c6e> in <module>()
----> 1 sc.pp.recipe_zheng17(adata, plot=True)

~/github/scanpy/scanpy/preprocessing/recipes.py in recipe_zheng17(adata, n_top_genes, log, plot, copy)
    106     if plot:
    107         from .. import plotting as pl  # should not import at the top of the file
--> 108         pl.filter_genes_dispersion(filter_result, log=True)
    109     # actually filter the genes, the following is the inplace version of
    110     #     adata = adata[:, filter_result.gene_subset]

AttributeError: module 'scanpy.plotting' has no attribute 'filter_genes_dispersion'
```

It looks like there's a pretty easy fix here, so I'd be up for making a pull request if you'd like.


Discussion:
Oh, yes... I moved the reexports from `scanpy.plotting` to `scanpy.api.plotting`... one needs to 
`import filter_genes_dispersion from scanpy.plotting.preprocessing`, I guess... pull request is of course welcome... Could also fix this myself, if you prefer.

Resolving patch:
diff --git a/scanpy/preprocessing/recipes.py b/scanpy/preprocessing/recipes.py
--- a/scanpy/preprocessing/recipes.py
+++ b/scanpy/preprocessing/recipes.py
@@ -51,7 +51,7 @@ def recipe_seurat(adata, log=True, plot=False, copy=False):
         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)
     if plot:
         from .. import plotting as pl  # should not import at the top of the file
-        pl.filter_genes_dispersion(filter_result, log=not log)
+        pl.preprocessing.filter_genes_dispersion(filter_result, log=not log)
     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
     if log: pp.log1p(adata)
     pp.scale(adata, max_value=10)
@@ -105,7 +105,7 @@ def recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):
         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
     if plot:
         from .. import plotting as pl  # should not import at the top of the file
-        pl.filter_genes_dispersion(filter_result, log=True)
+        pl.preprocessing.filter_genes_dispersion(filter_result, log=True)
     # actually filter the genes, the following is the inplace version of
     #     adata = adata[:, filter_result.gene_subset]
     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes


Test patch:
diff --git a/scanpy/tests/preprocessing.py b/scanpy/tests/preprocessing.py
--- a/scanpy/tests/preprocessing.py
+++ b/scanpy/tests/preprocessing.py
@@ -29,3 +29,10 @@ def test_normalize_per_cell():
     sc.pp.normalize_per_cell(adata_sparse)
     assert adata.X.sum(axis=1).tolist() == adata_sparse.X.sum(
         axis=1).A1.tolist()
+
+def test_recipe_plotting():
+    sc.settings.autoshow = False
+    adata = AnnData(np.random.randint(0, 1000, (1000, 1000)))
+    # These shouldn't throw an error
+    sc.pp.recipe_seurat(adata.copy(), plot=True)
+    sc.pp.recipe_zheng17(adata.copy(), plot=True)