We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
sc.pp.neighbors n_pcs doesn't subset if use_rep isn't X_pca
Smaller reproducible example below: https://github.com/theislab/scanpy/issues/1846#issuecomment-863823148 –@ivirshup

--------------------------

- [x] I have checked that this issue has not already been reported.
- [ ] I have confirmed this bug exists on the latest version of scanpy.
- [ ] (optional) I have confirmed this bug exists on the master branch of scanpy.

---

Hi, 

not sure whether this is the right place to post this but i'm having a slight issue after running harmony from scanpy. It's producing very different results and i'm not sure why. It didn't used to be a problem when i was using scanpy 1.6x

### Minimal code sample (that we can copy&paste without having any data)

without running harmony:
```python
sc.tl.pca(adata, svd_solver='arpack')
sc.pp.neighbors(adata, n_pcs = 20)
sc.tl.umap(adata)
sc.pl.umap(adata, color = 'sample')
```
![image](https://user-images.githubusercontent.com/26215587/118844728-1aa3ad80-b8c3-11eb-82d8-57f3b6346c44.png)

with harmony
```python
adata1 = adata.copy()
sc.external.pp.harmony_integrate(adata1, key = 'sample')
sc.pp.neighbors(adata1, n_pcs = 20, use_rep = 'X_pca_harmony')
sc.tl.umap(adata1)
sc.pl.umap(adata1, color = 'sample')
```
![image](https://user-images.githubusercontent.com/26215587/118845227-7ec67180-b8c3-11eb-9bce-a877ef26b47a.png)

If i don't use harmony and just ran with `n_pcs = 50`, the result is similar.
```python
adatax = adata.copy()
sc.pp.neighbors(adatax, n_pcs = 50)
sc.tl.umap(adatax, min_dist = .3)
sc.pl.umap(adatax, color = 'sample')
```
![image](https://user-images.githubusercontent.com/26215587/118845811-01e7c780-b8c4-11eb-8ca9-3ea639d97684.png)

What i don't get is, why does the following work then?
```python
# my current workaround
adata2 = adata.copy()
sc.external.pp.harmony_integrate(adata2, key = 'sample', adjusted_basis='X_pca')
sc.pp.neighbors(adata2, n_pcs = 20)
sc.tl.umap(adata2)
sc.pl.umap(adata2, color = 'sample')
```
![image](https://user-images.githubusercontent.com/26215587/118843486-04492200-b8c2-11eb-8e2b-6aaf59564721.png)


#### Versions

<details>

-----
anndata     0.7.5
scanpy      1.7.1
sinfo       0.3.1
-----
Bio                 1.78
PIL                 8.2.0
adjustText          NA
anndata             0.7.5
annoy               NA
backcall            0.2.0
brotli              NA
cachecontrol        0.12.6
cairo               1.19.1
certifi             2020.06.20
cffi                1.14.5
changeo             1.0.2
chardet             4.0.0
cloudpickle         1.6.0
cycler              0.10.0
cython_runtime      NA
dandelion           0.1.2
dask                2021.03.0
dateutil            2.8.1
decorator           5.0.6
descartes           NA
distance            NA
get_version         2.1
google              NA
h5py                2.10.0
harmonypy           NA
hdmedians           NA
idna                2.10
igraph              0.8.3
ipykernel           5.3.4
ipython_genutils    0.2.0
ipywidgets          7.6.3
jedi                0.17.0
joblib              1.0.1
kiwisolver          1.3.1
legacy_api_wrap     1.2
leidenalg           0.8.3
llvmlite            0.34.0
matplotlib          3.3.4
mizani              0.7.2
mpl_toolkits        NA
msgpack             1.0.2
natsort             7.1.1
networkx            2.5
numba               0.51.2
numexpr             2.7.1
numpy               1.20.2
packaging           20.9
palettable          3.3.0
pandas              1.2.4
parso               0.8.2
patsy               0.5.1
pexpect             4.8.0
pickleshare         0.7.5
pkg_resources       NA
plotnine            0.7.1
polyleven           NA
presto              0.6.2
prompt_toolkit      3.0.17
ptyprocess          0.7.0
pycparser           2.20
pygments            2.8.1
pynndescent         0.5.2
pyparsing           2.4.7
pytoml              NA
pytz                2021.1
pywt                1.1.1
requests            2.25.1
scanpy              1.7.1
scipy               1.6.3
scrublet            NA
seaborn             0.11.1
setuptools_scm      NA
sinfo               0.3.1
six                 1.15.0
skbio               0.5.6
skimage             0.18.1
sklearn             0.23.2
socks               1.7.1
sparse              0.11.2
sphinxcontrib       NA
statsmodels         0.12.1
storemagic          NA
tables              3.6.1
texttable           1.6.3
tlz                 0.11.1
toolz               0.11.1
tornado             6.1
tqdm                4.59.0
traitlets           5.0.5
typing_extensions   NA
umap                0.5.1
urllib3             1.26.4
wcwidth             0.2.5
yaml                5.4.1
zmq                 20.0.0
-----
IPython             7.22.0
jupyter_client      6.1.12
jupyter_core        4.7.1
notebook            6.3.0
-----
Python 3.8.8 (default, Feb 24 2021, 21:46:12) [GCC 7.3.0]
Linux-4.15.0-142-generic-x86_64-with-glibc2.10
64 logical CPU cores, x86_64
-----
Session information updated at 2021-05-19 16:44

</details>


--- 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/tools/_utils.py`
Content:
```
1 from typing import Optional
2 
3 import numpy as np
4 from .. import logging as logg
5 from ._pca import pca
6 from .. import settings
7 from .._utils import _choose_graph
8 
9 doc_use_rep = """\
10 use_rep
11     Use the indicated representation. `'X'` or any key for `.obsm` is valid.
12     If `None`, the representation is chosen automatically:
13     For `.n_vars` < 50, `.X` is used, otherwise 'X_pca' is used.
14     If 'X_pca' is not present, it’s computed with default parameters.\
15 """
16 
17 doc_n_pcs = """\
18 n_pcs
19     Use this many PCs. If `n_pcs==0` use `.X` if `use_rep is None`.\
20 """
21 
22 
23 def _choose_representation(adata, use_rep=None, n_pcs=None, silent=False):
24     verbosity = settings.verbosity
25     if silent and settings.verbosity > 1:
26         settings.verbosity = 1
27     if use_rep is None and n_pcs == 0:  # backwards compat for specifying `.X`
28         use_rep = 'X'
29     if use_rep is None:
30         if adata.n_vars > settings.N_PCS:
31             if 'X_pca' in adata.obsm.keys():
32                 if n_pcs is not None and n_pcs > adata.obsm['X_pca'].shape[1]:
33                     raise ValueError(
34                         '`X_pca` does not have enough PCs. Rerun `sc.pp.pca` with adjusted `n_comps`.'
35                     )
36                 X = adata.obsm['X_pca'][:, :n_pcs]
37                 logg.info(f'    using \'X_pca\' with n_pcs = {X.shape[1]}')
38             else:
39                 logg.warning(
40                     f'You’re trying to run this on {adata.n_vars} dimensions of `.X`, '
41                     'if you really want this, set `use_rep=\'X\'`.\n         '
42                     'Falling back to preprocessing with `sc.pp.pca` and default params.'
43                 )
44                 X = pca(adata.X)
45                 adata.obsm['X_pca'] = X[:, :n_pcs]
46         else:
47             logg.info('    using data matrix X directly')
48             X = adata.X
49     else:
50         if use_rep in adata.obsm.keys():
51             X = adata.obsm[use_rep]
52             if use_rep == 'X_pca' and n_pcs is not None:
53                 X = adata.obsm[use_rep][:, :n_pcs]
54         elif use_rep == 'X':
55             X = adata.X
56         else:
57             raise ValueError(
58                 'Did not find {} in `.obsm.keys()`. '
59                 'You need to compute it first.'.format(use_rep)
60             )
61     settings.verbosity = verbosity  # resetting verbosity
62     return X
63 
64 
65 def preprocess_with_pca(adata, n_pcs: Optional[int] = None, random_state=0):
66     """
67     Parameters
68     ----------
69     n_pcs
70         If `n_pcs=0`, do not preprocess with PCA.
71         If `None` and there is a PCA version of the data, use this.
72         If an integer, compute the PCA.
73     """
74     if n_pcs == 0:
75         logg.info('    using data matrix X directly (no PCA)')
76         return adata.X
77     elif n_pcs is None and 'X_pca' in adata.obsm_keys():
78         logg.info(f'    using \'X_pca\' with n_pcs = {adata.obsm["X_pca"].shape[1]}')
79         return adata.obsm['X_pca']
80     elif 'X_pca' in adata.obsm_keys() and adata.obsm['X_pca'].shape[1] >= n_pcs:
81         logg.info(f'    using \'X_pca\' with n_pcs = {n_pcs}')
82         return adata.obsm['X_pca'][:, :n_pcs]
83     else:
84         n_pcs = settings.N_PCS if n_pcs is None else n_pcs
85         if adata.X.shape[1] > n_pcs:
86             logg.info(f'    computing \'X_pca\' with n_pcs = {n_pcs}')
87             logg.hint('avoid this by setting n_pcs = 0')
88             X = pca(adata.X, n_comps=n_pcs, random_state=random_state)
89             adata.obsm['X_pca'] = X
90             return X
91         else:
92             logg.info('    using data matrix X directly (no PCA)')
93             return adata.X
94 
95 
96 def get_init_pos_from_paga(
97     adata, adjacency=None, random_state=0, neighbors_key=None, obsp=None
98 ):
99     np.random.seed(random_state)
100     if adjacency is None:
101         adjacency = _choose_graph(adata, obsp, neighbors_key)
102     if 'paga' in adata.uns and 'pos' in adata.uns['paga']:
103         groups = adata.obs[adata.uns['paga']['groups']]
104         pos = adata.uns['paga']['pos']
105         connectivities_coarse = adata.uns['paga']['connectivities']
106         init_pos = np.ones((adjacency.shape[0], 2))
107         for i, group_pos in enumerate(pos):
108             subset = (groups == groups.cat.categories[i]).values
109             neighbors = connectivities_coarse[i].nonzero()
110             if len(neighbors[1]) > 0:
111                 connectivities = connectivities_coarse[i][neighbors]
112                 nearest_neighbor = neighbors[1][np.argmax(connectivities)]
113                 noise = np.random.random((len(subset[subset]), 2))
114                 dist = pos[i] - pos[nearest_neighbor]
115                 noise = noise * dist
116                 init_pos[subset] = group_pos - 0.5 * dist + noise
117             else:
118                 init_pos[subset] = group_pos
119     else:
120         raise ValueError(
121             'Plot PAGA first, so that adata.uns[\'paga\']' 'with key \'pos\'.'
122         )
123     return init_pos
124
```
--- 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/tools/_utils.py b/scanpy/tools/_utils.py
--- a/scanpy/tools/_utils.py
+++ b/scanpy/tools/_utils.py
@@ -47,10 +47,16 @@
             logg.info('    using data matrix X directly')
             X = adata.X
     else:
-        if use_rep in adata.obsm.keys():
+        if use_rep in adata.obsm.keys() and n_pcs is not None:
+            if n_pcs > adata.obsm[use_rep].shape[1]:
+                raise ValueError(
+                    f'{use_rep} does not have enough Dimensions. Provide a '
+                    'Representation with equal or more dimensions than'
+                    '`n_pcs` or lower `n_pcs` '
+                )
+            X = adata.obsm[use_rep][:, :n_pcs]
+        elif use_rep in adata.obsm.keys() and n_pcs is None:
             X = adata.obsm[use_rep]
-            if use_rep == 'X_pca' and n_pcs is not None:
-                X = adata.obsm[use_rep][:, :n_pcs]
         elif use_rep == 'X':
             X = adata.X
         else:

{"golden_diff": "diff --git a/scanpy/tools/_utils.py b/scanpy/tools/_utils.py\n--- a/scanpy/tools/_utils.py\n+++ b/scanpy/tools/_utils.py\n@@ -47,10 +47,16 @@\n             logg.info('    using data matrix X directly')\n             X = adata.X\n     else:\n-        if use_rep in adata.obsm.keys():\n+        if use_rep in adata.obsm.keys() and n_pcs is not None:\n+            if n_pcs > adata.obsm[use_rep].shape[1]:\n+                raise ValueError(\n+                    f'{use_rep} does not have enough Dimensions. Provide a '\n+                    'Representation with equal or more dimensions than'\n+                    '`n_pcs` or lower `n_pcs` '\n+                )\n+            X = adata.obsm[use_rep][:, :n_pcs]\n+        elif use_rep in adata.obsm.keys() and n_pcs is None:\n             X = adata.obsm[use_rep]\n-            if use_rep == 'X_pca' and n_pcs is not None:\n-                X = adata.obsm[use_rep][:, :n_pcs]\n         elif use_rep == 'X':\n             X = adata.X\n         else:\n", "issue": "sc.pp.neighbors n_pcs doesn't subset if use_rep isn't X_pca\nSmaller reproducible example below: https://github.com/theislab/scanpy/issues/1846#issuecomment-863823148 \u2013@ivirshup\r\n\r\n--------------------------\r\n\r\n- [x] I have checked that this issue has not already been reported.\r\n- [ ] I have confirmed this bug exists on the latest version of scanpy.\r\n- [ ] (optional) I have confirmed this bug exists on the master branch of scanpy.\r\n\r\n---\r\n\r\nHi, \r\n\r\nnot sure whether this is the right place to post this but i'm having a slight issue after running harmony from scanpy. It's producing very different results and i'm not sure why. It didn't used to be a problem when i was using scanpy 1.6x\r\n\r\n### Minimal code sample (that we can copy&paste without having any data)\r\n\r\nwithout running harmony:\r\n```python\r\nsc.tl.pca(adata, svd_solver='arpack')\r\nsc.pp.neighbors(adata, n_pcs = 20)\r\nsc.tl.umap(adata)\r\nsc.pl.umap(adata, color = 'sample')\r\n```\r\n![image](https://user-images.githubusercontent.com/26215587/118844728-1aa3ad80-b8c3-11eb-82d8-57f3b6346c44.png)\r\n\r\nwith harmony\r\n```python\r\nadata1 = adata.copy()\r\nsc.external.pp.harmony_integrate(adata1, key = 'sample')\r\nsc.pp.neighbors(adata1, n_pcs = 20, use_rep = 'X_pca_harmony')\r\nsc.tl.umap(adata1)\r\nsc.pl.umap(adata1, color = 'sample')\r\n```\r\n![image](https://user-images.githubusercontent.com/26215587/118845227-7ec67180-b8c3-11eb-9bce-a877ef26b47a.png)\r\n\r\nIf i don't use harmony and just ran with `n_pcs = 50`, the result is similar.\r\n```python\r\nadatax = adata.copy()\r\nsc.pp.neighbors(adatax, n_pcs = 50)\r\nsc.tl.umap(adatax, min_dist = .3)\r\nsc.pl.umap(adatax, color = 'sample')\r\n```\r\n![image](https://user-images.githubusercontent.com/26215587/118845811-01e7c780-b8c4-11eb-8ca9-3ea639d97684.png)\r\n\r\nWhat i don't get is, why does the following work then?\r\n```python\r\n# my current workaround\r\nadata2 = adata.copy()\r\nsc.external.pp.harmony_integrate(adata2, key = 'sample', adjusted_basis='X_pca')\r\nsc.pp.neighbors(adata2, n_pcs = 20)\r\nsc.tl.umap(adata2)\r\nsc.pl.umap(adata2, color = 'sample')\r\n```\r\n![image](https://user-images.githubusercontent.com/26215587/118843486-04492200-b8c2-11eb-8e2b-6aaf59564721.png)\r\n\r\n\r\n#### Versions\r\n\r\n<details>\r\n\r\n-----\r\nanndata     0.7.5\r\nscanpy      1.7.1\r\nsinfo       0.3.1\r\n-----\r\nBio                 1.78\r\nPIL                 8.2.0\r\nadjustText          NA\r\nanndata             0.7.5\r\nannoy               NA\r\nbackcall            0.2.0\r\nbrotli              NA\r\ncachecontrol        0.12.6\r\ncairo               1.19.1\r\ncertifi             2020.06.20\r\ncffi                1.14.5\r\nchangeo             1.0.2\r\nchardet             4.0.0\r\ncloudpickle         1.6.0\r\ncycler              0.10.0\r\ncython_runtime      NA\r\ndandelion           0.1.2\r\ndask                2021.03.0\r\ndateutil            2.8.1\r\ndecorator           5.0.6\r\ndescartes           NA\r\ndistance            NA\r\nget_version         2.1\r\ngoogle              NA\r\nh5py                2.10.0\r\nharmonypy           NA\r\nhdmedians           NA\r\nidna                2.10\r\nigraph              0.8.3\r\nipykernel           5.3.4\r\nipython_genutils    0.2.0\r\nipywidgets          7.6.3\r\njedi                0.17.0\r\njoblib              1.0.1\r\nkiwisolver          1.3.1\r\nlegacy_api_wrap     1.2\r\nleidenalg           0.8.3\r\nllvmlite            0.34.0\r\nmatplotlib          3.3.4\r\nmizani              0.7.2\r\nmpl_toolkits        NA\r\nmsgpack             1.0.2\r\nnatsort             7.1.1\r\nnetworkx            2.5\r\nnumba               0.51.2\r\nnumexpr             2.7.1\r\nnumpy               1.20.2\r\npackaging           20.9\r\npalettable          3.3.0\r\npandas              1.2.4\r\nparso               0.8.2\r\npatsy               0.5.1\r\npexpect             4.8.0\r\npickleshare         0.7.5\r\npkg_resources       NA\r\nplotnine            0.7.1\r\npolyleven           NA\r\npresto              0.6.2\r\nprompt_toolkit      3.0.17\r\nptyprocess          0.7.0\r\npycparser           2.20\r\npygments            2.8.1\r\npynndescent         0.5.2\r\npyparsing           2.4.7\r\npytoml              NA\r\npytz                2021.1\r\npywt                1.1.1\r\nrequests            2.25.1\r\nscanpy              1.7.1\r\nscipy               1.6.3\r\nscrublet            NA\r\nseaborn             0.11.1\r\nsetuptools_scm      NA\r\nsinfo               0.3.1\r\nsix                 1.15.0\r\nskbio               0.5.6\r\nskimage             0.18.1\r\nsklearn             0.23.2\r\nsocks               1.7.1\r\nsparse              0.11.2\r\nsphinxcontrib       NA\r\nstatsmodels         0.12.1\r\nstoremagic          NA\r\ntables              3.6.1\r\ntexttable           1.6.3\r\ntlz                 0.11.1\r\ntoolz               0.11.1\r\ntornado             6.1\r\ntqdm                4.59.0\r\ntraitlets           5.0.5\r\ntyping_extensions   NA\r\numap                0.5.1\r\nurllib3             1.26.4\r\nwcwidth             0.2.5\r\nyaml                5.4.1\r\nzmq                 20.0.0\r\n-----\r\nIPython             7.22.0\r\njupyter_client      6.1.12\r\njupyter_core        4.7.1\r\nnotebook            6.3.0\r\n-----\r\nPython 3.8.8 (default, Feb 24 2021, 21:46:12) [GCC 7.3.0]\r\nLinux-4.15.0-142-generic-x86_64-with-glibc2.10\r\n64 logical CPU cores, x86_64\r\n-----\r\nSession information updated at 2021-05-19 16:44\r\n\r\n</details>\r\n\n", "before_files": [{"content": "from typing import Optional\n\nimport numpy as np\nfrom .. import logging as logg\nfrom ._pca import pca\nfrom .. import settings\nfrom .._utils import _choose_graph\n\ndoc_use_rep = \"\"\"\\\nuse_rep\n    Use the indicated representation. `'X'` or any key for `.obsm` is valid.\n    If `None`, the representation is chosen automatically:\n    For `.n_vars` < 50, `.X` is used, otherwise 'X_pca' is used.\n    If 'X_pca' is not present, it\u2019s computed with default parameters.\\\n\"\"\"\n\ndoc_n_pcs = \"\"\"\\\nn_pcs\n    Use this many PCs. If `n_pcs==0` use `.X` if `use_rep is None`.\\\n\"\"\"\n\n\ndef _choose_representation(adata, use_rep=None, n_pcs=None, silent=False):\n    verbosity = settings.verbosity\n    if silent and settings.verbosity > 1:\n        settings.verbosity = 1\n    if use_rep is None and n_pcs == 0:  # backwards compat for specifying `.X`\n        use_rep = 'X'\n    if use_rep is None:\n        if adata.n_vars > settings.N_PCS:\n            if 'X_pca' in adata.obsm.keys():\n                if n_pcs is not None and n_pcs > adata.obsm['X_pca'].shape[1]:\n                    raise ValueError(\n                        '`X_pca` does not have enough PCs. Rerun `sc.pp.pca` with adjusted `n_comps`.'\n                    )\n                X = adata.obsm['X_pca'][:, :n_pcs]\n                logg.info(f'    using \\'X_pca\\' with n_pcs = {X.shape[1]}')\n            else:\n                logg.warning(\n                    f'You\u2019re trying to run this on {adata.n_vars} dimensions of `.X`, '\n                    'if you really want this, set `use_rep=\\'X\\'`.\\n         '\n                    'Falling back to preprocessing with `sc.pp.pca` and default params.'\n                )\n                X = pca(adata.X)\n                adata.obsm['X_pca'] = X[:, :n_pcs]\n        else:\n            logg.info('    using data matrix X directly')\n            X = adata.X\n    else:\n        if use_rep in adata.obsm.keys():\n            X = adata.obsm[use_rep]\n            if use_rep == 'X_pca' and n_pcs is not None:\n                X = adata.obsm[use_rep][:, :n_pcs]\n        elif use_rep == 'X':\n            X = adata.X\n        else:\n            raise ValueError(\n                'Did not find {} in `.obsm.keys()`. '\n                'You need to compute it first.'.format(use_rep)\n            )\n    settings.verbosity = verbosity  # resetting verbosity\n    return X\n\n\ndef preprocess_with_pca(adata, n_pcs: Optional[int] = None, random_state=0):\n    \"\"\"\n    Parameters\n    ----------\n    n_pcs\n        If `n_pcs=0`, do not preprocess with PCA.\n        If `None` and there is a PCA version of the data, use this.\n        If an integer, compute the PCA.\n    \"\"\"\n    if n_pcs == 0:\n        logg.info('    using data matrix X directly (no PCA)')\n        return adata.X\n    elif n_pcs is None and 'X_pca' in adata.obsm_keys():\n        logg.info(f'    using \\'X_pca\\' with n_pcs = {adata.obsm[\"X_pca\"].shape[1]}')\n        return adata.obsm['X_pca']\n    elif 'X_pca' in adata.obsm_keys() and adata.obsm['X_pca'].shape[1] >= n_pcs:\n        logg.info(f'    using \\'X_pca\\' with n_pcs = {n_pcs}')\n        return adata.obsm['X_pca'][:, :n_pcs]\n    else:\n        n_pcs = settings.N_PCS if n_pcs is None else n_pcs\n        if adata.X.shape[1] > n_pcs:\n            logg.info(f'    computing \\'X_pca\\' with n_pcs = {n_pcs}')\n            logg.hint('avoid this by setting n_pcs = 0')\n            X = pca(adata.X, n_comps=n_pcs, random_state=random_state)\n            adata.obsm['X_pca'] = X\n            return X\n        else:\n            logg.info('    using data matrix X directly (no PCA)')\n            return adata.X\n\n\ndef get_init_pos_from_paga(\n    adata, adjacency=None, random_state=0, neighbors_key=None, obsp=None\n):\n    np.random.seed(random_state)\n    if adjacency is None:\n        adjacency = _choose_graph(adata, obsp, neighbors_key)\n    if 'paga' in adata.uns and 'pos' in adata.uns['paga']:\n        groups = adata.obs[adata.uns['paga']['groups']]\n        pos = adata.uns['paga']['pos']\n        connectivities_coarse = adata.uns['paga']['connectivities']\n        init_pos = np.ones((adjacency.shape[0], 2))\n        for i, group_pos in enumerate(pos):\n            subset = (groups == groups.cat.categories[i]).values\n            neighbors = connectivities_coarse[i].nonzero()\n            if len(neighbors[1]) > 0:\n                connectivities = connectivities_coarse[i][neighbors]\n                nearest_neighbor = neighbors[1][np.argmax(connectivities)]\n                noise = np.random.random((len(subset[subset]), 2))\n                dist = pos[i] - pos[nearest_neighbor]\n                noise = noise * dist\n                init_pos[subset] = group_pos - 0.5 * dist + noise\n            else:\n                init_pos[subset] = group_pos\n    else:\n        raise ValueError(\n            'Plot PAGA first, so that adata.uns[\\'paga\\']' 'with key \\'pos\\'.'\n        )\n    return init_pos\n", "path": "scanpy/tools/_utils.py"}], "after_files": [{"content": "from typing import Optional\n\nimport numpy as np\nfrom .. import logging as logg\nfrom ._pca import pca\nfrom .. import settings\nfrom .._utils import _choose_graph\n\ndoc_use_rep = \"\"\"\\\nuse_rep\n    Use the indicated representation. `'X'` or any key for `.obsm` is valid.\n    If `None`, the representation is chosen automatically:\n    For `.n_vars` < 50, `.X` is used, otherwise 'X_pca' is used.\n    If 'X_pca' is not present, it\u2019s computed with default parameters.\\\n\"\"\"\n\ndoc_n_pcs = \"\"\"\\\nn_pcs\n    Use this many PCs. If `n_pcs==0` use `.X` if `use_rep is None`.\\\n\"\"\"\n\n\ndef _choose_representation(adata, use_rep=None, n_pcs=None, silent=False):\n    verbosity = settings.verbosity\n    if silent and settings.verbosity > 1:\n        settings.verbosity = 1\n    if use_rep is None and n_pcs == 0:  # backwards compat for specifying `.X`\n        use_rep = 'X'\n    if use_rep is None:\n        if adata.n_vars > settings.N_PCS:\n            if 'X_pca' in adata.obsm.keys():\n                if n_pcs is not None and n_pcs > adata.obsm['X_pca'].shape[1]:\n                    raise ValueError(\n                        '`X_pca` does not have enough PCs. Rerun `sc.pp.pca` with adjusted `n_comps`.'\n                    )\n                X = adata.obsm['X_pca'][:, :n_pcs]\n                logg.info(f'    using \\'X_pca\\' with n_pcs = {X.shape[1]}')\n            else:\n                logg.warning(\n                    f'You\u2019re trying to run this on {adata.n_vars} dimensions of `.X`, '\n                    'if you really want this, set `use_rep=\\'X\\'`.\\n         '\n                    'Falling back to preprocessing with `sc.pp.pca` and default params.'\n                )\n                X = pca(adata.X)\n                adata.obsm['X_pca'] = X[:, :n_pcs]\n        else:\n            logg.info('    using data matrix X directly')\n            X = adata.X\n    else:\n        if use_rep in adata.obsm.keys() and n_pcs is not None:\n            if n_pcs > adata.obsm[use_rep].shape[1]:\n                raise ValueError(\n                    f'{use_rep} does not have enough Dimensions. Provide a '\n                    'Representation with equal or more dimensions than'\n                    '`n_pcs` or lower `n_pcs` '\n                )\n            X = adata.obsm[use_rep][:, :n_pcs]\n        elif use_rep in adata.obsm.keys() and n_pcs is None:\n            X = adata.obsm[use_rep]\n        elif use_rep == 'X':\n            X = adata.X\n        else:\n            raise ValueError(\n                'Did not find {} in `.obsm.keys()`. '\n                'You need to compute it first.'.format(use_rep)\n            )\n    settings.verbosity = verbosity  # resetting verbosity\n    return X\n\n\ndef preprocess_with_pca(adata, n_pcs: Optional[int] = None, random_state=0):\n    \"\"\"\n    Parameters\n    ----------\n    n_pcs\n        If `n_pcs=0`, do not preprocess with PCA.\n        If `None` and there is a PCA version of the data, use this.\n        If an integer, compute the PCA.\n    \"\"\"\n    if n_pcs == 0:\n        logg.info('    using data matrix X directly (no PCA)')\n        return adata.X\n    elif n_pcs is None and 'X_pca' in adata.obsm_keys():\n        logg.info(f'    using \\'X_pca\\' with n_pcs = {adata.obsm[\"X_pca\"].shape[1]}')\n        return adata.obsm['X_pca']\n    elif 'X_pca' in adata.obsm_keys() and adata.obsm['X_pca'].shape[1] >= n_pcs:\n        logg.info(f'    using \\'X_pca\\' with n_pcs = {n_pcs}')\n        return adata.obsm['X_pca'][:, :n_pcs]\n    else:\n        n_pcs = settings.N_PCS if n_pcs is None else n_pcs\n        if adata.X.shape[1] > n_pcs:\n            logg.info(f'    computing \\'X_pca\\' with n_pcs = {n_pcs}')\n            logg.hint('avoid this by setting n_pcs = 0')\n            X = pca(adata.X, n_comps=n_pcs, random_state=random_state)\n            adata.obsm['X_pca'] = X\n            return X\n        else:\n            logg.info('    using data matrix X directly (no PCA)')\n            return adata.X\n\n\ndef get_init_pos_from_paga(\n    adata, adjacency=None, random_state=0, neighbors_key=None, obsp=None\n):\n    np.random.seed(random_state)\n    if adjacency is None:\n        adjacency = _choose_graph(adata, obsp, neighbors_key)\n    if 'paga' in adata.uns and 'pos' in adata.uns['paga']:\n        groups = adata.obs[adata.uns['paga']['groups']]\n        pos = adata.uns['paga']['pos']\n        connectivities_coarse = adata.uns['paga']['connectivities']\n        init_pos = np.ones((adjacency.shape[0], 2))\n        for i, group_pos in enumerate(pos):\n            subset = (groups == groups.cat.categories[i]).values\n            neighbors = connectivities_coarse[i].nonzero()\n            if len(neighbors[1]) > 0:\n                connectivities = connectivities_coarse[i][neighbors]\n                nearest_neighbor = neighbors[1][np.argmax(connectivities)]\n                noise = np.random.random((len(subset[subset]), 2))\n                dist = pos[i] - pos[nearest_neighbor]\n                noise = noise * dist\n                init_pos[subset] = group_pos - 0.5 * dist + noise\n            else:\n                init_pos[subset] = group_pos\n    else:\n        raise ValueError(\n            'Plot PAGA first, so that adata.uns[\\'paga\\']' 'with key \\'pos\\'.'\n        )\n    return init_pos\n", "path": "scanpy/tools/_utils.py"}]}