{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modify array shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Basic numpy methods to modify array dimensions are implemented in dimarray, with some additional functionality allowed by named dimensions.\n",
    "\n",
    ".. seealso:: :ref:`refapi_reshaping`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### transpose"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Transpose, just like its numpy equivalent, permutes dimensions, but in dimarray it can be provided with axis names instead of just axis position."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 6 non-null elements (0 null)\n",
       "0 / x1 (3): 0 to 2\n",
       "1 / x0 (2): 0 to 1\n",
       "array([[1, 3],\n",
       "       [2, 4],\n",
       "       [3, 5]])"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from dimarray import DimArray\n",
    "a = DimArray([[1,2,3],[3,4,5]],dims=('x0','x1'))\n",
    "a.transpose() # doctest: +SKIP\n",
    "a.T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 6 non-null elements (0 null)\n",
       "0 / x1 (3): 0 to 2\n",
       "1 / x2 (1): 0 to 0\n",
       "2 / x0 (2): 0 to 1\n",
       "array([[[1, 3]],\n",
       "\n",
       "       [[2, 4]],\n",
       "\n",
       "       [[3, 5]]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = DimArray([[[1,2,3],[3,4,5]]],dims=('x2','x0','x1'))\n",
    "a.transpose('x1','x2','x0')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### swapaxes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sometimes it is only useful to have on dimension in the first position, for example to make indexing easier. \n",
    ":py:ref:`dimarray.DimArray.swapaxes` is a more general method of swapping two axes, but it can achieve that operation nicely (more useful with more than 2 dimensions!):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 6 non-null elements (0 null)\n",
       "0 / x1 (3): 0 to 2\n",
       "1 / x0 (2): 0 to 1\n",
       "array([[1, 3],\n",
       "       [2, 4],\n",
       "       [3, 5]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = DimArray([[1,2,3],[3,4,5]],dims=('x0','x1'))\n",
    "a.swapaxes('x1',0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### flatten and unflatten [experimental]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As a new, experimental feature, it is possible to flatten or any subset of dimensions. Corresponding axes are converted in MultiAxis objects. It is similar to numpy's flatten method but may apply selectively on a set of axes. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 24 non-null elements (0 null)\n",
       "0 / time (2): 1950 to 1955\n",
       "1 / lat (3): -90.0 to 90.0\n",
       "2 / lon (4): -180.0 to 180.0\n",
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7],\n",
       "        [ 8,  9, 10, 11]],\n",
       "\n",
       "       [[12, 13, 14, 15],\n",
       "        [16, 17, 18, 19],\n",
       "        [20, 21, 22, 23]]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "data = np.arange(2*3*4).reshape(2,3,4)\n",
    "v = DimArray(data, dims=['time','lat','lon'], axes=[[1950,1955], np.linspace(-90,90,3), np.linspace(-180,180,4)])\n",
    "v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Flatten a set of dimensions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 24 non-null elements (0 null)\n",
       "0 / time (2): 1950 to 1955\n",
       "1 / lat,lon (12): (-90.0, -180.0) to (90.0, 180.0)\n",
       "array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],\n",
       "       [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w = v.flatten(('lat','lon'))\n",
    "w"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Along-axis transformations use that feature and can flatten any subset of axes prior to the operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 2 non-null elements (0 null)\n",
       "0 / time (2): 1950 to 1955\n",
       "array([  5.5,  17.5])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.mean(axis=('lat','lon'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any flattened axis can be reshaped back to full n-d array via **`unflatten`**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dimarray: 24 non-null elements (0 null)\n",
       "0 / time (2): 1950 to 1955\n",
       "1 / lat (3): -90.0 to 90.0\n",
       "2 / lon (4): -180.0 to 180.0\n",
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7],\n",
       "        [ 8,  9, 10, 11]],\n",
       "\n",
       "       [[12, 13, 14, 15],\n",
       "        [16, 17, 18, 19],\n",
       "        [20, 21, 22, 23]]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w.unflatten()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### reshape [experimental]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":py:meth:`dimarray.DimArray.reshape` is similar but not the same as numpy ndarray's :ref:`reshape <http://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html>`. It takes only axis names as parameters. It is a high-level function that makes use of `newaxis`, `squeeze`, `flatten` and `unflatten` to reshape the array. It differs from numpy in that it cannot \"break\" an existing dimension (unless it is a MultiAxis). It also performs :py:meth:`transpose` as needed to match the required shape. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here an example where high-dimensional data is converted into a pandas' DataFrame for displaying result of a sensitivity analysis. MultiAxis are converted into MultiIndex before passing to pandas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"max-height:1000px;max-width:1500px;overflow:auto;\">\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th>B</th>\n",
       "      <th colspan=\"5\" halign=\"left\">0</th>\n",
       "      <th colspan=\"5\" halign=\"left\">1</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th>C</th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>A</th>\n",
       "      <th>D</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"2\" valign=\"top\">0</th>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "      <td>6</td>\n",
       "      <td>8</td>\n",
       "      <td>10</td>\n",
       "      <td>12</td>\n",
       "      <td>14</td>\n",
       "      <td>16</td>\n",
       "      <td>18</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>5</td>\n",
       "      <td>7</td>\n",
       "      <td>9</td>\n",
       "      <td>11</td>\n",
       "      <td>13</td>\n",
       "      <td>15</td>\n",
       "      <td>17</td>\n",
       "      <td>19</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th rowspan=\"2\" valign=\"top\">1</th>\n",
       "      <th>0</th>\n",
       "      <td>20</td>\n",
       "      <td>22</td>\n",
       "      <td>24</td>\n",
       "      <td>26</td>\n",
       "      <td>28</td>\n",
       "      <td>30</td>\n",
       "      <td>32</td>\n",
       "      <td>34</td>\n",
       "      <td>36</td>\n",
       "      <td>38</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>21</td>\n",
       "      <td>23</td>\n",
       "      <td>25</td>\n",
       "      <td>27</td>\n",
       "      <td>29</td>\n",
       "      <td>31</td>\n",
       "      <td>33</td>\n",
       "      <td>35</td>\n",
       "      <td>37</td>\n",
       "      <td>39</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "B     0                   1                \n",
       "C     0   1   2   3   4   0   1   2   3   4\n",
       "A D                                        \n",
       "0 0   0   2   4   6   8  10  12  14  16  18\n",
       "  1   1   3   5   7   9  11  13  15  17  19\n",
       "1 0  20  22  24  26  28  30  32  34  36  38\n",
       "  1  21  23  25  27  29  31  33  35  37  39"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "large_array = DimArray(np.arange(2*2*5*2).reshape(2,2,5,2), dims=('A','B','C','D'))\n",
    "large_array.reshape('A,D','B,C').to_pandas()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}