Repository: scverse/scanpy

Issue:
sc.get.obs_df() gives an error when `obsm_keys` is given and keys are not given
Calling `sc.get.obs_df()` without the `keys` parameter causes an error:

```python
adata = sc.datasets.pbmc68k_reduced()
sc.get.obs_df(adata, obsm_keys=[('X_umap', 0,)])
```

```pytb
~/scanpy/scanpy/get/get.py in obs_df(adata, keys, obsm_keys, layer, gene_symbols, use_raw)
    301 
    302     # reorder columns to given order (including duplicates keys if present)
--> 303     df = df[keys]
    304     for k, idx in obsm_keys:
    305         added_k = f"{k}-{idx}"

KeyError: ()
```

Also, if `keys` is not a list, the object returned is not a pandas dataframe but a Series object in which the last row is the obsm values. In other words, instead of adding a column to a dataframe with the obsm values, a row is added to a pandas Series. 

```python
adata = sc.datasets.pbmc68k_reduced()
sc.get.obs_df(adata, obsm_keys=[('X_umap', 0,)], keys='CST3')
```
```
index
AAAGCCTGGCTAAC-1                                                0.281
AAATTCGATGCACA-1                                               -0.176
AACACGTGGTCTTT-1                                               -0.818
AAGTGCACGTGCTA-1                                               -0.818
ACACGAACGGAGTG-1                                                0.854
                                          ...                        
TGTGAGTGCTTTAC-8                                               -0.069
TGTTACTGGCGATT-8                                               -0.818
TTCAGTACCGGGAA-8                                               -0.818
TTGAGGTGGAGAGC-8                                                0.428
X_umap-0            [-1.9918625454649166, -3.2486919412134108, -3....
Name: CST3, Length: 701, dtype: object
```


Discussion:

Resolving patch:
diff --git a/scanpy/get/get.py b/scanpy/get/get.py
--- a/scanpy/get/get.py
+++ b/scanpy/get/get.py
@@ -300,7 +300,9 @@ def obs_df(
         df = pd.concat([df, adata.obs[obs_cols]], axis=1)
 
     # reorder columns to given order (including duplicates keys if present)
-    df = df[keys]
+    if keys:
+        df = df[keys]
+
     for k, idx in obsm_keys:
         added_k = f"{k}-{idx}"
         val = adata.obsm[k]
@@ -364,7 +366,8 @@ def var_df(
         df = pd.concat([df, adata.var[var_cols]], axis=1)
 
     # reorder columns to given order
-    df = df[keys]
+    if keys:
+        df = df[keys]
 
     for k, idx in varm_keys:
         added_k = f"{k}-{idx}"


Test patch:
diff --git a/scanpy/tests/test_get.py b/scanpy/tests/test_get.py
--- a/scanpy/tests/test_get.py
+++ b/scanpy/tests/test_get.py
@@ -281,6 +281,32 @@ def test_var_df(adata):
     assert all(badkey_err.match(k) for k in badkeys)
 
 
+@TRANSPOSE_PARAMS
+def test_just_mapping_keys(dim, transform, func):
+    # https://github.com/theislab/scanpy/issues/1634
+    # Test for error where just passing obsm_keys, but not keys, would cause error.
+    mapping_attr = f"{dim}m"
+    kwargs = {f"{mapping_attr}_keys": [("array", 0), ("array", 1)]}
+
+    adata = transform(
+        sc.AnnData(
+            X=np.zeros((5, 5)),
+            obsm={
+                "array": np.arange(10).reshape((5, 2)),
+            },
+        )
+    )
+
+    expected = pd.DataFrame(
+        np.arange(10).reshape((5, 2)),
+        index=getattr(adata, f"{dim}_names"),
+        columns=["array-0", "array-1"],
+    )
+    result = func(adata, **kwargs)
+
+    pd.testing.assert_frame_equal(expected, result)
+
+
 ##################################
 # Test errors for obs_df, var_df #
 ##################################