Repository: regionmask/regionmask

Issue:
bug with rasterize_flip
Something goes terribly wrong with `rasterize_flip` - maybe only when wrap_lon is called? I am confused... Why does this go wrong and why is it not caught in the tests?


```python
import regionmask
import numpy as np
import matplotlib.pyplot as plt
%matplotlib

lat = np.arange(90, -91, -2.5)
lon = np.arange(-300, 60, 2.5)
regionmask.defined_regions.srex.mask(lon, lat, wrap_lon=180).plot()
```

Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) Report
> Merging [#267](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (0dc6632) into [master](https://codecov.io/gh/regionmask/regionmask/commit/e59aaa94f07e1579033ef2436701a1fe99ff3659?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (e59aaa9) will **decrease** coverage by `0.84%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/regionmask/regionmask/pull/267/graphs/tree.svg?width=650&height=150&src=pr&token=WI9PSJZIB7&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask)](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask)

```diff
@@            Coverage Diff             @@
##           master     #267      +/-   ##
==========================================
- Coverage   98.97%   98.12%   -0.85%     
==========================================
  Files          14       14              
  Lines        1068     1068              
==========================================
- Hits         1057     1048       -9     
- Misses         11       20       +9     
```

| Flag | Coverage Δ | |
|---|---|---|
| py36-bare-minimum | `?` | |
| py36-min-all-deps | `?` | |
| unittests | `98.12% <100.00%> (-0.85%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | Coverage Δ | |
|---|---|---|
| [regionmask/core/mask.py](https://codecov.io/gh/regionmask/regionmask/pull/267/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9jb3JlL21hc2sucHk=) | `97.79% <100.00%> (-1.77%)` | :arrow_down: |
| [regionmask/defined\_regions/natural\_earth.py](https://codecov.io/gh/regionmask/regionmask/pull/267/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9kZWZpbmVkX3JlZ2lvbnMvbmF0dXJhbF9lYXJ0aC5weQ==) | `96.33% <0.00%> (-2.76%)` | :arrow_down: |
| [regionmask/core/plot.py](https://codecov.io/gh/regionmask/regionmask/pull/267/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9jb3JlL3Bsb3QucHk=) | `98.50% <0.00%> (-1.50%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask). Last update [e59aaa9...0dc6632](https://codecov.io/gh/regionmask/regionmask/pull/267?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask).


Patch:
diff --git a/docs/whats_new.rst b/docs/whats_new.rst
index 186ea08..a689350 100644
--- a/docs/whats_new.rst
+++ b/docs/whats_new.rst
@@ -51,6 +51,18 @@ New regions
 Bug Fixes
 ~~~~~~~~~
 
+- Fixed a bug that could silently lead to a wrong mask in certain cases. Three conditions are
+  required:
+
+  1. The longitude coordinates are not ordered (note that wrapping the longitudes can
+     also lead to unordered coordinates).
+  2. Rearranging the coordinates makes them equally spaced.
+  3. The split point is not in the middle of the array.
+
+  Thus, the issue would happen for the following example longitude coordinates: ``[3, 4, 5, 1, 2]``
+  (but not for ``[3, 4, 1, 2]``). Before the bugfix the mask would incorrectly be rearranged
+  in the following order ``[4, 5, 1, 2, 3]`` (:issue:`266`).
+
 - :py:meth:`Regions.mask` (and all other ``mask`` methods and functions) no longer raise
   an error for regions that exceed 360° latitude if ``wrap_lon=False``. This was most
   likely a regression from :pull:`48` (:issue:`151`).
diff --git a/regionmask/core/mask.py b/regionmask/core/mask.py
index 7dff9d9..ac895b0 100644
--- a/regionmask/core/mask.py
+++ b/regionmask/core/mask.py
@@ -512,7 +512,7 @@ def _mask_rasterize_flip(lon, lat, polygons, numbers, fill=np.NaN, **kwargs):
     mask = _mask_rasterize(flipped_lon, lat, polygons, numbers=numbers)
 
     # revert the mask
-    return np.hstack((mask[:, split_point:], mask[:, :split_point]))
+    return np.hstack((mask[:, -split_point:], mask[:, :-split_point]))
 
 
 def _mask_rasterize_split(lon, lat, polygons, numbers, fill=np.NaN, **kwargs):


Test patch:
diff --git a/regionmask/tests/test_mask.py b/regionmask/tests/test_mask.py
index c75107e..6c91532 100644
--- a/regionmask/tests/test_mask.py
+++ b/regionmask/tests/test_mask.py
@@ -678,6 +678,21 @@ def test_rasterize_on_split_lon(ds_360, regions_180):
     xr.testing.assert_equal(result, expected_shapely)
 
 
+def test_rasterize_on_split_lon_asymmetric():
+    # https://github.com/regionmask/regionmask/issues/266
+
+    # for _mask_rasterize_flip: split_point not in the middle
+    lon = np.hstack([np.arange(-90, 20, 2), np.arange(-180, -90, 2)])
+    lat = np.arange(75, 13, -2)
+    ds = xr.Dataset(coords=dict(lon=lon, lat=lat))
+
+    assert _determine_method(ds.lon, ds.lat) == "rasterize_flip"
+
+    result = r_US_180_cw.mask(ds, method="rasterize")
+    expected = r_US_180_cw.mask(ds, method="shapely")
+    xr.testing.assert_equal(result, expected)
+
+
 METHOD_IRREGULAR = "pygeos" if has_pygeos else "shapely"
 METHODS = {
     0: "rasterize",