Repository: pydata/xarray
Issue: Strings are truncated when concatenating Datasets.

When concatenating Datasets, a variable's string length is limited to the length in the first of the Datasets being concatenated.

```
>>> import xray
>>> first = xray.Dataset({'animal': ('animal', ['horse'])})
>>> second = xray.Dataset( {'animal': ('animal', ['aardvark_0'])})
>>> xray.Dataset.concat([first, second], dimension='animal')['animal']
<xray.DataArray 'animal' (animal: 2)>
array(['horse', 'aardv'], 
      dtype='|S5')
Coordinates:
    animal: Index([u'horse', u'aardv'], dtype='object')
Attributes:
    Empty
```

(Note the `|S5` dtype and the truncated `aardv`)

I think this is the offending line: https://github.com/xray/xray/blob/master/xray/core/variable.py#L623
May want to use `dtype=object` for strings to avoid this issue.


Changed files:
xray/test/test_variable.py, xray/core/variable.py

diff --git a/xray/core/variable.py b/xray/core/variable.py
index 0fb4c91f1..9467a4ba0 100644
--- a/xray/core/variable.py
+++ b/xray/core/variable.py
@@ -620,10 +620,17 @@ class Variable(common.AbstractArray):
             shape = (length,) + first_var.shape
             dims = (dim,) + first_var.dims
 
-        concatenated = cls(dims, np.empty(shape, dtype=first_var.dtype))
-        concatenated.attrs.update(first_var.attrs)
+        dtype = first_var.dtype
+        if dtype.kind in ['S', 'U']:
+            # use an object array instead of a fixed length strings to avoid
+            # possible truncation
+            dtype = object
+
+        data = np.empty(shape, dtype=dtype)
+        attrs = OrderedDict(first_var.attrs)
 
         alt_dims = tuple(d for d in dims if d != dim)
+        key = [slice(None)] * len(dims)
 
         # copy in the data from the variables
         for var, indexer in zip(variables, indexers):
@@ -631,17 +638,16 @@ class Variable(common.AbstractArray):
                 # do sanity checks & attributes clean-up
                 if dim in var.dims:
                     # transpose verifies that the dims are equivalent
-                    if var.dims != concatenated.dims:
-                        var = var.transpose(*concatenated.dims)
+                    if var.dims != dims:
+                        var = var.transpose(*dims)
                 elif var.dims != alt_dims:
                     raise ValueError('inconsistent dimensions')
-                utils.remove_incompatible_items(concatenated.attrs, var.attrs)
+                utils.remove_incompatible_items(attrs, var.attrs)
 
-            key = tuple(indexer if n == axis else slice(None)
-                        for n in range(concatenated.ndim))
-            concatenated.values[key] = var.values
+            key[axis] = indexer
+            data[key] = var.values
 
-        return concatenated
+        return cls(dims, data, attrs)
 
     def _data_equals(self, other):
         return (self._data is other._data
diff --git a/xray/test/test_variable.py b/xray/test/test_variable.py
index 9b5bd98ab..4fc769844 100644
--- a/xray/test/test_variable.py
+++ b/xray/test/test_variable.py
@@ -261,6 +261,16 @@ class VariableSubclassTestCases(object):
         expected.attrs['foo'] = 'bar'
         self.assertVariableIdentical(expected, Variable.concat([v, w], 'a'))
 
+    def test_concat_fixed_len_str(self):
+        # regression test for #217
+        for kind in ['S', 'U']:
+            x = self.cls('animal', np.array(['horse'], dtype=kind))
+            y = self.cls('animal', np.array(['aardvark'], dtype=kind))
+            actual = Variable.concat([x, y], 'animal')
+            expected = Variable(
+                'animal', np.array(['horse', 'aardvark'], dtype=kind))
+            self.assertVariableEqual(expected, actual)
+
     def test_copy(self):
         v = self.cls('x', 0.5 * np.arange(10), {'foo': 'bar'})
         for deep in [True, False]: