We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scanpy/preprocessing/recipes.py`
Content:
```
1 """Preprocessing recipes from the literature
2 """
3 
4 from . import simple as pp
5 from .. import logging as logg
6 
7 
8 def recipe_weinreb17(adata, log=True, mean_threshold=0.01, cv_threshold=2,
9                      n_pcs=50, svd_solver='randomized', random_state=0,
10                      copy=False):
11     """Normalization and filtering as of [Weinreb17]_.
12 
13     Expects non-logarithmized data. If using logarithmized data, pass `log=False`.
14 
15     Parameters
16     ----------
17     adata : :class:`~scanpy.api.AnnData`
18         Annotated data matrix.
19     copy : bool (default: False)
20         Return a copy if true.
21     """
22     from scipy.sparse import issparse
23     if issparse(adata.X):
24         raise ValueError('`recipe_weinreb16 does not support sparse matrices.')
25     if copy: adata = adata.copy()
26     if log: pp.log1p(adata)
27     adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,
28                                                          max_fraction=0.05,
29                                                          mult_with_mean=True)
30     gene_subset = pp.filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)
31     adata._inplace_subset_var(gene_subset)  # this modifies the object itself
32     X_pca = pp.pca(pp.zscore_deprecated(adata.X),
33                    n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)
34     # update adata
35     adata.obsm['X_pca'] = X_pca
36     return adata if copy else None
37 
38 
39 def recipe_seurat(adata, log=True, plot=False, copy=False):
40     """Normalization and filtering as of Seurat [Satija15]_.
41 
42     This uses a particular preprocessing.
43 
44     Expects non-logarithmized data. If using logarithmized data, pass `log=False`.
45     """
46     if copy: adata = adata.copy()
47     pp.filter_cells(adata, min_genes=200)
48     pp.filter_genes(adata, min_cells=3)
49     pp.normalize_per_cell(adata, counts_per_cell_after=1e4)
50     filter_result = pp.filter_genes_dispersion(
51         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)
52     if plot:
53         from .. import plotting as pl  # should not import at the top of the file
54         pl.filter_genes_dispersion(filter_result, log=not log)
55     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
56     if log: pp.log1p(adata)
57     pp.scale(adata, max_value=10)
58     return adata if copy else None
59 
60 
61 def recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):
62     """Normalization and filtering as of [Zheng17]_.
63 
64     Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x
65     Genomics.
66 
67     Expects non-logarithmized data. If using logarithmized data, pass `log=False`.
68 
69     The recipe runs the following steps::
70 
71         sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count
72         sc.pp.normalize_per_cell(                # normalize with total UMI count per cell
73              adata, key_n_counts='n_counts_all')
74         filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes
75             adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
76         adata = adata[:, filter_result.gene_subset]     # subset the genes
77         sc.pp.normalize_per_cell(adata)          # renormalize after filtering
78         if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)
79         sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean
80 
81 
82     Parameters
83     ----------
84     adata : :class:`~scanpy.api.AnnData`
85         Annotated data matrix.
86     n_top_genes : `int`, optional (default: 1000)
87         Number of genes to keep.
88     log : `bool`, optional (default: `True`)
89         Take logarithm.
90     plot : `bool`, optional (default: `True`)
91         Show a plot of the gene dispersion vs. mean relation.
92     copy : `bool`, optional (default: `False`)
93         Return a copy of `adata` instead of updating it.
94 
95     Returns
96     -------
97     Returns or updates `adata` depending on `copy`.
98     """
99     logg.info('running recipe zheng17', reset=True)
100     if copy: adata = adata.copy()
101     pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count
102     pp.normalize_per_cell(adata,  # normalize with total UMI count per cell
103                           key_n_counts='n_counts_all')
104     filter_result = pp.filter_genes_dispersion(
105         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
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]
111     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
112     pp.normalize_per_cell(adata)  # renormalize after filtering
113     if log: pp.log1p(adata)  # log transform: X = log(X + 1)
114     pp.scale(adata)
115     logg.info('    finished', time=True)
116     return adata if copy else None
117
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
         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 @@
         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

