diff --git a/Exercises8-gameoflife.ipynb b/Exercises8-gameoflife.ipynb new file mode 100644 index 0000000..63021bb --- /dev/null +++ b/Exercises8-gameoflife.ipynb @@ -0,0 +1,65 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "567e2e56-b9fa-49ff-b672-a040cc537818", + "metadata": {}, + "source": [ + "### **Exercise: Game of Life (no xarray, just python practice)**\n", + "\n", + "Implement [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) using numpy array to hold data.\n", + "Neighbours are defined as adjacent cells.\n", + "\n", + " - Any LIVING cell with 2 or 3 neighbours survives.\n", + " - Any DEAD cell with 3 neighbours comes alive.\n", + " - Any OTHER LIVING cell dies.\n", + " - All deaths and births occur simultaneously\n", + "\n", + "For plotting: Jupyter is very finicky with \"real-time\" plots and there is a high chance it will refuse to plot everything in one frame even if you try all the stackoverflow solutions, so I propose just using a script to run your program (type \"python FILE_NAME.py\" in console). Try the following code to produce \"animation\" to test that it works:\n", + "\n", + "```\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.axis([0, 10, 0, 1])\n", + "\n", + "for i in range(10):\n", + " y = np.random.random()\n", + " plt.scatter(i, y)\n", + " plt.pause(0.5)\n", + "plt.show()\n", + "\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "646ae670-4f06-4bef-a161-b2ad0d9a8089", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Lecture8-xarray.ipynb b/Lecture8-xarray.ipynb new file mode 100644 index 0000000..c88b43a --- /dev/null +++ b/Lecture8-xarray.ipynb @@ -0,0 +1,4983 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a35244ba-c2a4-4bb3-8b91-a60e67b5a163", + "metadata": {}, + "source": [ + "### **Xarray**\n", + "\n", + "Xarray is a Python package for working with labelled **multi-dimensional** arrays. Documentaion can be found [here](https://docs.xarray.dev/en/stable/index.html).\n", + "\n", + "Installation line from their site:\n", + "\n", + "```\n", + "conda install -c conda-forge xarray dask netCDF4 bottleneck\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "996b6b41-0e81-4fa4-b4bd-708218749392", + "metadata": {}, + "outputs": [], + "source": [ + "import xarray as xr\n", + "\n", + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "id": "13da518e-2eeb-45f2-a404-a271e3b6aa0b", + "metadata": {}, + "source": [ + "#### **Core data structures:**\n", + "\n", + "`DataArray` is an implementation of a labeled, N-dimensional array. It is an a generalization of a `pandas.Series`. \n", + "\n", + "Let's create it (start with a panda-like 2 dimensions):" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "fa146f4e-602a-4c85-825a-8d37aceebca7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "array([[ 1.7031711 , 0.87109261, -1.10146049, 0.66713982],\n", + " [-0.58381484, 2.23172779, -1.07109423, -0.67708292],\n", + " [ 0.78173323, 0.74386989, -0.37114002, 0.04634405]])\n", + "Coordinates:\n", + " * x (x) int64 10 20 30\n", + "Dimensions without coordinates: y\n" + ] + } + ], + "source": [ + "data = xr.DataArray(np.random.randn(3, 4), dims=(\"x\", \"y\"), coords={\"x\": [10, 20,30]})\n", + "print(data)\n", + "#data # <--- gives a much nices print in Jupyter" + ] + }, + { + "cell_type": "markdown", + "id": "ea7cb154-d4fc-4b8e-8556-5449de27903a", + "metadata": {}, + "source": [ + "You can convert it to pandas:" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "1d32ec8d-7e46-40f1-a2bc-46a739923557", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
y0123
x
101.7031710.871093-1.1014600.667140
20-0.5838152.231728-1.071094-0.677083
300.7817330.743870-0.3711400.046344
\n", + "
" + ], + "text/plain": [ + "y 0 1 2 3\n", + "x \n", + "10 1.703171 0.871093 -1.101460 0.667140\n", + "20 -0.583815 2.231728 -1.071094 -0.677083\n", + "30 0.781733 0.743870 -0.371140 0.046344" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df=data.to_pandas()\n", + "df" + ] + }, + { + "cell_type": "markdown", + "id": "ea6b3229-ad19-4b2a-b9e1-f46c9a3d3b26", + "metadata": {}, + "source": [ + "Here we see that \"dims\" are labels for dimensions and \"coords\" are \"labels\" along the `x` axis. \n", + "We can generate that directly from pandas:" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "d68703aa-340e-4529-965f-7c4214233b3a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (name: 11, dim_1: 4)>\n",
+       "array([[24, 18, 30, 20],\n",
+       "       [18, 27, 29, 27],\n",
+       "       [21, 24, 28, 27],\n",
+       "       [30, 30, 29, 30],\n",
+       "       [24, 25, 27, 21],\n",
+       "       [23, 26, 30, 30],\n",
+       "       [18, 28, 26, 24],\n",
+       "       [19, 20, 27, 27],\n",
+       "       [24, 29, 23, 26],\n",
+       "       [24, 25, 26, 30],\n",
+       "       [20, 20, 18, 18]])\n",
+       "Coordinates:\n",
+       "  * name     (name) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * dim_1    (dim_1) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([[24, 18, 30, 20],\n", + " [18, 27, 29, 27],\n", + " [21, 24, 28, 27],\n", + " [30, 30, 29, 30],\n", + " [24, 25, 27, 21],\n", + " [23, 26, 30, 30],\n", + " [18, 28, 26, 24],\n", + " [19, 20, 27, 27],\n", + " [24, 29, 23, 26],\n", + " [24, 25, 26, 30],\n", + " [20, 20, 18, 18]])\n", + "Coordinates:\n", + " * name (name) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * dim_1 (dim_1) object 'course1' 'course2' 'course3' 'course4'" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('example.csv', index_col=0)\n", + "#print(df)\n", + "data=xr.DataArray(df)\n", + "data" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "d42960d2-f6ef-4dbd-9934-10a83fec2701", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('name', 'dim_1')\n", + "Coordinates:\n", + " * name (name) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * dim_1 (dim_1) object 'course1' 'course2' 'course3' 'course4'\n" + ] + } + ], + "source": [ + "print(data.dims)\n", + "print(data.coords)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "d9fde5f7-e4a8-47da-afce-5de3bef25921", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (pname: 11, course: 4)>\n",
+       "array([[24, 18, 30, 20],\n",
+       "       [18, 27, 29, 27],\n",
+       "       [21, 24, 28, 27],\n",
+       "       [30, 30, 29, 30],\n",
+       "       [24, 25, 27, 21],\n",
+       "       [23, 26, 30, 30],\n",
+       "       [18, 28, 26, 24],\n",
+       "       [19, 20, 27, 27],\n",
+       "       [24, 29, 23, 26],\n",
+       "       [24, 25, 26, 30],\n",
+       "       [20, 20, 18, 18]])\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([[24, 18, 30, 20],\n", + " [18, 27, 29, 27],\n", + " [21, 24, 28, 27],\n", + " [30, 30, 29, 30],\n", + " [24, 25, 27, 21],\n", + " [23, 26, 30, 30],\n", + " [18, 28, 26, 24],\n", + " [19, 20, 27, 27],\n", + " [24, 29, 23, 26],\n", + " [24, 25, 26, 30],\n", + " [20, 20, 18, 18]])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#there seems to not be an inplace option for this, \n", + "#so if you work on a big dataset, time to see if this takes too long\n", + "data=data.rename({\"dim_1\":\"course\", \"name\":\"pname\"})\n", + "data" + ] + }, + { + "cell_type": "markdown", + "id": "dbf42389-f180-40f9-ad41-e79f44ea135a", + "metadata": {}, + "source": [ + "Accessing data:\n", + "\n", + "positional, like numpy:" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "33d74554-1e89-47d1-aa71-331fb65568f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (course: 4)>\n",
+       "array([24, 18, 30, 20])\n",
+       "Coordinates:\n",
+       "    pname    <U5 'Marie'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([24, 18, 30, 20])\n", + "Coordinates:\n", + " pname \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray ()>\n",
+       "array(20)\n",
+       "Coordinates:\n",
+       "    pname    <U5 'Marie'\n",
+       "    course   <U7 'course4'
" + ], + "text/plain": [ + "\n", + "array(20)\n", + "Coordinates:\n", + " pname \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (course: 4)>\n",
+       "array([24, 18, 30, 20])\n",
+       "Coordinates:\n",
+       "    pname    <U5 'Marie'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([24, 18, 30, 20])\n", + "Coordinates:\n", + " pname \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (pname: 11)>\n",
+       "array([30, 29, 28, 29, 27, 30, 26, 27, 23, 26, 18])\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "    course   <U7 'course3'
" + ], + "text/plain": [ + "\n", + "array([30, 29, 28, 29, 27, 30, 26, 27, 23, 26, 18])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " course \n", + "array(['Marie', 'John', 'Kati', 'Olaf', 'Mark', 'Olga', 'Jean', 'Alex', 'Pier',\n", + " 'Bennet', 'Luis'], dtype=object)\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + "\n", + "array(['course1', 'course2', 'course3', 'course4'], dtype=object)\n", + "Coordinates:\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'\n", + "None\n" + ] + } + ], + "source": [ + "print(data.pname)\n", + "print(data.course)\n", + "print(data.name)" + ] + }, + { + "cell_type": "markdown", + "id": "92d38923-59a8-4c74-a1a3-004a17f31111", + "metadata": {}, + "source": [ + "sel: by dimension name and coordinate label" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "c1c5265e-9b97-4902-9b1e-6d61cd023a98", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (course: 4)>\n",
+       "array([24, 18, 30, 20])\n",
+       "Coordinates:\n",
+       "    pname    <U5 'Marie'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([24, 18, 30, 20])\n", + "Coordinates:\n", + " pname \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (pname: 11, course: 4)>\n",
+       "array([[34, 28, 40, 30],\n",
+       "       [28, 37, 39, 37],\n",
+       "       [31, 34, 38, 37],\n",
+       "       [40, 40, 39, 40],\n",
+       "       [34, 35, 37, 31],\n",
+       "       [33, 36, 40, 40],\n",
+       "       [28, 38, 36, 34],\n",
+       "       [29, 30, 37, 37],\n",
+       "       [34, 39, 33, 36],\n",
+       "       [34, 35, 36, 40],\n",
+       "       [30, 30, 28, 28]])\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'
" + ], + "text/plain": [ + "\n", + "array([[34, 28, 40, 30],\n", + " [28, 37, 39, 37],\n", + " [31, 34, 38, 37],\n", + " [40, 40, 39, 40],\n", + " [34, 35, 37, 31],\n", + " [33, 36, 40, 40],\n", + " [28, 38, 36, 34],\n", + " [29, 30, 37, 37],\n", + " [34, 39, 33, 36],\n", + " [34, 35, 36, 40],\n", + " [30, 30, 28, 28]])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data + 10" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "60b9d087-6a61-40dd-a306-1761640d2daf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (pname: 11, course: 4)>\n",
+       "array([[-0.90557836, -0.75098725, -0.98803162,  0.91294525],\n",
+       "       [-0.75098725,  0.95637593, -0.66363388,  0.95637593],\n",
+       "       [ 0.83665564, -0.90557836,  0.27090579,  0.95637593],\n",
+       "       [-0.98803162, -0.98803162, -0.66363388, -0.98803162],\n",
+       "       [-0.90557836, -0.13235175,  0.95637593,  0.83665564],\n",
+       "       [-0.8462204 ,  0.76255845, -0.98803162, -0.98803162],\n",
+       "       [-0.75098725,  0.27090579,  0.76255845, -0.90557836],\n",
+       "       [ 0.14987721,  0.91294525,  0.95637593,  0.95637593],\n",
+       "       [-0.90557836, -0.66363388, -0.8462204 ,  0.76255845],\n",
+       "       [-0.90557836, -0.13235175,  0.76255845, -0.98803162],\n",
+       "       [ 0.91294525,  0.91294525, -0.75098725, -0.75098725]])\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'\n",
+       "Attributes:\n",
+       "    long_name:         those are courses\n",
+       "    units:             they are grades out of 30\n",
+       "    description:       random fake grades data\n",
+       "    random_attribute:  123
" + ], + "text/plain": [ + "\n", + "array([[-0.90557836, -0.75098725, -0.98803162, 0.91294525],\n", + " [-0.75098725, 0.95637593, -0.66363388, 0.95637593],\n", + " [ 0.83665564, -0.90557836, 0.27090579, 0.95637593],\n", + " [-0.98803162, -0.98803162, -0.66363388, -0.98803162],\n", + " [-0.90557836, -0.13235175, 0.95637593, 0.83665564],\n", + " [-0.8462204 , 0.76255845, -0.98803162, -0.98803162],\n", + " [-0.75098725, 0.27090579, 0.76255845, -0.90557836],\n", + " [ 0.14987721, 0.91294525, 0.95637593, 0.95637593],\n", + " [-0.90557836, -0.66363388, -0.8462204 , 0.76255845],\n", + " [-0.90557836, -0.13235175, 0.76255845, -0.98803162],\n", + " [ 0.91294525, 0.91294525, -0.75098725, -0.75098725]])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'\n", + "Attributes:\n", + " long_name: those are courses\n", + " units: they are grades out of 30\n", + " description: random fake grades data\n", + " random_attribute: 123" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sin(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "020224d5-024b-4fb2-a9f3-af9cc0be8cb0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "array(1090)\n", + "\n", + "array([ 92, 101, 100, 119, 97, 109, 96, 93, 102, 105, 76])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + "\n", + "array([22.27272727, 24.72727273, 26.63636364, 25.45454545])\n", + "Coordinates:\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'\n", + "\n", + "array([23. , 25.25, 25. , 29.75, 24.25, 27.25, 24. , 23.25, 25.5 ,\n", + " 26.25, 19. ])\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n" + ] + } + ], + "source": [ + "#help(data)\n", + "print(data.sum())\n", + "print(data.sum(axis=1))\n", + "print(data.mean(axis=0))\n", + "print(data.mean(dim=\"course\"))" + ] + }, + { + "cell_type": "markdown", + "id": "7032075a-5ea1-4e52-99db-793b72992ad4", + "metadata": {}, + "source": [ + "#### **Plotting:**" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "e6d91a87-b9d9-45af-827e-e05a664bd403", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'This is a title')" + ] + }, + "execution_count": 116, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAHVCAYAAACt07JUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA20ElEQVR4nO3deXwV1f3/8fcly00ISYCwhsQkgOybEGQVUASKstkK1IUdLAUEpEVERFkN1rJYFSzUhlKqILK4oAgIYceyCkU22WUpRSFB1Ask5/eHP+7XSxKSG064ufB6Ph738ejMnJnzucfp5M3M3BmHMcYIAADAgkK+LgAAANw+CBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAawgWgI84HI5cfVJSUpSSkiKHw6H3338/x+327NlT8fHxVmqMj49Xz549rWzrZrzzzjuaNm1alsscDofGjBnjnv7qq680ZswYHT16NFNbm2MDIGuBvi4AuFNt2rTJY3r8+PFavXq1Vq1a5TG/WrVq2r59e663O3r0aA0ZMsRKjYsXL1ZERISVbd2Md955R//5z380dOjQTMs2bdqkmJgY9/RXX32lsWPHqkWLFoQIwAcIFoCPNGzY0GO6ZMmSKlSoUKb53qpQocJNrf9L99xzj7Vt5ZebHS8AdnEpBPAjV65c0ahRoxQdHa2IiAg9+OCD2r9/v0ebrE73L1iwQA0aNFBkZKQKFy6s8uXLq3fv3jn2d/2lkIyMDE2YMEGVK1dWaGioihYtqlq1aum111674XZ++ukn/eEPf1CdOnUUGRmp4sWLq1GjRvrggw9yrKFFixZaunSpjh075nGJ6JpfXgqZPXu2OnfuLEm6//773W1nz56d7faNMZo+fbrq1Kmj0NBQFStWTI8++qgOHz6cY20AMuOMBeBHnn/+eTVp0kR/+9vflJaWphEjRqh9+/bau3evAgICslxn06ZN6tq1q7p27aoxY8YoJCREx44dy3TJJTf+9Kc/acyYMXrhhRfUrFkzXblyRfv27dOFCxduuJ7L5dJ3332nP/7xjypXrpwuX76slStX6te//rWSk5PVvXv3bNedPn26nnrqKR06dEiLFy++YT8PP/ywXn75ZT3//PN68803VbduXUk3Povzu9/9TrNnz9bgwYP1yiuv6LvvvtO4cePUuHFjffnllypduvQN+wTgiWAB+JFq1app7ty57umAgAB16dJFW7ZsyfaSwMaNG2WM0VtvvaXIyEj3/LzclLlhwwbVrFnT42bJNm3a5LheZGSkkpOT3dPp6elq2bKlzp8/r2nTpt0wWFSrVk1FixaV0+nM8bJHyZIldffdd7vXy6n95s2bNWvWLE2ePFnDhg1zz7/vvvtUqVIlTZkyRa+88kqO3w/A/+FSCOBHOnTo4DFdq1YtSdKxY8eyXad+/fqSpC5duui9997TyZMn89z/vffeqy+//FIDBgzQZ599prS0tFyvu2DBAjVp0kRFihRRYGCggoKC9Pbbb2vv3r15rudmffzxx3I4HHryySd19epV96dMmTKqXbu2UlJSfFYb4K8IFoAfiYqK8ph2Op2SpB9//DHbdZo1a6YlS5bo6tWr6t69u2JiYlSjRg29++67Xvc/cuRI/fnPf9bmzZvVtm1bRUVFqWXLltq6desN11u0aJG6dOmicuXKae7cudq0aZO2bNmi3r1766effvK6Dlv++9//yhij0qVLKygoyOOzefNmnTt3zme1Af6KSyHAHaBjx47q2LGjXC6XNm/erKSkJD3++OOKj49Xo0aNcr2dwMBADRs2TMOGDdOFCxe0cuVKPf/882rTpo1OnDihwoULZ7ne3LlzlZCQoPnz53vceOlyuW76u92MEiVKyOFwaN26de6Q9ktZzQNwYwQL4A7idDrVvHlzFS1aVJ999pl27NjhVbD4paJFi+rRRx/VyZMnNXToUB09elTVqlXLsq3D4VBwcLBHqDhz5kyufhVyre4bnZW5vq1047M417Rr106TJk3SyZMn1aVLl1xtH8CNESyA29yLL76ob775Ri1btlRMTIwuXLig1157TUFBQWrevLlX22rfvr1q1KihxMRElSxZUseOHdO0adMUFxfnvmkyK+3atdOiRYs0YMAAPfroozpx4oTGjx+vsmXL6uDBgzn2W7NmTS1atEgzZsxQvXr1VKhQISUmJmbZtkaNGpKkmTNnKjw8XCEhIUpISMh0GUmSmjRpoqeeekq9evXS1q1b1axZM4WFhen06dNav369atasqd///ve5HB0AEsECuO01aNBAW7du1YgRI/S///1PRYsWVWJiolatWqXq1at7ta37779fCxcudP/ctUyZMmrVqpVGjx6toKCgbNfr1auX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uvb33nvPREVFuaeTk5ONJLNz586b6uuzzz4zhQoVMvv3789y+eOPP25atWrlMW/48OGmWrVq7uncBotp06Z5tKlZs6b7D/H1Ro8ebVq3bu0x78SJE0aS2b9/v9m2bZuRZI4ePZrl+tfLKlgYk/d94r777jMvv/yyx3r//Oc/TdmyZd3T1apVM6+88op7ulOnTqZnz565qveahx56yPzhD3/wqLdOnToebXIaK6Ag4FII7ji1atVy/++yZctKks6ePStJ2rt3r5o0aeLRvkmTJtq7d68kqXPnzvrxxx9Vvnx59evXT4sXL3afEt++fbuMMapUqZKKFCni/qxZs0aHDh3Ktp7Vq1erVatWKleunMLDw9W9e3d9++23Hqf6g4ODPerOS187d+5UTEyMKlWqlOXy7L77wYMHlZ6enm39WUlMTPSYHjx4sCZMmKAmTZropZde0q5du9zLtm3bptWrV3t8jypVqkiSDh06pNq1a6tly5aqWbOmOnfurFmzZun8+fNe1ZOTG+0T27Zt07hx4zzq69evn06fPq0ffvhBktS3b18lJye711u6dKl69+6dbX/p6emaOHGiatWqpaioKBUpUkTLly/X8ePHPdpdP445jRVQEAT6ugDgVgsKCnL/b4fDIUkeN0Nem3eNMcY9LzY2Vvv379eKFSu0cuVKDRgwQK+++qrWrFmjjIwMBQQEaNu2bQoICPDYRpEiRbKs5dixY3rooYfUv39/jR8/XsWLF9f69evVp08fj5seQ0NDPerKS1+hoaHZjsn13/OX837J4XBkmpfVzZlhYWEe03379lWbNm20dOlSLV++XElJSZo8ebKefvppZWRkqH379nrllVcybads2bIKCAjQihUrtHHjRi1fvlyvv/66Ro0apS+++EIJCQk3/E65daN9IiMjQ2PHjtWvf/3rTOuFhIRIkrp3767nnntOmzZt0qZNmxQfH6/77rsv2/4mT56sqVOnatq0ae77a4YOHZrpBs3rxzGnsQIKAoIFbkvBwcFe/ytbkqpWrar169ere/fu7nkbN25U1apV3dOhoaHq0KGDOnTooIEDB6pKlSravXu37rnnHqWnp+vs2bM3/KPyS1u3btXVq1c1efJkFSr08wnE9957L8f18tJXrVq19M033+jAgQNZnrWoVq2a1q9f7zFv48aNqlSpkju8lCxZUqdPn3YvP3jwoPtf7TmJjY1V//791b9/f40cOVKzZs3S008/rbp162rhwoWKj49XYGDWhySHw6EmTZqoSZMmevHFFxUXF6fFixdr2LBhuepbyvs+UbduXe3fv18VK1bMtk1UVJQ6deqk5ORkbdq0Sb169brhNtetW6eOHTvqySeflPRzYDh48KDHfpZdLTmNFeBr7Jm4LcXHx+uLL77Q0aNHVaRIERUvXjxX6w0fPlxdunRR3bp11bJlS3300UdatGiRVq5cKennX2ikp6erQYMGKly4sP75z38qNDRUcXFxioqK0hNPPKHu3btr8uTJuueee3Tu3DmtWrVKNWvW1EMPPZSpvwoVKujq1at6/fXX1b59e23YsEFvvfVWjnVWqlTJ676aN2+uZs2a6Te/+Y2mTJmiihUrat++fXI4HPrVr36lP/zhD6pfv77Gjx+vrl27atOmTXrjjTc0ffp09zYeeOABvfHGG2rYsKEyMjI0YsQIj3/tZ2fo0KFq27atKlWqpPPnz2vVqlXuP6IDBw7UrFmz9Nhjj2n48OEqUaKEvv76a82bN0+zZs3S1q1b9fnnn6t169YqVaqUvvjiC/3vf//L8Y/w9fK6T7z44otq166dYmNj1blzZxUqVEi7du3S7t27NWHCBHe7vn37ql27dkpPT1ePHj1uuM2KFStq4cKF2rhxo4oVK6YpU6bozJkzOX6nnMbq+rNXgE/48gYPIL/s37/fNGzY0ISGhhpJ5siRI1ne1Ldjxw738mumT59uypcvb4KCgkylSpXMnDlz3MsWL15sGjRoYCIiIkxYWJhp2LChx41/ly9fNi+++KKJj483QUFBpkyZMuaRRx4xu3btyrbWKVOmmLJly5rQ0FDTpk0bM2fOHI86k5OTTWRkZKb18tLXt99+a3r16mWioqJMSEiIqVGjhvn444/dy99//31TrVo1ExQUZO666y7z6quveqx/8uRJ07p1axMWFmbuvvtu88knn2R58+aOHTs81hs0aJCpUKGCcTqdpmTJkqZbt27m3Llz7uUHDhwwjzzyiClatKgJDQ01VapUMUOHDjUZGRnmq6++Mm3atDElS5Y0TqfTVKpUybz++uvZfsfsbt68mX1i2bJlpnHjxiY0NNRERESYe++91+PXQMYYk5GRYeLi4tw3+t7It99+azp27GiKFCliSpUqZV544QXTvXt307Fj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z5/XsGHDNHXqVJUtW1Z16tRRoUKFtGDBApUpUybb50wMHz5cL730kipUqKA6deooOTlZO3fu1L/+9S933bGxsRozZowmTJiggwcPZjrLEh8fr++//16ff/65ateurcKFC6tw4cJZ9tWlSxfVrVtXLVu21EcffaRFixZp5cqVuRl+t6SkJCUmJqpChQq6fPmyPvnkE82ZM8fjFx/Dhg1Tt27dlJiYqEaNGmnmzJk6fvy4+vfv71VfwB3Ph/d3AHeEtLQ08/jjj5vChQubMmXKmClTpph7773XPPfcc+42cXFxZurUqZnWHT58uImKijJFihQxXbt2NVOnTs100+PEiRNNiRIlTJEiRUyPHj3Ms88+63HzpjHG/Otf/zJ16tQxwcHBplixYqZZs2buX0DMnDnT1KlTx4SFhZmIiAjTsmVLs3379my/T3p6uhk7dqwpV66cCQoKMrVr1zaffvqpR5v169ebmjVrmpCQEHPfffeZBQsWeNy8aYwx/fv3N1FRUUaSeemll7Ltb/r06aZ8+fImKCjIVKpUycyZM8djeW5u3hw1apSpWLGiCQkJMcWKFTONGjUy8+bNy9TuzTffNHFxcSY4ONjUrVvXrFmzJlMbbt4EboyXkAG32KVLl1SuXDlNnjxZffr08XU58NLRo0eVkJCgHTt23FGPTgdyi0shQD7bsWOH9u3bp3vvvVepqakaN26cJKljx44+rgzeatu2rdauXevrMoACjWAB3AJ//vOftX//fvdNguvWrVOJEiV8XRa89Le//U0//vijJLkf8w3AE5dCAACANfzcFAAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFjz/wA9Koo2YYo6FQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#if the data makes sense to just plot, it can be done with just \"plot\"\n", + "#labels are taken from attributes, you can overwite with matplotlib\n", + "import matplotlib.pyplot as plt\n", + "data[2:].plot.hist()\n", + "plt.title(\"This is a title\")" + ] + }, + { + "cell_type": "markdown", + "id": "9de50e4d-dec4-41cb-b77b-396a39730d86", + "metadata": {}, + "source": [ + "[Documentaion](https://docs.xarray.dev/en/stable/user-guide/plotting.html#plotting) for plotting says you always need `import matplotlib.pyplot as plt`, but it seems to work fine for me without doing that if you are not making modifications to the default picture. That link also has a lot of plotting examples you might want to use if you work with complicated data." + ] + }, + { + "cell_type": "markdown", + "id": "c177b599-9745-49a5-a807-68d53c0f1b54", + "metadata": {}, + "source": [ + "### **DataSets:**\n", + "\n", + "DataSet is a dict-like container of DataArray objects aligned along any number of shared dimensions, and serves a similar purpose in xarray to the pandas.DataFrame.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "id": "ce0a9579-3430-4de3-afac-cd4808f51e03", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:  (pname: 11, course: 4)\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'\n",
+       "Data variables:\n",
+       "    grades   (pname, course) int64 24 18 30 20 18 27 29 ... 25 26 30 20 20 18 18
" + ], + "text/plain": [ + "\n", + "Dimensions: (pname: 11, course: 4)\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'\n", + "Data variables:\n", + " grades (pname, course) int64 24 18 30 20 18 27 29 ... 25 26 30 20 20 18 18" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#the easiest is to create it from an array\n", + "ds=data.to_dataset(name=\"grades\")\n", + "ds" + ] + }, + { + "cell_type": "markdown", + "id": "c55d3d95-12c9-4e30-877e-81a35a12eba6", + "metadata": {}, + "source": [ + "### **NetCDF**\n", + "\n", + "NetCDF (Network Common Data Form) is a set of software libraries and machine-independent data formats that support the creation, access, and sharing of array-oriented scientific data. It is also a community standard for sharing scientific data.\n", + "\n", + "[Wikipedia link](https://en.wikipedia.org/wiki/NetCDF)" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "4799707c-25da-441d-aea1-3f260cb56d24", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:  (pname: 11, course: 4)\n",
+       "Coordinates:\n",
+       "  * pname    (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n",
+       "  * course   (course) object 'course1' 'course2' 'course3' 'course4'\n",
+       "Data variables:\n",
+       "    grades   (pname, course) int64 ...
" + ], + "text/plain": [ + "\n", + "Dimensions: (pname: 11, course: 4)\n", + "Coordinates:\n", + " * pname (pname) object 'Marie' 'John' 'Kati' ... 'Pier' 'Bennet' 'Luis'\n", + " * course (course) object 'course1' 'course2' 'course3' 'course4'\n", + "Data variables:\n", + " grades (pname, course) int64 ..." + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds.to_netcdf(\"example.nc\")\n", + "\n", + "reopened = xr.open_dataset(\"example.nc\")\n", + "\n", + "reopened" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2fd27b90-0761-4780-a593-615844fd5c7d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:my_env2] *", + "language": "python", + "name": "conda-env-my_env2-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}