Repository: geopandas/geopandas

Issue:
Return `total_bounds` as an array?
Would it be possible to set the `total_bounds` attribute so that it's an array instead of a tuple? E.g., just throw in an `np.array` here:

https://github.com/geopandas/geopandas/blob/46e4033a4ae6a002af9637c894c0e12d37b6487a/geopandas/base.py#L279

The reason for this is that many plotting packages (e.g., cartopy) take bounds in a different order, so it's convenient to be able to do something like `bounds[[0, 2, 1, 3]]`


Discussion:
(I'm happy to make this PR if folks are friendly to it)
I can't think of any problem by doing that? (I mean incompatibilities by assuming a tuple when it will now return an array) 
If so, I am fine with that.

(one thing I think of is that you would now be able to change an element of the returned property (without effect), without it raising an error, like `df.total_bounds[0] = 10`, but that doesn't seem like a major problem)



Resolving patch:
diff --git a/geopandas/base.py b/geopandas/base.py
--- a/geopandas/base.py
+++ b/geopandas/base.py
@@ -283,10 +283,10 @@ def total_bounds(self):
         """
 
         b = self.bounds
-        return (b['minx'].min(),
-                b['miny'].min(),
-                b['maxx'].max(),
-                b['maxy'].max())
+        return np.array((b['minx'].min(),
+                         b['miny'].min(),
+                         b['maxx'].max(),
+                         b['maxy'].max()))
 
     @property
     def sindex(self):
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -307,7 +307,7 @@ def _to_geo(self, **kwargs):
                'features': list(self.iterfeatures(**kwargs))}
 
         if kwargs.get('show_bbox', False):
-            geo['bbox'] = self.total_bounds
+            geo['bbox'] = tuple(self.total_bounds)
 
         return geo
 


Test patch:
diff --git a/geopandas/tests/test_geom_methods.py b/geopandas/tests/test_geom_methods.py
--- a/geopandas/tests/test_geom_methods.py
+++ b/geopandas/tests/test_geom_methods.py
@@ -92,7 +92,7 @@ def _test_binary_topological(self, op, expected, a, b, *args, **kwargs):
         else:
             right_df = False
 
-        self._binary_op_test(op, expected, a, b, fcmp, True, right_df, 
+        self._binary_op_test(op, expected, a, b, fcmp, True, right_df,
                         *args, **kwargs)
 
     def _test_binary_real(self, op, expected, a, b, *args, **kwargs):
@@ -118,7 +118,7 @@ def _test_binary_operator(self, op, expected, a, b):
         self._binary_op_test(op, expected, a, b, fcmp, False, right_df)
 
     def _binary_op_test(self, op, expected, left, right, fcmp, left_df,
-                        right_df, 
+                        right_df,
                         *args, **kwargs):
         """
         This is a helper to call a function on GeoSeries and GeoDataFrame
@@ -129,12 +129,12 @@ def _binary_op_test(self, op, expected, left, right, fcmp, left_df,
 
         Parameters
         ----------
-        
+
         expected : str
             The operation to be tested. e.g., 'intersection'
         left: GeoSeries
         right: GeoSeries
-        fcmp: function 
+        fcmp: function
             Called with the result of the operation and expected. It should
             assert if the result is incorrect
         left_df: bool
@@ -148,16 +148,16 @@ def _make_gdf(s):
             n = len(s)
             col1 = string.ascii_lowercase[:n]
             col2 = range(n)
-            
-            return GeoDataFrame({'geometry': s.values, 
-                                 'col1' : col1, 
+
+            return GeoDataFrame({'geometry': s.values,
+                                 'col1' : col1,
                                  'col2' : col2},
                                  index=s.index, crs=s.crs)
 
         # Test GeoSeries.op(GeoSeries)
         result = getattr(left, op)(right, *args, **kwargs)
         fcmp(result, expected)
-        
+
         if left_df:
             # Test GeoDataFrame.op(GeoSeries)
             gdf_left = _make_gdf(left)
@@ -186,7 +186,7 @@ def _test_unary(self, op, expected, a, fcmp):
         fcmp(result, expected)
 
     def test_intersection(self):
-        self._test_binary_topological('intersection', self.t1, 
+        self._test_binary_topological('intersection', self.t1,
                                       self.g1, self.g2)
 
     def test_union_series(self):
@@ -419,11 +419,12 @@ def test_envelope(self):
 
     def test_total_bounds(self):
         bbox = self.sol.x, self.sol.y, self.esb.x, self.esb.y
-        self.assert_(self.landmarks.total_bounds, bbox)
+        self.assertIsInstance(self.landmarks.total_bounds, np.ndarray)
+        self.assert_(tuple(self.landmarks.total_bounds), bbox)
 
         df = GeoDataFrame({'geometry': self.landmarks,
                            'col1': range(len(self.landmarks))})
-        self.assert_(df.total_bounds, bbox)
+        self.assert_(tuple(df.total_bounds), bbox)
 
     def test_explode(self):
         s = GeoSeries([MultiPoint([(0,0), (1,1)]),