{"golden_diff": "diff --git a/scanpy/preprocessing/recipes.py b/scanpy/preprocessing/recipes.py\n--- a/scanpy/preprocessing/recipes.py\n+++ b/scanpy/preprocessing/recipes.py\n@@ -51,7 +51,7 @@\n         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n     if plot:\n         from .. import plotting as pl  # should not import at the top of the file\n-        pl.filter_genes_dispersion(filter_result, log=not log)\n+        pl.preprocessing.filter_genes_dispersion(filter_result, log=not log)\n     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n     if log: pp.log1p(adata)\n     pp.scale(adata, max_value=10)\n@@ -105,7 +105,7 @@\n         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n     if plot:\n         from .. import plotting as pl  # should not import at the top of the file\n-        pl.filter_genes_dispersion(filter_result, log=True)\n+        pl.preprocessing.filter_genes_dispersion(filter_result, log=True)\n     # actually filter the genes, the following is the inplace version of\n     #     adata = adata[:, filter_result.gene_subset]\n     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n", "issue": "Recipes with plotting option throw import error\nSome 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:\r\n\r\n```python\r\n    if plot:\r\n        from .. import plotting as pl  # should not import at the top of the file\r\n        pl.filter_genes_dispersion(filter_result, log=True)\r\n```\r\n\r\nBut `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:\r\n\r\n```python\r\nIn [1]: import numpy as np\r\n   ...: import pandas as pd\r\n   ...: import scanpy.api as sc\r\n   ...: \r\n   ...: sc.settings.verbosity = 3  # verbosity: errors (0), warnings (1), info (2), hints (3)\r\n   ...: sc.settings.set_figure_params(dpi=80)  # low dpi (dots per inch) yields small inline figures\r\n   ...: sc.logging.print_versions()\r\n/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`.\r\n  from ._conv import register_converters as _register_converters\r\nadatascanpy==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 \r\n\r\nIn [2]: adata = sc.read(\"./data/pbmc3k_filtered_gene_bc_matrices/hg19/matrix.mtx\").T\r\n--> This might be very slow. Consider passing `cache=True`, which enables much faster reading from a cache file.\r\nIn [3]: sc.pp.recipe_zheng17(adata, plot=True)\r\nrunning recipe zheng17\r\n---------------------------------------------------------------------------\r\nAttributeError                            Traceback (most recent call last)\r\n<ipython-input-3-c19f237f1c6e> in <module>()\r\n----> 1 sc.pp.recipe_zheng17(adata, plot=True)\r\n\r\n~/github/scanpy/scanpy/preprocessing/recipes.py in recipe_zheng17(adata, n_top_genes, log, plot, copy)\r\n    106     if plot:\r\n    107         from .. import plotting as pl  # should not import at the top of the file\r\n--> 108         pl.filter_genes_dispersion(filter_result, log=True)\r\n    109     # actually filter the genes, the following is the inplace version of\r\n    110     #     adata = adata[:, filter_result.gene_subset]\r\n\r\nAttributeError: module 'scanpy.plotting' has no attribute 'filter_genes_dispersion'\r\n```\r\n\r\nIt looks like there's a pretty easy fix here, so I'd be up for making a pull request if you'd like.\n", "before_files": [{"content": "\"\"\"Preprocessing recipes from the literature\n\"\"\"\n\nfrom . import simple as pp\nfrom .. import logging as logg\n\n\ndef recipe_weinreb17(adata, log=True, mean_threshold=0.01, cv_threshold=2,\n                     n_pcs=50, svd_solver='randomized', random_state=0,\n                     copy=False):\n    \"\"\"Normalization and filtering as of [Weinreb17]_.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    Parameters\n    ----------\n    adata : :class:`~scanpy.api.AnnData`\n        Annotated data matrix.\n    copy : bool (default: False)\n        Return a copy if true.\n    \"\"\"\n    from scipy.sparse import issparse\n    if issparse(adata.X):\n        raise ValueError('`recipe_weinreb16 does not support sparse matrices.')\n    if copy: adata = adata.copy()\n    if log: pp.log1p(adata)\n    adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,\n                                                         max_fraction=0.05,\n                                                         mult_with_mean=True)\n    gene_subset = pp.filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)\n    adata._inplace_subset_var(gene_subset)  # this modifies the object itself\n    X_pca = pp.pca(pp.zscore_deprecated(adata.X),\n                   n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)\n    # update adata\n    adata.obsm['X_pca'] = X_pca\n    return adata if copy else None\n\n\ndef recipe_seurat(adata, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of Seurat [Satija15]_.\n\n    This uses a particular preprocessing.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n    \"\"\"\n    if copy: adata = adata.copy()\n    pp.filter_cells(adata, min_genes=200)\n    pp.filter_genes(adata, min_cells=3)\n    pp.normalize_per_cell(adata, counts_per_cell_after=1e4)\n    filter_result = pp.filter_genes_dispersion(\n        adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n    if plot:\n        from .. import plotting as pl  # should not import at the top of the file\n        pl.filter_genes_dispersion(filter_result, log=not log)\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    if log: pp.log1p(adata)\n    pp.scale(adata, max_value=10)\n    return adata if copy else None\n\n\ndef recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of [Zheng17]_.\n\n    Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x\n    Genomics.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    The recipe runs the following steps::\n\n        sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n        sc.pp.normalize_per_cell(                # normalize with total UMI count per cell\n             adata, key_n_counts='n_counts_all')\n        filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes\n            adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n        adata = adata[:, filter_result.gene_subset]     # subset the genes\n        sc.pp.normalize_per_cell(adata)          # renormalize after filtering\n        if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)\n        sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean\n\n\n    Parameters\n    ----------\n    adata : :class:`~scanpy.api.AnnData`\n        Annotated data matrix.\n    n_top_genes : `int`, optional (default: 1000)\n        Number of genes to keep.\n    log : `bool`, optional (default: `True`)\n        Take logarithm.\n    plot : `bool`, optional (default: `True`)\n        Show a plot of the gene dispersion vs. mean relation.\n    copy : `bool`, optional (default: `False`)\n        Return a copy of `adata` instead of updating it.\n\n    Returns\n    -------\n    Returns or updates `adata` depending on `copy`.\n    \"\"\"\n    logg.info('running recipe zheng17', reset=True)\n    if copy: adata = adata.copy()\n    pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n    pp.normalize_per_cell(adata,  # normalize with total UMI count per cell\n                          key_n_counts='n_counts_all')\n    filter_result = pp.filter_genes_dispersion(\n        adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n    if plot:\n        from .. import plotting as pl  # should not import at the top of the file\n        pl.filter_genes_dispersion(filter_result, log=True)\n    # actually filter the genes, the following is the inplace version of\n    #     adata = adata[:, filter_result.gene_subset]\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    pp.normalize_per_cell(adata)  # renormalize after filtering\n    if log: pp.log1p(adata)  # log transform: X = log(X + 1)\n    pp.scale(adata)\n    logg.info('    finished', time=True)\n    return adata if copy else None\n", "path": "scanpy/preprocessing/recipes.py"}], "after_files": [{"content": "\"\"\"Preprocessing recipes from the literature\n\"\"\"\n\nfrom . import simple as pp\nfrom .. import logging as logg\n\n\ndef recipe_weinreb17(adata, log=True, mean_threshold=0.01, cv_threshold=2,\n                     n_pcs=50, svd_solver='randomized', random_state=0,\n                     copy=False):\n    \"\"\"Normalization and filtering as of [Weinreb17]_.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    Parameters\n    ----------\n    adata : :class:`~scanpy.api.AnnData`\n        Annotated data matrix.\n    copy : bool (default: False)\n        Return a copy if true.\n    \"\"\"\n    from scipy.sparse import issparse\n    if issparse(adata.X):\n        raise ValueError('`recipe_weinreb16 does not support sparse matrices.')\n    if copy: adata = adata.copy()\n    if log: pp.log1p(adata)\n    adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,\n                                                         max_fraction=0.05,\n                                                         mult_with_mean=True)\n    gene_subset = pp.filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)\n    adata._inplace_subset_var(gene_subset)  # this modifies the object itself\n    X_pca = pp.pca(pp.zscore_deprecated(adata.X),\n                   n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)\n    # update adata\n    adata.obsm['X_pca'] = X_pca\n    return adata if copy else None\n\n\ndef recipe_seurat(adata, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of Seurat [Satija15]_.\n\n    This uses a particular preprocessing.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n    \"\"\"\n    if copy: adata = adata.copy()\n    pp.filter_cells(adata, min_genes=200)\n    pp.filter_genes(adata, min_cells=3)\n    pp.normalize_per_cell(adata, counts_per_cell_after=1e4)\n    filter_result = pp.filter_genes_dispersion(\n        adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n    if plot:\n        from .. import plotting as pl  # should not import at the top of the file\n        pl.preprocessing.filter_genes_dispersion(filter_result, log=not log)\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    if log: pp.log1p(adata)\n    pp.scale(adata, max_value=10)\n    return adata if copy else None\n\n\ndef recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of [Zheng17]_.\n\n    Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x\n    Genomics.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    The recipe runs the following steps::\n\n        sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n        sc.pp.normalize_per_cell(                # normalize with total UMI count per cell\n             adata, key_n_counts='n_counts_all')\n        filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes\n            adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n        adata = adata[:, filter_result.gene_subset]     # subset the genes\n        sc.pp.normalize_per_cell(adata)          # renormalize after filtering\n        if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)\n        sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean\n\n\n    Parameters\n    ----------\n    adata : :class:`~scanpy.api.AnnData`\n        Annotated data matrix.\n    n_top_genes : `int`, optional (default: 1000)\n        Number of genes to keep.\n    log : `bool`, optional (default: `True`)\n        Take logarithm.\n    plot : `bool`, optional (default: `True`)\n        Show a plot of the gene dispersion vs. mean relation.\n    copy : `bool`, optional (default: `False`)\n        Return a copy of `adata` instead of updating it.\n\n    Returns\n    -------\n    Returns or updates `adata` depending on `copy`.\n    \"\"\"\n    logg.info('running recipe zheng17', reset=True)\n    if copy: adata = adata.copy()\n    pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n    pp.normalize_per_cell(adata,  # normalize with total UMI count per cell\n                          key_n_counts='n_counts_all')\n    filter_result = pp.filter_genes_dispersion(\n        adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n    if plot:\n        from .. import plotting as pl  # should not import at the top of the file\n        pl.preprocessing.filter_genes_dispersion(filter_result, log=True)\n    # actually filter the genes, the following is the inplace version of\n    #     adata = adata[:, filter_result.gene_subset]\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    pp.normalize_per_cell(adata)  # renormalize after filtering\n    if log: pp.log1p(adata)  # log transform: X = log(X + 1)\n    pp.scale(adata)\n    logg.info('    finished', time=True)\n    return adata if copy else None\n", "path": "scanpy/preprocessing/recipes.py"}]}