Repository: geopandas/geopandas

Issue:
[cython] GeoSeries.reindex has wrong filling logic
```
In [2]: s = GeoSeries([Point(1,1), Point(2,2)])

In [3]: s.reindex([0,1,2])
Out[3]: I am densified (3 elements)

0    POINT (1 1)
1    POINT (2 2)
2    POINT (2 2)
dtype: object
```

while this should be `Point(1 1), Point(2 2), None`

The reason for this is because the `indexer` that is passed to `GeometryBlock.take_nd` (and currently thus `GeometryArray.take`) has the form of `array([ 0,  1, -1])`:

```
> /home/joris/scipy/geopandas/geopandas/_block.py(129)take_nd()
-> new_values = self.values[indexer]
(Pdb) l
127  	        # TODO implement take_nd on GeometryArray
128  	        # new_values = self.values.take_nd(indexer, fill_value=fill_value)
129  ->	        new_values = self.values[indexer]
130  	

(Pdb) indexer
array([ 0,  1, -1])
```


Discussion:
Actually, it is not using `GeometryArray.take`, but its `__getitem__`. And `take` already seems to support the '-1' indexer case:

https://github.com/geopandas/geopandas/blob/f9aa2202e47fdae4764fee20d15394d11a6d600e/geopandas/vectorized.pyx#L1208-L1211

should be an easy fix then!

Resolving patch:
diff --git a/geopandas/_block.py b/geopandas/_block.py
--- a/geopandas/_block.py
+++ b/geopandas/_block.py
@@ -124,7 +124,7 @@ def take_nd(self, indexer, axis=0, new_mgr_locs=None, fill_tuple=None):
 
         # TODO implement take_nd on GeometryArray
         # new_values = self.values.take_nd(indexer, fill_value=fill_value)
-        new_values = self.values[indexer]
+        new_values = self.values.take(indexer)
 
         # if we are a 1-dim object, then always place at 0
         if self.ndim == 1:


Test patch:
diff --git a/geopandas/tests/test_pandas_methods.py b/geopandas/tests/test_pandas_methods.py
--- a/geopandas/tests/test_pandas_methods.py
+++ b/geopandas/tests/test_pandas_methods.py
@@ -74,6 +74,26 @@ def test_indexing(s, df):
     assert_series_equal(s.loc[2:], exp)
 
 
+def test_reindex(s, df):
+    # GeoSeries reindex
+    res = s.reindex([1, 2, 3])
+    exp = GeoSeries([Point(1, 1), Point(2, 2), None], index=[1, 2, 3])
+    assert_geoseries_equal(res, exp)
+
+    # GeoDataFrame reindex index
+    res = df.reindex(index=[1, 2, 3])
+    assert_geoseries_equal(res.geometry, exp)
+
+    # GeoDataFrame reindex columns
+    res = df.reindex(columns=['value1', 'geometry'])
+    assert isinstance(res, GeoDataFrame)
+    assert isinstance(res.geometry, GeoSeries)
+    assert_frame_equal(res, df[['value1', 'geometry']])
+
+    # TODO df.reindex(columns=['value1', 'value2']) still returns GeoDataFrame,
+    # should it return DataFrame instead ?
+
+
 @pytest.mark.cython
 @pytest.mark.xfail(reason="GEOPANDAS-CYTHON not supported")
 def test_assignment(s, df):
diff --git a/geopandas/tests/util.py b/geopandas/tests/util.py
--- a/geopandas/tests/util.py
+++ b/geopandas/tests/util.py
@@ -116,6 +116,16 @@ def geom_equals(this, that):
     return (this.geom_equals(that) | (this.is_empty & that.is_empty)).all()
 
 
+def _geoms_equals(this, that):
+    """
+    Test that two GeoSeries objects have the same geometries.
+
+    """
+
+    return (this.geom_equals(that) | (this.is_empty & that.is_empty)
+            | this.isna() & that.isna()).all()
+
+
 def geom_almost_equals(this, that):
     """Test for 'almost' geometric equality. Empty geometries considered equal.
 
@@ -187,4 +197,4 @@ def assert_geoseries_equal(left, right, check_dtype=False,
     if check_less_precise:
         assert geom_almost_equals(left, right)
     else:
-        assert geom_equals(left, right)
+        assert _geoms_equals(left, right)