Repository: numpy/numpy

Issue:
Masked array equivalent append function (Trac #1623)
_Original ticket http://projects.scipy.org/numpy/ticket/1623 on 2010-09-29 by trac user gsever, assigned to @pierregm._

Current np.append implementation can't handle masked array appending. 

```
I[1]: a = np.ma.masked_equal([1,2,3], value=2)

I[2]: b = np.ma.masked_equal([4,3,2], value=2)

I[3]: np.append(a,b)
O[3]: 
masked_array(data = [1 2 3 4 3 2],
             mask = False,
       fill_value = 999999)
```

It would be nice to have np.ma.append() to operate on masked arrays properly. The desired output from that given piece would be:

```
np.ma.append(a,b)
masked_array(data = [1 -- 3 4 3 --],
             mask = [False, True, False, False, False, True],
       fill_value = 999999)
```



Discussion:
@kh452 Are you going to finish this up?


Resolving patch:
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -46,7 +46,7 @@
 __all__ = ['MAError', 'MaskError', 'MaskType', 'MaskedArray',
            'bool_',
            'abs', 'absolute', 'add', 'all', 'allclose', 'allequal', 'alltrue',
-           'amax', 'amin', 'angle', 'anom', 'anomalies', 'any', 'arange',
+           'amax', 'amin', 'angle', 'anom', 'anomalies', 'any', 'append', 'arange',
            'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2',
            'arctanh', 'argmax', 'argmin', 'argsort', 'around',
            'array', 'asarray', 'asanyarray',
@@ -7258,3 +7258,41 @@ def __call__(self, a, *args, **params):
 zeros_like = np.zeros_like
 
 ###############################################################################
+def append(a, b, axis=None):
+    """Append values to the end of an array.
+
+    .. versionadded:: 1.9.0
+
+    Parameters
+    ----------
+    arr : array_like
+        Values are appended to a copy of this array.
+    values : array_like
+        These values are appended to a copy of `arr`.  It must be of the
+        correct shape (the same shape as `arr`, excluding `axis`).  If `axis`
+        is not specified, `values` can be any shape and will be flattened
+        before use.
+    axis : int, optional
+        The axis along which `values` are appended.  If `axis` is not given,
+        both `arr` and `values` are flattened before use.
+
+    Returns
+    -------
+    append : MaskedArray
+        A copy of `arr` with `values` appended to `axis`.  Note that `append`
+        does not occur in-place: a new array is allocated and filled.  If
+        `axis` is None, the result is a flattened array.
+
+    See Also
+    --------
+    numpy.append : Equivalent function in the top-level NumPy module.
+
+    Examples
+    --------
+    >>> import numpy.ma as ma
+    >>> a = ma.masked_values([1, 2, 3], 2)
+    >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
+    >>> print(ma.append(a, b))
+    [1 -- 3 4 5 6 -- 8 9]
+    """
+    return concatenate([a, b], axis)


Test patch:
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -13,6 +13,8 @@
 import pickle
 from functools import reduce
 
+from nose.tools import assert_raises
+
 import numpy as np
 import numpy.ma.core
 import numpy.core.fromnumeric as fromnumeric
@@ -3583,6 +3585,45 @@ def test_masked_array():
     a = np.ma.array([0, 1, 2, 3], mask=[0, 0, 1, 0])
     assert_equal(np.argwhere(a), [[1], [3]])
 
+def test_append_masked_array():
+    a = np.ma.masked_equal([1,2,3], value=2)
+    b = np.ma.masked_equal([4,3,2], value=2)
+
+    result = np.ma.append(a, b)
+    expected_data = [1, 2, 3, 4, 3, 2]
+    expected_mask = [False, True, False, False, False, True]
+    assert_array_equal(result.data, expected_data)
+    assert_array_equal(result.mask, expected_mask)
+
+    a = np.ma.masked_all((2,2))
+    b = np.ma.ones((3,1))
+
+    result = np.ma.append(a, b)
+    expected_data = [1] * 3
+    expected_mask = [True] * 4 + [False] * 3
+    assert_array_equal(result.data[-3], expected_data)
+    assert_array_equal(result.mask, expected_mask)
+
+    result = np.ma.append(a, b, axis=None)
+    assert_array_equal(result.data[-3], expected_data)
+    assert_array_equal(result.mask, expected_mask)
+
+
+def test_append_masked_array_along_axis():
+    a = np.ma.masked_equal([1,2,3], value=2)
+    b = np.ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
+    
+    # When `axis` is specified, `values` must have the correct shape.
+    assert_raises(ValueError, np.ma.append, a, b, axis=0)
+
+    result = np.ma.append(a[np.newaxis,:], b, axis=0)
+    expected = np.ma.arange(1, 10)
+    expected[[1, 6]] = np.ma.masked
+    expected = expected.reshape((3,3))
+    assert_array_equal(result.data, expected.data)
+    assert_array_equal(result.mask, expected.mask)
+    
+
 ###############################################################################
 if __name__ == "__main__":
     run_module_suite()