summaryrefslogtreecommitdiff
path: root/python/atms-310/notebooks/Week 06 M.ipynb
blob: 193e7a51cf4b6979567407ac00c310ca0bdf9292 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>13. More Adventures in OOP</h1>\n",
    "<h2>10/30/2023</h2>\n",
    "\n",
    "<h2>13.0 Last Time...</h2>\n",
    "<ul>\n",
    "    <li>A class can be created using a <b>class</b> statement followed by the name of the class.</li>\n",
    "    <li>Methods within a class definition are created using a <b>def</b> statement.</li>\n",
    "    <li><b>__init__</b> is typically the first method defined and is used to initialize the core features of the class.</li>\n",
    "</ul>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>13.1 OOP Example: Creating a Bibliography</h2>\n",
    "\n",
    "Let's create a new class called <b>Article</b> that's similar to our book class from last time, but stores a scientific journal article instead of a book, and writes the bibiliography entry accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Start by defining a new class. (Remember, you need the 'object' argument.)\n",
    "class Article(object):\n",
    "        def __init__(self, authlast, authfirst, arttitle, journtitle, volume, pages, year):\n",
    "                self.authlast = authlast\n",
    "                self.authfirst = authfirst\n",
    "                self.arttitle = arttitle\n",
    "                self.journtitle = journtitle\n",
    "                self.volume = volume\n",
    "                self.pages = pages\n",
    "                self.year = year\n",
    "        # Let's create the make_authoryear and write_bib_entry methods from before.\n",
    "        def write_bib_entry(self):\n",
    "            \n",
    "    # We won't need any additional arguments here, since it's all handled above.\n",
    "                return self.authlast + ',' + self.authfirst + ',' + self.arttitle + ',' + self.journtitle + ',' + self.volume + ',' + self.pages + ',' + self.year\n",
    "        def authyear(self):\n",
    "                self.authyear = self.authlast + '('+self.year +')'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Article object at 0x7f0511dc9dd0>\n",
      "brooks,harold,on the tornado thingies,journal,19,310-319,2004\n"
     ]
    }
   ],
   "source": [
    "# And a test!\n",
    "tornado = Article(\"brooks\", 'harold', \"on the tornado thingies\", \"journal\", \"19\", \"310-319\", \"2004\")\n",
    "print(tornado)\n",
    "print(tornado.write_bib_entry())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also bring <b>Book</b> and our two instances of Book back from last lecture:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Book(object):\n",
    "    \n",
    "    def __init__(self, authlast, authfirst, \\\n",
    "                title, place, publisher, year):\n",
    "        self.authlast = authlast\n",
    "        self.authfirst = authfirst\n",
    "        self.title = title\n",
    "        self.place = place\n",
    "        self.publisher = publisher\n",
    "        self.year = year\n",
    "    \n",
    "    def write_bib_entry(self):        \n",
    "        return self.authlast \\\n",
    "            + ', ' + self.authfirst \\\n",
    "            + ', ' + self.title \\\n",
    "            + ', ' + self.place \\\n",
    "            + ': ' + self.publisher + ', '\\\n",
    "            + self.year + '.'\n",
    "    def writebibalph(self):\n",
    "        self.sortentriesalph()\n",
    "        output=''\n",
    "        for i in self.entries:\n",
    "            output = output+i.writebibalph()+\"\\n\\n\"\n",
    "        return output\n",
    "    def sortentriesalph(self):\n",
    "        self.entries = sorted(self.entries,key=op.attrgetter('authlast','authfirst'))\n",
    "beauty = Book(\"Dubay\",\"Thomas\" \\\n",
    "             , \"The Evidential Power of Beauty\" \\\n",
    "             , \"San Francisco\" \\\n",
    "             , \"Ignatius Press\", \"1999\")\n",
    "\n",
    "pynut = Book(\"Martelli\", \"Alex\" \\\n",
    "            , \"Python in a Nutshell\" \\\n",
    "            , \"Sebastopol, CA\" \\\n",
    "            , \"O'Reilly Media, Inc.\", \"2003\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's say we have a series of instances of the Book and Article classes that we want to pull together into one big bibliography. We'll create a new class called <b>Bibliography</b> for this task, and within Bibliography's definition will be two modules: one that initializes the class with everything we need, and one that sorts all entries alphabetically.\n",
    "\n",
    "To do this, we'll need some additional tools. One useful package to import here is called <b>operator</b>, which contains a useful function called <b>attrgetter</b>, which will pull a list of attributes out of an item in question. There are other ways of doing the same thing, but operator.attrgetter() will save us a lot of time! \n",
    "\n",
    "We'll also want to make use of <b>sorted()</b>, which is a function that sorts all entries (either alphabetically or numerically) according to a key we specify, which in this case will be the last name and the first name of the author (just in case we have multiple authors with the same last name)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We'll need the operator package.\n",
    "import operator as op\n",
    "\n",
    "\n",
    "# Define our Bibliography class.\n",
    "class bib(object):\n",
    "    # Initialize the class.\n",
    "    def __init__(self,entries):\n",
    "        self.entries = entries\n",
    "        \n",
    "    # Sort the entries alphabetically.\n",
    "    def sortentriesalph(self):\n",
    "        self.entries = sorted(self.entries,key=op.attrgetter('authlast','authfirst'))\n",
    "    # Now, write a bibliography in alphabetical order.\n",
    "    def writebibalph(self):\n",
    "        self.sortentriesalph()\n",
    "        output=''\n",
    "        for i in self.entries:\n",
    "            output = output+i.writebibalph()+\"\\n\\n\"\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Book' object has no attribute 'entries'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m/home/nik/data/python/notebooks/Week 06 M.ipynb Cell 9\u001b[0m line \u001b[0;36m2\n\u001b[1;32m      <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=0'>1</a>\u001b[0m a \u001b[39m=\u001b[39m bib([beauty,pynut,tornado])\n\u001b[0;32m----> <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=1'>2</a>\u001b[0m b \u001b[39m=\u001b[39m a\u001b[39m.\u001b[39;49mwritebibalph()\n\u001b[1;32m      <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=2'>3</a>\u001b[0m \u001b[39mprint\u001b[39m(b)\n",
      "\u001b[1;32m/home/nik/data/python/notebooks/Week 06 M.ipynb Cell 9\u001b[0m line \u001b[0;36m1\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=16'>17</a>\u001b[0m output\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=17'>18</a>\u001b[0m \u001b[39mfor\u001b[39;00m i \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mentries:\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=18'>19</a>\u001b[0m     output \u001b[39m=\u001b[39m output\u001b[39m+\u001b[39mi\u001b[39m.\u001b[39;49mwritebibalph()\u001b[39m+\u001b[39m\u001b[39m\"\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m\\n\u001b[39;00m\u001b[39m\"\u001b[39m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=19'>20</a>\u001b[0m \u001b[39mreturn\u001b[39;00m output\n",
      "\u001b[1;32m/home/nik/data/python/notebooks/Week 06 M.ipynb Cell 9\u001b[0m line \u001b[0;36m2\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=18'>19</a>\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mwritebibalph\u001b[39m(\u001b[39mself\u001b[39m):\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=19'>20</a>\u001b[0m     \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49msortentriesalph()\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=20'>21</a>\u001b[0m     output\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=21'>22</a>\u001b[0m     \u001b[39mfor\u001b[39;00m i \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mentries:\n",
      "\u001b[1;32m/home/nik/data/python/notebooks/Week 06 M.ipynb Cell 9\u001b[0m line \u001b[0;36m2\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=24'>25</a>\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39msortentriesalph\u001b[39m(\u001b[39mself\u001b[39m):\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/nik/data/python/notebooks/Week%2006%20M.ipynb#X11sZmlsZQ%3D%3D?line=25'>26</a>\u001b[0m     \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mentries \u001b[39m=\u001b[39m \u001b[39msorted\u001b[39m(\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mentries,key\u001b[39m=\u001b[39mop\u001b[39m.\u001b[39mattrgetter(\u001b[39m'\u001b[39m\u001b[39mauthlast\u001b[39m\u001b[39m'\u001b[39m,\u001b[39m'\u001b[39m\u001b[39mauthfirst\u001b[39m\u001b[39m'\u001b[39m))\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'Book' object has no attribute 'entries'"
     ]
    }
   ],
   "source": [
    "a = bib([beauty,pynut,tornado])\n",
    "b = a.writebibalph()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Why did we bother doing this? Because it really highlights the power of OOP over traditional, procedural programming. In a lot of languages, we'd have to write a function to format every source entry correctly, depending on the source type (e.g., article or book), which would result in a tree of <b>if</b> tests.\n",
    "\n",
    "Another big advantage? Adding another source type would require <b>no changes or additions to existing code</b>, just a new class definition."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>13.2 OOP Example: Creating a Class for Geoscience Work</h2>\n",
    "\n",
    "Let's work through another application: as an example, we'll define a class called <b>SurfaceDomain</b> that describes surface domain instances. A domain would be a land/ocean surface where the spatial extent is described by a latitude-longitude grid. We'll instantiate the class by providing a vector of longitudes and latitudes; our surface domain will be a regular grid based on those vectors. We can then assign surface parameters (e.g., elevation, temperature, roughness, etc.) as instance attributes.\n",
    "\n",
    "It may be helpful here to think of how best to represent a latitude-longitude grid in code. Let's look at the following example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's say we have 5 longitude values and 4 latitude values.\n",
    "# We want something that's going to look like the following:\n",
    "\n",
    "# Longitude should look like this:\n",
    "\n",
    "[[0 1 2 3 4]\n",
    " [0 1 2 3 4]\n",
    " [0 1 2 3 4]\n",
    " [0 1 2 3 4]]\n",
    "\n",
    "# Latitude should look like this:\n",
    "\n",
    "[[0 0 0 0 0]\n",
    " [1 1 1 1 1]\n",
    " [2 2 2 2 2]\n",
    " [3 3 3 3 3]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There's a function in NumPy built in for this called <b>meshgrid</b>: given a longitude array and a latitude array, it will create a nice grid combining the two.\n",
    "\n",
    "Let's start our class definition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "class SurfaceDomain(object):\n",
    "        def __init__(self, lon, lat):\n",
    "        \n",
    "        # Let's make sure that latitude and longitude \n",
    "                self.lon = np.array(lon)\n",
    "                self.lat = np.array(lat)\n",
    "                [xall,yall] = np.meshgrid(self.lon,self.lat)\n",
    "                self.lonall = xall\n",
    "                self.latall = yall\n",
    "                del xall,yall\n",
    "        # are in array format.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can then begin to manipulate elements of this domain individually or collectively (e.g., interpolation, etc.)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3 4 5]\n",
      " [1 2 3 4 5]\n",
      " [1 2 3 4 5]\n",
      " [1 2 3 4 5]]\n",
      "[[0 0 0 0 0]\n",
      " [1 1 1 1 1]\n",
      " [2 2 2 2 2]\n",
      " [3 3 3 3 3]]\n"
     ]
    }
   ],
   "source": [
    "lon = [1,2,3,4,5]\n",
    "lat = [0,1,2,3]\n",
    "\n",
    "a = SurfaceDomain(lon,lat)\n",
    "print(a.lonall)\n",
    "print(a.latall)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>13.3 Take-Home Points</h2>\n",
    "<ul>\n",
    "    <li>The <b>operator</b> package enables us to use a function called <b>attrgetter()</b> to grab attribute information from various classes.</li>\n",
    "    <li>The <b>sorted()</b> function lets us sort data alphabetically or numerically as needed.</li>\n",
    "    <li>NumPy's <b>meshgrid()</b> module lets us create a grid from lat/lon vectors.</li> \n",
    "</ul>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "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.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}