├── .gitattributes ├── .gitignore ├── 01_Basic_Data_Analysis_and_Visualization.ipynb ├── 02_Science_Data_Formats_and_Advanced_Plotting.ipynb ├── 03_Remote_Datasets_and_Exporting.ipynb ├── LICENSE.md ├── README.md ├── Solutions_to_Exercises.ipynb ├── data ├── 20200901_20200930_Monterey.lev15.csv ├── JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc ├── MOP03JM-201811-L3V95.6.3_thinned.nc ├── VIIRSNDE_global2020258.v1.0.txt ├── gfs_3_20200915_0000_000.grb2 └── sst.mon.ltm.1981-2010.nc ├── environment.yml ├── img └── flowchart.png └── sample_script.py /.gitattributes: -------------------------------------------------------------------------------- 1 | 01_Basic_Data_Analysis_and_Visualization.ipynb filter=strip-notebook-output 2 | 02_Science_Data_Formats_and_Advanced_Plotting.ipynb filter=strip-notebook-output 3 | 03_Remote_Datasets_and_Exporting.ipynb filter=strip-notebook-output -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .ipynb_checkpoints/* 3 | satnames.npz 4 | satellites.csv 5 | SRB.png 6 | -------------------------------------------------------------------------------- /01_Basic_Data_Analysis_and_Visualization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Lesson 1: Basic Data Analysis and Visualization \n", 8 | "\n", 9 | "Author: Rebekah Esmaili (rebekah.esmaili@gmail.com)\n", 10 | " \n", 11 | "---\n", 12 | "\n", 13 | "\n", 14 | "## Why Python?\n", 15 | "\n", 16 | "Pros\n", 17 | "\n", 18 | "* General-purpose, cross-platform\n", 19 | "* Free and open source\n", 20 | "* Reasonably easy to learn\n", 21 | "* Expressive and succinct code, forces good style\n", 22 | "* Being interpreted and dynamically typed makes it great for data analysis\n", 23 | "* Robust ecosystem of scientific libraries, including powerful statistical and visualization packages\n", 24 | "* Large community of scientific users and large existing codebases\n", 25 | "* Major investment into Python ecosystem by Earth science research agencies, including NASA, NCAR, UK Met Office, and Lamont-Doherty Earth Observatory. See Pangeo.\n", 26 | "* Reads Earth science data formats like HDF, NetCDF, GRIB\n", 27 | "\n", 28 | "Cons\n", 29 | "\n", 30 | "* Performance penalties for interpreted languages, although many libraries are wrappers for compiled languages. Avoid large loops in favor of matrix/vector operations when possible.\n", 31 | "* Multithreading is limited due to the Global Interpreter Lock, but other parallelism is available\n", 32 | "* See Julia for a modern scientific language which is trying to overcome these challenges\n", 33 | "\n", 34 | "Why you should not use Python 2.7:\n", 35 | "\n", 36 | "* Python 2 reached it's \"end of life\" as of January 2020\n", 37 | "* No more updates or bugfixes\n", 38 | "* No further official support\n", 39 | "* Subtle differences: https://www.geeksforgeeks.org/important-differences-between-python-2-x-and-python-3-x-with-examples/\n", 40 | "\n", 41 | "---\n", 42 | "\n", 43 | "## Lesson Objectives\n", 44 | "\n", 45 | "* You will learn to:\n", 46 | " * Import relevant packages for scientific programming\n", 47 | " * Read ascii data\n", 48 | " * Basic plotting and visualization\n", 49 | " \n", 50 | "---\n", 51 | "\n", 52 | "## Basic Python Syntax" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "The most basic Python command is to write words to the screen. In jupyter notebooks, the result will appear below the line of code. To run the above command in Jupyter notebook, highlight the cell and either chick the run button (►) or press the **Shift** and **Enter** keys" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": null, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "# This is a comment, python will not run this!\n", 69 | "print(\"Hello Earth\")" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "In Python, variables are dynamically allocated, which means that you do not need to declare the type or size prior to storing data in them. Instead, Python will automatically guess the variable type based on the content of what you are assigning:" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "var_int = 8\n", 86 | "var_float = 15.0\n", 87 | "var_scifloat = 4e8\n", 88 | "var_complex = complex(4, 2)\n", 89 | "var_greetings = 'Hello Earth'" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "Python has many built in functions, the syntax is usually:\n", 97 | "\n", 98 | "```\n", 99 | "function_name(inputs)\n", 100 | "```\n", 101 | "You have already used two functions: *print()* and *complex()*. Another useful function is *type()*, will tell us if the variable is an integer, a float, a complex number, or a string. " 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | " type(var_int), type(var_float), type(var_scifloat), type(var_complex), type(var_greetings)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "Python has the following built-in operators:\n", 118 | "\n", 119 | "* Addition, subtraction, multiplication, division: +, -, *, /\n", 120 | "* Exponential, integer division, modulus: \\**, //, %\n", 121 | "\n" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "2+2.0, var_int**2, var_float//var_int, var_float%var_int" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "---\n", 138 | "\n", 139 | "**Exercise 1:** Learning to use notebooks\n", 140 | "\n", 141 | "1. Launch Jupyter Notebook and create a new notebook\n", 142 | "2. Rename the notebook\n", 143 | "3. Create a new cell and use *type()* to see if the following are floats and integers:\n", 144 | " * 2+2\n", 145 | " * 2\\*2.0\n", 146 | " * var_float/var_int\n", 147 | "---\n", 148 | "**Solution:**" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "## Working with lists\n", 163 | "\n", 164 | "Lists are useful for storing scientific data. Lists are made using square brackets. They can hold any data type (integers, floats, and strings) and even mixtures of the two." 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": null, 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "numbers_list = [4, 8, 15, 16, 23]" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "You can access elements of the list using the index. Python is zero based, so index 0 retrieves the first element." 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "numbers_list[3]" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "New items can also be appended to the list using the append function, which has the syntax:\n", 197 | "\n", 198 | "```\n", 199 | "variable.function(element(s))\n", 200 | "```\n", 201 | "The list will be updated *in-place*." 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "numbers_list.append(42)\n", 211 | "print(numbers_list)" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "Perhaps we want to calculate the sum of the values in two lists. However, we cannot use the *+* like we did with single values. For list objects, the + will *combine* lists." 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "numbers_list" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "To perform mathematical operations, you can convert the above list to an array using the NumPy package." 235 | ] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "metadata": {}, 240 | "source": [ 241 | "### Importing Packages\n", 242 | "\n", 243 | "Packages are collection of modules, which help simplify common tasks. [NumPy](https://numpy.org/) is useful for mathematical operations and array manipulation.\n", 244 | "\n", 245 | "\n", 246 | "* Provides a high-performance multidimensional array object and tools for working with these arrays.\n", 247 | "* Fundamental package for scientific computing with Python.\n", 248 | "* Included with with the Anaconda package manager.\n", 249 | "* For more examples than presented below, please refer [the NumPy Quick Start](https://numpy.org/devdocs/user/quickstart.html)\n", 250 | "\n", 251 | "The basic syntax for calling packages is to type the import \\[package name\\]. However, some packages have long names, so you can use import \\[package name\\] as \\[alias\\]." 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": null, 257 | "metadata": {}, 258 | "outputs": [], 259 | "source": [ 260 | "import numpy as np" 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "If you do not see any error after running the line above, then the package was successfully imported.\n", 268 | "### Working with arrays\n", 269 | "\n", 270 | "I can use NumPy’s array constructor *np.array()* to convert our list to a NumPy array and perform the matrix multiplication. For example, I can double each element of the array:" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": null, 276 | "metadata": {}, 277 | "outputs": [], 278 | "source": [ 279 | "numbers_array = np.array(numbers_list)\n", 280 | "numbers_array*2" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "Another difference between arrays and lists is that lists are only one-dimensional. NumPy can be any number of dimensions. For example, I can change the dimensions of the data using the *reshape()* function:" 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": null, 293 | "metadata": {}, 294 | "outputs": [], 295 | "source": [ 296 | "numbers_array_2d = numbers_array.reshape(3,2)\n", 297 | "numbers_array_2d" 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": null, 303 | "metadata": {}, 304 | "outputs": [], 305 | "source": [ 306 | "numbers_array_2d.shape" 307 | ] 308 | }, 309 | { 310 | "cell_type": "markdown", 311 | "metadata": {}, 312 | "source": [ 313 | "The original numbers_array had 6 elements in a 1D array, the new array is 2D with 3 rows and 2 columns." 314 | ] 315 | }, 316 | { 317 | "cell_type": "markdown", 318 | "metadata": {}, 319 | "source": [ 320 | "### Reading ASCII data\n", 321 | "\n", 322 | "The Pandas package has a useful function for reading text/ascii data called *read_csv()*. The function name is somewhat a misnomer, as *read_csv* will read any delimited data using the *delim=* keyword argument. Below, you will import the [Pandas](https://pandas.pydata.org/) package and we will read in a dataset. Note that the path below is relative to the current notebook and you may have to change the code if you are running locally on your computer:\n", 323 | "\n", 324 | "```\n", 325 | "data/VIIRSNDE_global2020258.v1.0.txt\n", 326 | "```\n", 327 | "\n", 328 | "We will look at the Visible Infrared Imaging Radiometer Suite (VIIRS) Active Fire product, a product that classifies if a pixel contains fire with various confidence levels. More information can be found at https://www.ospo.noaa.gov/Products/land/fire.html. We will examine the data on Sept 15, 2020 (day of year 258)." 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "import pandas as pd" 338 | ] 339 | }, 340 | { 341 | "cell_type": "markdown", 342 | "metadata": {}, 343 | "source": [ 344 | "The default seperator is a comma (,), however my data also contains space. I use the \"\\s*\" to indicate space following the comma should be ignored. The engine=\"python\" keyword ensures that this will work across different operating systems." 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": null, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "fname = \"data/VIIRSNDE_global2020258.v1.0.txt\"\n", 354 | "fires = pd.read_csv(fname, sep=',\\s*', engine='python')" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "You can inspect the contents within the notebook using the *head()* function, which will return the first five rows of the dataset. Pandas automatically stores data in structures called *DataFrames*. DataFrames are two dimensional (rows and columns) and resemble a spreadsheet. The leftmost column is the row index and is not part of the *fires* dataset. " 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "fires.head()" 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": {}, 376 | "source": [ 377 | "You can access individual columns of data using the column name. For example, below you can extract the pixel brightness temperature (brt):" 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": null, 383 | "metadata": {}, 384 | "outputs": [], 385 | "source": [ 386 | "fires[\"brt_t13(K)\"]" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "---\n", 394 | "\n", 395 | "**Exercise 2:** Import an ascii file\n", 396 | "\n", 397 | "1. Import the dataset \"20200901_20200930_Monterey.lev15.csv\" and save it to a variable called *aeronet*.\n", 398 | "2. Print the first few lines using *.head()*\n", 399 | "3. Find a column that doesn't have only missing values (-999) and (challenge!) calculate the mean using the following syntax *variable\\[\"column\"\\].mean()*\n", 400 | "---\n", 401 | "**Solution:**" 402 | ] 403 | }, 404 | { 405 | "cell_type": "code", 406 | "execution_count": null, 407 | "metadata": {}, 408 | "outputs": [], 409 | "source": [] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": {}, 414 | "source": [ 415 | "### Working with masks and masked arrays\n", 416 | "\n", 417 | "When working with data, sometimes there are numbers I want to remove. For instance, I may want to work with data below a certain threshold. You can subset the data using identity operations:\n", 418 | "\n", 419 | "* less than: <\n", 420 | "* less than or equal to: <=\n", 421 | "* greater than: >\n", 422 | "* greater than or equal to: >=\n", 423 | "* equals: ==\n", 424 | "* not equals: !=\n", 425 | "\n", 426 | "Their use will return either a True or False statement. For the *fires* dataset, you can find which elements of the array that meet some condition, such as only examining larger fires that have a Fire Radiative Power (FRP) above 50 MW:" 427 | ] 428 | }, 429 | { 430 | "cell_type": "code", 431 | "execution_count": null, 432 | "metadata": {}, 433 | "outputs": [], 434 | "source": [ 435 | "masked_nums = (fires['frp(MW)'] > 50)\n", 436 | "print(masked_nums)" 437 | ] 438 | }, 439 | { 440 | "cell_type": "markdown", 441 | "metadata": {}, 442 | "source": [ 443 | "Sometimes you may want to filter by two conditions. For example, insteading of filtering the FRP data, you may only want to examine values within a latitude and longitude domain. In Python, I can combine multiple conditions using and (&) and or (|) statements. Below, I extract the data in 5°x5° box arond Monterey, California:" 444 | ] 445 | }, 446 | { 447 | "cell_type": "code", 448 | "execution_count": null, 449 | "metadata": {}, 450 | "outputs": [], 451 | "source": [ 452 | "masked_nums = (fires['Lat'] > 35.0) & (fires['Lat'] < 40.0) & (fires['Lon'] > -125.0) & (fires['Lon'] < -120.0)\n", 453 | "print(masked_nums)" 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "metadata": {}, 459 | "source": [ 460 | "The above mask can be used in place of an index. Below, you can create a new variable that takes the FRP using the *fires\\['frp(MW)'\\]* variable and subsets it with the array of *masked_nums*:" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": null, 466 | "metadata": {}, 467 | "outputs": [], 468 | "source": [ 469 | "monterey_fires = fires['frp(MW)'][masked_nums]\n", 470 | "print(monterey_fires)" 471 | ] 472 | }, 473 | { 474 | "cell_type": "markdown", 475 | "metadata": {}, 476 | "source": [ 477 | "From this new variable, you can compute the average in this region and compare them to the global average for that day:" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": null, 483 | "metadata": {}, 484 | "outputs": [], 485 | "source": [ 486 | "monterey_fires.mean(), fires['frp(MW)'].mean()" 487 | ] 488 | }, 489 | { 490 | "cell_type": "markdown", 491 | "metadata": {}, 492 | "source": [ 493 | "You can use the size command to compare the dimensions of original array and the one that filtered out values that were outside of our latitude and longitude bounds. You will notice that these two arrays have different sizes." 494 | ] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "execution_count": null, 499 | "metadata": {}, 500 | "outputs": [], 501 | "source": [ 502 | "fires['frp(MW)'].size, monterey_fires.size" 503 | ] 504 | }, 505 | { 506 | "cell_type": "markdown", 507 | "metadata": {}, 508 | "source": [ 509 | "There are cases where you will want to preserve the size and shape of the original array. For these situations, you can utilize the NumPy *masked array* module. The syntax is *np.ma.array()*, and you will add a keyword argument *mask=*, which is set to the inverse (~) of the *mask_nums*." 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": null, 515 | "metadata": {}, 516 | "outputs": [], 517 | "source": [ 518 | "monterey_fires_ma = np.ma.array(fires['frp(MW)'], mask=~masked_nums, fill_value=-999)\n", 519 | "monterey_fires_ma" 520 | ] 521 | }, 522 | { 523 | "cell_type": "markdown", 524 | "metadata": {}, 525 | "source": [ 526 | "Then, you can calculate the mean values and confirm that they are the same as the previous example:" 527 | ] 528 | }, 529 | { 530 | "cell_type": "code", 531 | "execution_count": null, 532 | "metadata": {}, 533 | "outputs": [], 534 | "source": [ 535 | "monterey_fires_ma.mean()" 536 | ] 537 | }, 538 | { 539 | "cell_type": "markdown", 540 | "metadata": {}, 541 | "source": [ 542 | "However, the key difference will be the size, which retains the shape of the unmasked data:" 543 | ] 544 | }, 545 | { 546 | "cell_type": "code", 547 | "execution_count": null, 548 | "metadata": {}, 549 | "outputs": [], 550 | "source": [ 551 | "monterey_fires_ma.size" 552 | ] 553 | }, 554 | { 555 | "cell_type": "markdown", 556 | "metadata": {}, 557 | "source": [ 558 | "---\n", 559 | "**Exercise 3:** Filtering data\n", 560 | "\n", 561 | "Using the dataset imported in the previous example (*aeronet*):\n", 562 | " \n", 563 | "1. Create a mask that filters the \"AOD_870nm\" column to only include values that are above 0.\n", 564 | "2. Create a new variables, *day_of_year*, with the mask applied to aeronet\\[\"Day_of_Year(Fraction)\"\\].\n", 565 | "3. Create a new variables, *aod_870*, with the mask applied to aeronet\\[\"AOD_870nm\"\\].\n", 566 | "4. Compare the mean value of *aeronet\\[\"AOD_870nm\"\\]* to *aod_870*.\n", 567 | " \n", 568 | "---\n", 569 | "**Solution**" 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": null, 575 | "metadata": {}, 576 | "outputs": [], 577 | "source": [] 578 | }, 579 | { 580 | "cell_type": "markdown", 581 | "metadata": {}, 582 | "source": [ 583 | "### Basic figures and plots\n", 584 | "\n", 585 | "Python has several packages to create visuals for remote sensing data, either in the form of imagery or plots of relevant analysis. Of these, the most widely used and oldest packages is [Matplotlib](https://matplotlib.org/). Matplotlib plots are highly customizable and has additional toolkits that can enhance functionality, such as creating maps using the [Cartopy](https://scitools.org.uk/cartopy/docs/latest/) package, which I will describe more in the next session.\n" 586 | ] 587 | }, 588 | { 589 | "cell_type": "code", 590 | "execution_count": null, 591 | "metadata": {}, 592 | "outputs": [], 593 | "source": [ 594 | "import matplotlib.pyplot as plt" 595 | ] 596 | }, 597 | { 598 | "cell_type": "markdown", 599 | "metadata": {}, 600 | "source": [ 601 | "Suppose you want to learn what the global distribution of fire radiative power is. From inspecting the frp(MW) column earlier, these values extend to many decimal places. Rather than use a continuous scale, I can instead group in the data into 10 MW bins, from 0 to 500 MW:" 602 | ] 603 | }, 604 | { 605 | "cell_type": "code", 606 | "execution_count": null, 607 | "metadata": {}, 608 | "outputs": [], 609 | "source": [ 610 | "bins10MW = np.arange(0, 500, 10)" 611 | ] 612 | }, 613 | { 614 | "cell_type": "markdown", 615 | "metadata": {}, 616 | "source": [ 617 | "I can use these bins to create a histogram. Line by line, the code below will do as follows. Each additional line is layering elements on this empty graphic. The entire block of code must be run at once and not split into multiple cells. \n", 618 | "\n", 619 | "1. *plt.figure()* creates a blank canvas.\n", 620 | "2. I add the histogram to the figure using *plt.hist()*, which automatically will count the number of rows with fire radiative power in the bins that I defined above in the bins10W variable. I must then pass in the data (fires['frp(MW)']) and the bins (bins10MW) into plt.hist. \n", 621 | "3. *plt.show()* tells matplotlib the plot is now complete and to render it:" 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": null, 627 | "metadata": {}, 628 | "outputs": [], 629 | "source": [ 630 | "plt.figure(figsize=[5,5])\n", 631 | "plt.hist(fires['frp(MW)'], bins=bins10MW)\n", 632 | "plt.show()" 633 | ] 634 | }, 635 | { 636 | "cell_type": "markdown", 637 | "metadata": {}, 638 | "source": [ 639 | "Below, you will remake this plot but add some aesthetic additions, such as labels to the x and y axis using *set_xlabel()* and *set_ylabel()*. Since there are thousands more fires with fire radiative power less than 100 MW than fires with higher values the data are likely lognormal. The plot will be easier to interpret of I rescale the y-axis to a log scale while leaving the x-axis linear.\n", 640 | "\n", 641 | "The command *plt.subplot()* will return an axis object to a variable (*ax*). There are three numbers passed in (111), which correspond to rows, columns, and index. In this example, there is one row and one column, and therefore, only one index." 642 | ] 643 | }, 644 | { 645 | "cell_type": "code", 646 | "execution_count": null, 647 | "metadata": {}, 648 | "outputs": [], 649 | "source": [ 650 | "plt.figure()\n", 651 | "\n", 652 | "ax = plt.subplot(111)\n", 653 | "\n", 654 | "ax.hist(fires['frp(MW)'], bins=bins10MW)\n", 655 | "\n", 656 | "ax.set_yscale('log')\n", 657 | "\n", 658 | "ax.set_xlabel(\"Fire Radiative Power (MW)\")\n", 659 | "ax.set_ylabel(\"Counts\")\n", 660 | "\n", 661 | "plt.show()" 662 | ] 663 | }, 664 | { 665 | "cell_type": "markdown", 666 | "metadata": {}, 667 | "source": [ 668 | "You can also plot the data in 2-dimensions. For example, each row in *fires* has a latitude and longitude coordinates pair. I will take these two coordinates and plot using *plt.scatter()*. The first argument is the x-coordinate and the second is the y-coordinate (the order matters). \n", 669 | "\n", 670 | "There are some command line options *plt.scatter()*:\n", 671 | "\n", 672 | "* s: size with respect to the default\n", 673 | "* c: color, which can be either from a predefined name list or a hexadecimal value\n", 674 | "* alpha: opacity, where smaller values are transparent.\n", 675 | "\n", 676 | "Like in the previous example, I have chosen to label the latitude and longitude axes:" 677 | ] 678 | }, 679 | { 680 | "cell_type": "code", 681 | "execution_count": null, 682 | "metadata": {}, 683 | "outputs": [], 684 | "source": [ 685 | "fig = plt.figure()\n", 686 | "ax = plt.subplot(111)\n", 687 | "\n", 688 | "ax.scatter(fires['Lon'], fires['Lat'], s=0.5, c='black', alpha=0.1)\n", 689 | "\n", 690 | "ax.set_xlabel('Longitude')\n", 691 | "ax.set_ylabel('Latitude')\n", 692 | "\n", 693 | "plt.show()" 694 | ] 695 | }, 696 | { 697 | "cell_type": "markdown", 698 | "metadata": {}, 699 | "source": [ 700 | "You can almost see the outline of the continents from the data above. In the next session, you will learn how to overlay maps onto your plots." 701 | ] 702 | }, 703 | { 704 | "cell_type": "markdown", 705 | "metadata": {}, 706 | "source": [ 707 | "---\n", 708 | "**Exercise 4:** Create a scatterplot\n", 709 | "\n", 710 | "Use the variables *aod_870* and *day_of_year* that you made in Exercise 3 to:\n", 711 | "\n", 712 | "1. Create a scatter plot showing the *day_of_year* (x-axis) and *aod_870* (y-axis)\n", 713 | "2. Add y-axis and x-axis labels using *.set_xlabel()* and *.set_ylabel()*\n", 714 | "3. Adjust the color and size of the scatterplot\n", 715 | "---\n", 716 | "**Solution**" 717 | ] 718 | }, 719 | { 720 | "cell_type": "code", 721 | "execution_count": null, 722 | "metadata": {}, 723 | "outputs": [], 724 | "source": [] 725 | }, 726 | { 727 | "cell_type": "markdown", 728 | "metadata": {}, 729 | "source": [ 730 | "## Summary:\n", 731 | "\n", 732 | "You learned:\n", 733 | "* Very basic built-in Python functions and operations\n", 734 | "* How to import three packages: numpy, pandas, and matplotlib\n", 735 | "* Worked with arrays and lists\n", 736 | "* How to create a simple plot\n", 737 | "\n", 738 | "Next lesson:\n", 739 | "* More advanced plots, such as using maps\n", 740 | "* Importing scientific datasets, such as netcdf and grib" 741 | ] 742 | }, 743 | { 744 | "cell_type": "code", 745 | "execution_count": null, 746 | "metadata": {}, 747 | "outputs": [], 748 | "source": [] 749 | } 750 | ], 751 | "metadata": { 752 | "kernelspec": { 753 | "display_name": "Python 3.11.0 ('notebook_demo')", 754 | "language": "python", 755 | "name": "python3" 756 | }, 757 | "language_info": { 758 | "codemirror_mode": { 759 | "name": "ipython", 760 | "version": 3 761 | }, 762 | "file_extension": ".py", 763 | "mimetype": "text/x-python", 764 | "name": "python", 765 | "nbconvert_exporter": "python", 766 | "pygments_lexer": "ipython3", 767 | "version": "3.11.0" 768 | }, 769 | "vscode": { 770 | "interpreter": { 771 | "hash": "4589143d4cda0c8671911bd60c16dc1d10ec327722e7574bc882b745b51509b4" 772 | } 773 | } 774 | }, 775 | "nbformat": 4, 776 | "nbformat_minor": 4 777 | } 778 | -------------------------------------------------------------------------------- /02_Science_Data_Formats_and_Advanced_Plotting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Lesson 2: Scientific Data Formats and Advanced Plotting\n", 8 | "\n", 9 | "Author: Rebekah Esmaili (rebekah.esmaili@gmail.com)\n", 10 | " \n", 11 | "---\n", 12 | "\n", 13 | "## Lesson Objectives\n", 14 | "* You will learn to:\n", 15 | " * Import relevant packages for scientific programming\n", 16 | " * Read netCDF and GRIB2 data\n", 17 | " * Creating plots and maps\n", 18 | " \n", 19 | "\n", 20 | "![](img/flowchart.png)\n", 21 | "\n" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "\n", 29 | "## Importing NetCDF files\n", 30 | "\n", 31 | "NetCDF and HDF are self-describing formats, which are structured binary data files and useful for storing other big datasets. Computationally, it is faster to read in binary-based datasets than text, which needs to be parsed before being stored into a computer’s memory. Because the files are more compact, they are cheaper to store large, long-term satellite data. Furthermore, information about the data (\"metadata\") can be stored inside the file themselves.\n", 32 | "\n", 33 | "Datasets:\n", 34 | "* JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc: A netCDF file that contains Aerosol Optical Depth (AOD) retrieved from a Suomi NPP overpass on 2020 9 Aug. For this workshop, unused fields were removed.\n", 35 | "* gfs_3_20200915_0000_000.grb2: A GRIB2 file that contains GFS analysis\n", 36 | "* MOP03JM-201811-L3V95.6.3_thinned.nc: The Nov 2018 CO monthly mean from the Measurement of Pollution in the Troposphere (MOPITT), which is an instrument on the Terra satellite.\n", 37 | " * NOTE: For this tutorial, the file was converted to a netCDF4 file and unused variable fields were removed. The original file is HDF5 MOP03JM-201811-L3V95.6.3.he5 and can be obtained from https://earthdata.nasa.gov/.\n", 38 | "* [NOAA Extended Reconstructed SST version 5 dataset (ERSST)](https://psl.noaa.gov/data/gridded/data.noaa.ersst.v5.html). Shows the global monthly mean ocean surface temperature from 1854-present using data collected from ocean buoys, ships, and climate modeled data.\n", 39 | "\n", 40 | "Many environmental dataset names are quite long. However, the dataset name is encoded to give us information about the contents. For example:\n", 41 | "\n", 42 | "```\n", 43 | "JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150.nc\n", 44 | "```\n", 45 | "You can learn several important features of the dataset without opening it:\n", 46 | "\n", 47 | "* Prefix indicates the mission (JRR, for JPSS Risk Reduction)\n", 48 | "* Product (Aerosol Optical Depth, or AOD), algorithm version\n", 49 | "* Revision number (v1r1)\n", 50 | "* Satellite source (j01 for JPSS-1/NOAA-20)\n", 51 | "* Start (s), end (e), and creation (c) time, which are each followed by the year, month, day, hour, minute, and seconds (to one decimal place). \n", 52 | "\n", 53 | "First, import three commonly used packages in Python:" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "import numpy as np\n", 63 | "import pandas as pd\n", 64 | "import matplotlib.pyplot as plt" 65 | ] 66 | }, 67 | { 68 | "attachments": {}, 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "To begin, you need to first import [xarray](http://xarray.pydata.org/en/stable/io.html) which is tailored to open netCDF4 files and work with large arrays (like numpy and pandas). The [netCDF4 package](https://unidata.github.io/netcdf4-python/netCDF4/index.html) can also be used to import files. The [h5netcdf](https://github.com/h5netcdf/h5netcdf) is useful because it combines features of both netcdf4 and h5py so you can use one reader for two different file types." 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "import xarray as xr" 82 | ] 83 | }, 84 | { 85 | "attachments": {}, 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "Use the open_dataset function to import the above dataset. The engine option is used to read the files. Some possible file readers are \"netcdf4\", \"scipy\", \"pydap\", \"h5netcdf\", \"pynio\", \"cfgrib\", \"pseudonetcdf\", \"zarr\" but you also must have the packages installed. IN " 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "fname='data/JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc'\n", 99 | "aod_file_id = xr.open_dataset(fname, engine='h5netcdf')" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "If you print the contents of the file_id variable, you will get a long list of the global attributes, variables, dimensions, and much more." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "aod_file_id" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "The output above is worth inspecting. Inside Jupyter Notebooks, xarray allows you to inspect the file contents. Clicking on the arrows will show a preview of the metadata. Note that you can also use tools like [Panoply](https://www.giss.nasa.gov/tools/panoply/) to inspect the contents of the netCDF file outside of Python.\n", 123 | "\n", 124 | "* __Dimensions__: The dimensions are named Rows and Columns, which are respectively 768 and 3200.\n", 125 | "\n", 126 | "* __Coordinates__: The coordinates are Latitude and Longitude. These are both two dimensions.\n", 127 | "\n", 128 | "* __Variables__: This file has only one variable, which is AOD550. It's dimensions are also Rows and Columns.\n", 129 | "\n", 130 | "* __Attributes__: netCDF4 [CF-1.5 conventions](https://cfconventions.org/). Some of the information that we saw in the file name is also present: this product is the *JPSS Risk Reduction Unique Aerosol Optical Depth* (title) *Level 2* product (processing_level) and the data was collected from the *NOAA-20* (satellite_name) *VIIRS* instrument (instrument_name). The *start* (time_coverage_start) and *end* times (time_coverage_end) metadata fields are consistent with the filename. I recommend that you read netCDF file header contents, especially the first time you are working with new data. " 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "AOD is a unitless measure of the extinction of solar radiation by particles suspended in the atmosphere. High values of AOD can indicate the presence of dust, smoke, or another air pollutant while low values indicate a cleaner atmosphere.\n", 138 | "\n", 139 | "Xarray syntax will resemble both Pandas and Numpy. Unlike numpy, N-D arrays can be labeled. Instead of having to remember indices numbers, we can extract elements using their coordinate or variables names.\n", 140 | "\n", 141 | "Below I'll extract three important variables: AOD550, Latitude, and Longitude:" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "AOD_550 = aod_file_id['AOD550']\n", 151 | "AOD_lat = aod_file_id['Latitude']\n", 152 | "AOD_lon = aod_file_id['Longitude']" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "Let's print AOD_550 below. This variable contains only a portion of the original data array:" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": {}, 166 | "outputs": [], 167 | "source": [ 168 | "AOD_550" 169 | ] 170 | }, 171 | { 172 | "cell_type": "markdown", 173 | "metadata": {}, 174 | "source": [ 175 | "Xarray uses NumPy as a dependency so so we can use numpy functions like *.mean()*. First we have to make sure it's in the right format. If you check the type of *AOD_550*, you can see it's a *numpy.ndarray.*" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": null, 181 | "metadata": {}, 182 | "outputs": [], 183 | "source": [ 184 | "type(AOD_550.values)" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "metadata": {}, 190 | "source": [ 191 | "Xarray handles missing data automatically, so if we do statistics on the array, it will not include them:" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "avgAOD = AOD_550.mean()\n", 201 | "print(avgAOD)" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "---\n", 209 | "**Exercise 1**: Importing netCDF files\n", 210 | "1. Open the file \"MOP03JM-201811-L3V95.6.3_thinned.nc\" using the xarray library\n", 211 | "2. Print the variable names\n", 212 | "3. What are the dimensions?\n", 213 | "---\n", 214 | "\n", 215 | "**Solution:**" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": null, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "## Importing GRIB2 files\n", 230 | "\n", 231 | "GRIB2 files is a binary datasets that take on a table-driven code form. \"Table driven\" means that the files require external tables to decode the data type. Thus, they are not self-describing. These files follow a methodology of encoding binary data and not a distinct file type. Binary Universal Form for the Representation of meteorological data (BUFR) and GRIdded Binary (GRIB) are two common table-driven formats in Earth Sciences. \n", 232 | "\n", 233 | "American NWS models (e.g. GFS, NAM, and HRRR) and the European (e.g. ECMWF) models are stored in GRIB2. While they share the same format, there are some differences in how each organization stores its data. GRIB2 are stored as binary variables with a header describing the data stored followed by the variable values.\n", 234 | "\n", 235 | "Currently, some of the GRIB2 decoders have problems parsing the American datasets because the American models have multiple pressure dimensions (depending on the variable) while the European models have one. Still, there are ways the data can be inspected by using the pygrib and cfgrib packages." 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "import pygrib" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "The pygrib package (Unidata) has an interface between Python and the GRIB-API (ECMWF). ECMWF has since ended support for the GRIB-API as the primary GRIB2 encoded and decoder and now use ecCodes. However, the package is still maintained by the developer (https://jswhit.github.io/pygrib/) and is useful for parsing NCEP weather forecast data." 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": null, 257 | "metadata": {}, 258 | "outputs": [], 259 | "source": [ 260 | "filename = 'data/gfs_3_20200915_0000_000.grb2'\n", 261 | "gfs_grb2 = pygrib.open(filename)" 262 | ] 263 | }, 264 | { 265 | "cell_type": "markdown", 266 | "metadata": {}, 267 | "source": [ 268 | "This opens the file, but does not extract the elements:" 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": null, 274 | "metadata": {}, 275 | "outputs": [], 276 | "source": [ 277 | "type(gfs_grb2)" 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": {}, 283 | "source": [ 284 | "Below is a *for loop* in Python. The code block below will iterate over each item in the open dataset and append (using *.append*) them to a list (*records*). Note that if you run this command again, you will read to the end of the file, so there will be no result. You will have to re-open the command and re-run the block below.\n", 285 | "\n", 286 | "You can check the size of the final list using *len(messages)*:" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "metadata": {}, 293 | "outputs": [], 294 | "source": [ 295 | "records = []\n", 296 | "for grb in gfs_grb2:\n", 297 | " records.append(str(grb))\n", 298 | " \n", 299 | "len(records)" 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "metadata": {}, 305 | "source": [ 306 | "There are 522 individual data product definition in this file, so first let’s inspect the contents of one line to start:" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "records[12]" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "From the output above, you can see that the colons (:) separate the sections of the product definition in this GRIB2 message. The elements are *index* (1), *variable name* and *units* (2-3), and *spatial*, *vertical*, and *temporal* definitions (4-8). There is one record for each *pressure level* and *time*. You can then extract all variables using the *.select(name=\\[variable\\])* command. Below, you select all the Temperature records (there are 46, which you can see by using the *len(temps)* command). Since it is a long list, you are only printing some of these below:" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [ 331 | "temps = gfs_grb2.select(name='Temperature')" 332 | ] 333 | }, 334 | { 335 | "cell_type": "markdown", 336 | "metadata": {}, 337 | "source": [ 338 | "If you want to extract temperature at 85000 Pa, you can use the index (*315*) to pull that record:" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "temp = gfs_grb2[315]" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "metadata": {}, 353 | "source": [ 354 | "Then, using *.values* you can extract the data from the record:" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": null, 360 | "metadata": {}, 361 | "outputs": [], 362 | "source": [ 363 | "temp.values" 364 | ] 365 | }, 366 | { 367 | "cell_type": "markdown", 368 | "metadata": {}, 369 | "source": [ 370 | "You can also extract the grid information and other import metadata for this record. To see all available information, use the *.keys()* command:" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": null, 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "temp.keys()" 380 | ] 381 | }, 382 | { 383 | "cell_type": "markdown", 384 | "metadata": {}, 385 | "source": [ 386 | "The coordinates can be extracted using the *.latitude* and *.longitude*. You can additionally extract the level, units, and forecast time from the file:" 387 | ] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "execution_count": null, 392 | "metadata": {}, 393 | "outputs": [], 394 | "source": [ 395 | "gfs_lat_all = temp.latitudes\n", 396 | "gfs_lon_all = temp.longitudes\n", 397 | "\n", 398 | "level = temp.level\n", 399 | "units = temp.units\n", 400 | "\n", 401 | "analysis_date = temp.analDate\n", 402 | "fcst_time = temp.forecastTime" 403 | ] 404 | }, 405 | { 406 | "cell_type": "markdown", 407 | "metadata": {}, 408 | "source": [ 409 | "Problem: The shape of the latitude is MUCH bigger than the temperature... why and what can we do about it?" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "temp.values.shape, gfs_lat_all.shape, gfs_lon_all.shape" 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "metadata": {}, 424 | "source": [ 425 | "We can troubleshoot by printing the values. We can see that latitude repeats the values many times." 426 | ] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "execution_count": null, 431 | "metadata": {}, 432 | "outputs": [], 433 | "source": [ 434 | "gfs_lat_all, gfs_lon_all" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "A simple way of fixing this is to use np.unique to remove any duplicating values:" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": null, 447 | "metadata": {}, 448 | "outputs": [], 449 | "source": [ 450 | "gfs_lat = np.unique(gfs_lat_all)\n", 451 | "gfs_lon = np.unique(gfs_lon_all)\n", 452 | "gfs_lat.shape, gfs_lon.shape" 453 | ] 454 | }, 455 | { 456 | "cell_type": "markdown", 457 | "metadata": {}, 458 | "source": [ 459 | "Now that we know how to import multidimensional data, you will make some plots in the next section." 460 | ] 461 | }, 462 | { 463 | "cell_type": "markdown", 464 | "metadata": {}, 465 | "source": [ 466 | "## Plotting 3-dimensional Data\n", 467 | "\n", 468 | "So far, we have only made line and scatter plots. Matplotlib also supports plotting spatial datasets. However, we often have to do perform several array operations to ensure the x, y, and z coordinates are the same shape. Let's work with a Sea Surface Temperature (SST) dataset in the next example and make a 3D plot." 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": null, 474 | "metadata": {}, 475 | "outputs": [], 476 | "source": [ 477 | "import xarray as xr\n", 478 | "\n", 479 | "fname = 'data/sst.mon.ltm.1981-2010.nc'\n", 480 | "sst_file_id = xr.open_dataset(fname, engine='h5netcdf', decode_times=False)" 481 | ] 482 | }, 483 | { 484 | "cell_type": "markdown", 485 | "metadata": {}, 486 | "source": [ 487 | "Like before, you can inspect the contents by typing the variable name:" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": null, 493 | "metadata": {}, 494 | "outputs": [], 495 | "source": [ 496 | "sst_file_id" 497 | ] 498 | }, 499 | { 500 | "cell_type": "markdown", 501 | "metadata": {}, 502 | "source": [ 503 | "From the printed information above, we can see the following:\n", 504 | "\n", 505 | "* __Dimensions__: The dimensions are named lat, lon, and time, which each have the size of 89, 180, and 12.\n", 506 | "\n", 507 | "* __Coordinates__: Are also lat, lon, and time\n", 508 | "\n", 509 | "* __Variables__: Has three variables, climatology_bounds, sst, valid_yr_count." 510 | ] 511 | }, 512 | { 513 | "cell_type": "markdown", 514 | "metadata": {}, 515 | "source": [ 516 | "Let's import *sst* which is a 2-dimensional variable. You will also need lat and lon, which are both one dimensional:" 517 | ] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "execution_count": null, 522 | "metadata": {}, 523 | "outputs": [], 524 | "source": [ 525 | "sst = sst_file_id[\"sst\"]\n", 526 | "sst_lat = sst_file_id[\"lat\"]\n", 527 | "sst_lon = sst_file_id[\"lon\"]" 528 | ] 529 | }, 530 | { 531 | "cell_type": "markdown", 532 | "metadata": {}, 533 | "source": [ 534 | "Let's inspect the shape and see if the data are already formatted for plotting:" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": null, 540 | "metadata": {}, 541 | "outputs": [], 542 | "source": [ 543 | "sst_lat.shape, sst_lon.shape, sst.shape" 544 | ] 545 | }, 546 | { 547 | "cell_type": "markdown", 548 | "metadata": {}, 549 | "source": [ 550 | "Contour plots and mesh plots are two useful ways of looking at 3-dimensional data. Both plots require the x, y, and z coordinates to have the same 2D grid. \n", 551 | "\n", 552 | "The shapes illustrate two problems:\n", 553 | "1. SST has a time dependency, we need to just pick one month from the record because we can't plot all 12 on a single graph\n", 554 | "2. sst is 2D while lat and lon are 1D. You can use *np.meshgrid()* to project the 1-dimensional x and y coordinates into two dimensions\n", 555 | "\n", 556 | "\n", 557 | "Problem #1 can be solved by using the xarray select (.sel) command to select just one month, I'll choose December. The index for December is 11 because python numbering starts at 0." 558 | ] 559 | }, 560 | { 561 | "cell_type": "code", 562 | "execution_count": null, 563 | "metadata": {}, 564 | "outputs": [], 565 | "source": [ 566 | "sst = sst_file_id[\"sst\"].isel(time=11)" 567 | ] 568 | }, 569 | { 570 | "cell_type": "markdown", 571 | "metadata": {}, 572 | "source": [ 573 | "The np.meshgrid function will help with problem #2 above. The function is a little confusing at first, so I'll show a simple example. Suppose you have to simple arrays:" 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": null, 579 | "metadata": {}, 580 | "outputs": [], 581 | "source": [ 582 | "tmp_x = [1,2]\n", 583 | "tmp_y = [3,4,5]" 584 | ] 585 | }, 586 | { 587 | "cell_type": "markdown", 588 | "metadata": {}, 589 | "source": [ 590 | "*tmp_x* has two elements and *tmp_y* has three. If you create a mesh of the two variables, there will be two variables, both with 3 rows and 2 columns: " 591 | ] 592 | }, 593 | { 594 | "cell_type": "code", 595 | "execution_count": null, 596 | "metadata": {}, 597 | "outputs": [], 598 | "source": [ 599 | "np.meshgrid(tmp_x, tmp_y)" 600 | ] 601 | }, 602 | { 603 | "cell_type": "markdown", 604 | "metadata": {}, 605 | "source": [ 606 | "Returning to the example, below is the meshgrid of the 1-dimensional latitude and longitude coordinates:" 607 | ] 608 | }, 609 | { 610 | "cell_type": "code", 611 | "execution_count": null, 612 | "metadata": {}, 613 | "outputs": [], 614 | "source": [ 615 | "X_sst, Y_sst = np.meshgrid(sst_lon, sst_lat)" 616 | ] 617 | }, 618 | { 619 | "cell_type": "markdown", 620 | "metadata": {}, 621 | "source": [ 622 | "Before plotting, you need to check if all the dimensions match. However, after comparing the shape of co to X_co, you can see that the dimensions are flipped:" 623 | ] 624 | }, 625 | { 626 | "cell_type": "code", 627 | "execution_count": null, 628 | "metadata": {}, 629 | "outputs": [], 630 | "source": [ 631 | "sst.shape, X_sst.shape" 632 | ] 633 | }, 634 | { 635 | "cell_type": "markdown", 636 | "metadata": {}, 637 | "source": [ 638 | "We've already learned how to use *plt.subplot()* to generate the empty figure (*fig*) and axis (*ax*). \n", 639 | "\n", 640 | "One line 2, you call *ax.contourf* and input the X_co, Y_co, and transposed co variables. co acts as a color value, which becomes the third dimension of the plot. You then store this object into a variable *co_plot* so that you can pass it into *ax.colorbar* in order to map the colors to numeric values." 641 | ] 642 | }, 643 | { 644 | "cell_type": "code", 645 | "execution_count": null, 646 | "metadata": {}, 647 | "outputs": [], 648 | "source": [ 649 | "# contourf\n", 650 | "fig = plt.figure()\n", 651 | "ax = plt.subplot(111)\n", 652 | "sst_plot = ax.contourf(X_sst, Y_sst, sst)\n", 653 | "fig.colorbar(sst_plot, orientation='horizontal', ax=ax)\n", 654 | "plt.show()" 655 | ] 656 | }, 657 | { 658 | "cell_type": "markdown", 659 | "metadata": {}, 660 | "source": [ 661 | "Like contour plots, mesh plots are also 2-dimensional plots that display 3-dimensions of information using x, y, coordinates and z for a color scale. However, mesh plots do not perform any smoothing and display data as-is on a regular grid. However, since many satellite datasets are swath-based, irregularly spaced data needs to be re-gridded in order to display it as a mesh grid. In the code block below, let’s compare how the sst data looks using pcolormesh command with the previous example using contour. The code below has no other changes to the plot other than the call to the plot type." 662 | ] 663 | }, 664 | { 665 | "cell_type": "code", 666 | "execution_count": null, 667 | "metadata": {}, 668 | "outputs": [], 669 | "source": [ 670 | "#pcolormesh\n", 671 | "fig = plt.figure()\n", 672 | "ax = plt.subplot(111)\n", 673 | "sst_plot = ax.pcolormesh(X_sst, Y_sst, sst, shading='auto')\n", 674 | "fig.colorbar(sst_plot, orientation='horizontal')\n", 675 | "plt.show()" 676 | ] 677 | }, 678 | { 679 | "attachments": {}, 680 | "cell_type": "markdown", 681 | "metadata": {}, 682 | "source": [ 683 | "You might notice that there is more structure in the mesh plot than the filled contour. This is useful if you wish to examine fine structure and patterns.\n", 684 | "\n", 685 | "---\n", 686 | "**Exercise 2**: Plot 3-dimensional data\n", 687 | "\n", 688 | "Plot *AOD_lat*, *AOD_lon*, and *AOD_550* (which we imported from the \"JRR-AOD_v2r3_j01_...\" netCDF file as:\n", 689 | "\n", 690 | "1. Check the dimensions for all variables using *.shape*.\n", 691 | "2. Do you need to generate a meshgrid with *np.meshgrid()*?\n", 692 | "3. Create a contour plot\n", 693 | "\n", 694 | "---\n", 695 | "**Solution:**" 696 | ] 697 | }, 698 | { 699 | "cell_type": "code", 700 | "execution_count": null, 701 | "metadata": {}, 702 | "outputs": [], 703 | "source": [] 704 | }, 705 | { 706 | "attachments": {}, 707 | "cell_type": "markdown", 708 | "metadata": {}, 709 | "source": [ 710 | "## Adding maps to plots\n", 711 | "\n", 712 | "The package [Cartopy](https://scitools.org.uk/cartopy/docs/latest/) add mapping functionality to Matplotlib. Cartopy provides an interface to obtain continent, country, and feature details to overlay onto your plot. Furthermore, Cartopy also enables you to convert your data from one map projection to another, which requires a cartesian coordinate system to the map coordinates. Matplotlib natively supports the six mathematical and map projections (Aitoff, Hammer, Lambert, Mollweide, polar, and rectilinear) and combined with Cartopy, data can be transformed to a total of 33 possible projections." 713 | ] 714 | }, 715 | { 716 | "cell_type": "code", 717 | "execution_count": null, 718 | "metadata": {}, 719 | "outputs": [], 720 | "source": [ 721 | "from cartopy import crs as ccrs" 722 | ] 723 | }, 724 | { 725 | "cell_type": "markdown", 726 | "metadata": {}, 727 | "source": [ 728 | "Just like before, we need to convert the 1D lat and lon coordinates to 2D using meshgrid. We can check the shape to ensure all variables have the same dimensions." 729 | ] 730 | }, 731 | { 732 | "cell_type": "code", 733 | "execution_count": null, 734 | "metadata": {}, 735 | "outputs": [], 736 | "source": [ 737 | "gfs_temp = temp.values\n", 738 | "gfs_x, gfs_y = np.meshgrid(gfs_lon, gfs_lat)\n", 739 | "\n", 740 | "gfs_x.shape, gfs_y.shape, gfs_temp.shape" 741 | ] 742 | }, 743 | { 744 | "cell_type": "code", 745 | "execution_count": null, 746 | "metadata": {}, 747 | "outputs": [], 748 | "source": [ 749 | "fig = plt.figure(figsize=[10,5])\n", 750 | "ax = plt.subplot(projection=ccrs.PlateCarree())\n", 751 | "\n", 752 | "ax.pcolormesh(gfs_x, gfs_y, gfs_temp)\n", 753 | "\n", 754 | "ax.coastlines('50m')\n", 755 | "plt.show()" 756 | ] 757 | }, 758 | { 759 | "cell_type": "markdown", 760 | "metadata": {}, 761 | "source": [ 762 | "In the next example, you can switch from Plate Carrée to Orthographic. You must define the projection twice, once in the *projection=* keyword and again in the *transform=*. In the *plt.subplot* line, you must define the to coordinates (*ccrs.Orthographic*), which is how you want to axes to show the data. In the ax.scatter line, you use the transform keyword argument in scatter to define the from coordinates (Plate Carrée), which are the coordinates that the data formatted for." 763 | ] 764 | }, 765 | { 766 | "cell_type": "code", 767 | "execution_count": null, 768 | "metadata": {}, 769 | "outputs": [], 770 | "source": [ 771 | "fig = plt.figure(figsize=[10,5])\n", 772 | "ax = plt.subplot(projection=ccrs.Orthographic(90, 0))\n", 773 | "\n", 774 | "ax.pcolormesh(gfs_x, gfs_y, gfs_temp, transform=ccrs.PlateCarree())\n", 775 | "\n", 776 | "ax.coastlines('50m')\n", 777 | "plt.show()" 778 | ] 779 | }, 780 | { 781 | "cell_type": "markdown", 782 | "metadata": {}, 783 | "source": [ 784 | "---\n", 785 | "**Exercise 3** Adding maps to plots\n", 786 | "\n", 787 | "Using *sst_lat*, *AOD_lon*, and *AOD_550* (which we imported from the \"JRR-AOD_v2r3_j01_...\" netCDF file)\n", 788 | "\n", 789 | "1. Create a *pcolormesh* plot\n", 790 | "2. Add the coastlines to a standard Plate Caree plot using *projection=* option.\n", 791 | "\n", 792 | "---\n", 793 | "**Solution**:" 794 | ] 795 | }, 796 | { 797 | "cell_type": "code", 798 | "execution_count": null, 799 | "metadata": {}, 800 | "outputs": [], 801 | "source": [] 802 | }, 803 | { 804 | "cell_type": "markdown", 805 | "metadata": {}, 806 | "source": [ 807 | "## Summary:\n", 808 | "\n", 809 | "You learned:\n", 810 | "\n", 811 | "* How to import scientific data formats, like netCDF and GRIB2\n", 812 | "* Worked with arrays and lists\n", 813 | "* How to create a simple maps\n", 814 | "\n", 815 | "Next lesson:\n", 816 | "* Obtain datasets from remote sources\n", 817 | "* Save data into text and binary files, and plots as images" 818 | ] 819 | }, 820 | { 821 | "cell_type": "code", 822 | "execution_count": null, 823 | "metadata": {}, 824 | "outputs": [], 825 | "source": [] 826 | } 827 | ], 828 | "metadata": { 829 | "kernelspec": { 830 | "display_name": "Python 3.11.0 ('notebook_demo')", 831 | "language": "python", 832 | "name": "python3" 833 | }, 834 | "language_info": { 835 | "codemirror_mode": { 836 | "name": "ipython", 837 | "version": 3 838 | }, 839 | "file_extension": ".py", 840 | "mimetype": "text/x-python", 841 | "name": "python", 842 | "nbconvert_exporter": "python", 843 | "pygments_lexer": "ipython3", 844 | "version": "3.11.0 | packaged by conda-forge | (main, Oct 25 2022, 06:18:27) [GCC 10.4.0]" 845 | }, 846 | "vscode": { 847 | "interpreter": { 848 | "hash": "4589143d4cda0c8671911bd60c16dc1d10ec327722e7574bc882b745b51509b4" 849 | } 850 | } 851 | }, 852 | "nbformat": 4, 853 | "nbformat_minor": 2 854 | } 855 | -------------------------------------------------------------------------------- /03_Remote_Datasets_and_Exporting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Lesson 3: Saving and Scripting\n", 8 | "Author: Rebekah Esmaili (rebekah.esmaili@gmail.com)\n", 9 | " \n", 10 | "---\n", 11 | "\n", 12 | "## Lesson Objectives\n", 13 | "* You will learn to:\n", 14 | " * Save data into text and binary files, and plots as images\n", 15 | " * Run python scripts" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import pandas as pd\n", 25 | "import numpy as np\n", 26 | "import matplotlib.pyplot as plt\n", 27 | "import xarray as xr\n", 28 | "import cartopy.crs as ccrs" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Data Sources\n", 36 | "\n", 37 | "### Data Archives\n", 38 | "\n", 39 | "Most Earth-science agencies openly and freely disseminate satellite, model, and in situ observations. Typically, data are stored in online data repositories and data holdings can be queried and ordered. Some examples are shown below.\n", 40 | "\n", 41 | "* [NASA](https://www.earthdata.nasa.gov/learn/find-data)\n", 42 | "* [NOAA](https://www.avl.class.noaa.gov/saa/products/welcome)\n", 43 | "* [ECMWF](https://www.ecmwf.int/en/forecasts/datasets)\n", 44 | "* [ESA](https://earth.esa.int/eogateway/catalog)\n", 45 | "\n", 46 | "### OPeNDAP/THREDDS catalogs\n", 47 | "\n", 48 | "Increasingly agencies are offering data catalogs that allow users to directly read from the archive without ordered. Open-source Project for a [Network Data Access Protocol (OPeNDAP)](https://www.opendap.org/) is an example of a software tool that simplifies access. Instead of downloading and reading data into Python, we can access it directly using a URL. Xarray supports OPeNDAP.\n", 49 | "\n", 50 | "Here are a couple of useful data OPeNDAP catalogs:\n", 51 | "\n", 52 | "* [NOAA/Physical Sciences Lab](https://psl.noaa.gov/data/) gridded climate datasets extending hundreds of years to real-time wind profiler data at a single location. The data or products derived from this data, organized by type, are available to scientists and the general public at the links below.\n", 53 | "* [NASA EOSDIS OpeNDAP Servers](https://www.earthdata.nasa.gov/engage/open-data-services-and-software/api/opendap/opendap-servers) servers across the Earth Observing System Data and Information System (EOSDIS). Contains many NASA satellite and reanalysis datasets.\n", 54 | "\n", 55 | "The example below shows Level 3 Monthly Average Chlorophyll Concentration from the Ocean Biology Processing Group (NASA/GSFC/OBPG). As you can see, we are passing a url and not a file location into xarray. One caveat if the engine **must be netcdf4** because the h5netcdf engine presently doesn't support opendap." 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "url = 'http://oceandata.sci.gsfc.nasa.gov/opendap/Merged_ATV/L3SMI/2022/001/X20220012022031.L3m_MO_CHL_chlor_a_4km.nc'\n", 65 | "sst_opendap = xr.open_dataset(url, engine='netcdf4')\n", 66 | "sst_opendap" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "chlor_a = sst_opendap.chlor_a[::15, ::15]\n", 76 | "chlor_a" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "map_proj = ccrs.PlateCarree()\n", 86 | "\n", 87 | "fig = plt.figure(figsize=[10,5])\n", 88 | "ax = plt.subplot(projection=map_proj)\n", 89 | "chlor_a.plot(vmin=0, vmax=.8, transform=map_proj, cmap='rainbow')\n", 90 | "ax.coastlines(\"10m\", color=\"k\")\n", 91 | "\n", 92 | "plt.show()\n" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "\n", 100 | "### Accessing data from the cloud\n", 101 | "\n", 102 | "Many major cloud computing companies, such as Google, Microsoft, and Amazon disseminate Earth science datasets. For instance, AWS supports an [open data program](https://aws.amazon.com/opendata/) that makes many climate datasets publicly available.\n", 103 | "\n", 104 | "The package s3fs is file interface for Amazon S3 (Simple Storage Service) buckets, so you can browse and search for data. NOAA's Open Data Dissemination (NODD) program is increasing access to satellite data, including GOES and JPSS. In this example, we'll look at GOES-16 data." 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "import s3fs" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "fs = s3fs.S3FileSystem(anon=True)\n", 123 | "url = 'noaa-goes16/ABI-L2-RSRF/2022/285/18/OR_ABI-L2-RSRF-M6_G16_s20222851800206_e20222851809514_c20222851901446.nc'\n", 124 | "remote_obj = fs.open(url, mode='rb')" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "# Open\n", 134 | "g16 = xr.open_dataset(remote_obj, engine='h5netcdf')" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "data_proj = ccrs.PlateCarree()\n", 144 | "map_proj = ccrs.Orthographic(central_longitude=-72.3)\n", 145 | "\n", 146 | "fig = plt.figure()\n", 147 | "ax = plt.subplot(projection=map_proj)\n", 148 | "g16.RSR.plot(transform=data_proj, vmin=0, vmax=600)\n", 149 | "ax.coastlines(\"10m\", color=\"k\")\n", 150 | "\n", 151 | "plt.show()\n" 152 | ] 153 | }, 154 | { 155 | "cell_type": "markdown", 156 | "metadata": {}, 157 | "source": [ 158 | "## Exporting data and figures\n" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "### Saving figures\n", 166 | "\n", 167 | "Normally, we end out plots with *plt.show()* to display them inline. Instead, use *plt.savefig()*. The second argument (*bbox_inches*) refers to the whitespace around the plot, it is optional. " 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "data_proj = ccrs.PlateCarree()\n", 177 | "map_proj = ccrs.Orthographic(central_longitude=-72.3)\n", 178 | "\n", 179 | "fig = plt.figure()\n", 180 | "ax = plt.subplot(projection=map_proj)\n", 181 | "g16.RSR.plot(transform=data_proj, vmin=0, vmax=600)\n", 182 | "ax.coastlines(\"10m\", color=\"k\")\n", 183 | "\n", 184 | "# The only difference is this...\n", 185 | "plt.savefig('SRB.png')\n", 186 | "plt.close()\n" 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "### Saving csv files\n", 194 | "\n", 195 | "The Pandas *to_csv* is convenient for quickly saving files. The option *index=False* suppress the indices of the DataFrame (which are printed to the left of the DataFrame) from being printed to file." 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [ 204 | "name = ['GOES-16', 'IceSat-2', 'Himawari']\n", 205 | "agency = ['NOAA', 'NASA', 'JAXA']\n", 206 | "orbit = ['GEO', 'LEO', 'GEO']\n", 207 | "\n", 208 | "df = pd.DataFrame({'name': name,\n", 209 | " 'agency': agency,\n", 210 | " 'orbit': orbit})\n", 211 | "\n", 212 | "df.to_csv('satellites.csv', index=False)" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "### Saving as a binary file\n", 220 | "\n", 221 | "NumPy binary files (.npz) are geared towards arrays, which can be multi-dimensional. These are useful for quickly storing large datasets." 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "execution_count": null, 227 | "metadata": {}, 228 | "outputs": [], 229 | "source": [ 230 | "np.savez('satnames', name=name, agency=agency, orbit=orbit)" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "npzfile = np.load('satnames.npz')\n", 240 | "npzfile.files\n", 241 | "npzfile.close()" 242 | ] 243 | }, 244 | { 245 | "attachments": {}, 246 | "cell_type": "markdown", 247 | "metadata": {}, 248 | "source": [ 249 | "## Scripting with Python\n", 250 | "\n", 251 | "### Running Python scripts from the command line\n", 252 | "\n", 253 | "Now you are finished editing the code and you probably want to run it. There are two ways you can run Python scripts:\n", 254 | "\n", 255 | "1. Using the command line interpreter\n", 256 | "2. Using iPython\n", 257 | "\n", 258 | "iPython is an interactive command line that allows you to run code in chunks. In fact, Jupyter Notebook is built using iPython, which explains the similarity in behavior.\n", 259 | " \n", 260 | "* Windows: I suggest using the Anaconda Prompt which you can access from the start menu or using Anaconda Navigator. \n", 261 | "* MacOs/Linux: open the Terminal app. \n", 262 | "\n", 263 | "Once the command line is open, you start in a default location. For example, if you are using Windows and launch the Anaconda Prompt you will see:\n", 264 | "\n", 265 | "```\n", 266 | "(base) C:\\Users\\>\n", 267 | "```\n", 268 | "\n", 269 | "Now, navigate to where our script is. To do this, you will change directories using the cd command. For example, if your code is stored in C:\\Documents\\Python, you can type:\n", 270 | "\n", 271 | "```\n", 272 | "\n", 273 | "cd C:\\Documents\\Python\n", 274 | "```\n", 275 | "\n", 276 | "The command line will now be updated showing:\n", 277 | "\n", 278 | "```\n", 279 | "(base) C:\\Documents\\Python>\n", 280 | "```\n", 281 | "\n", 282 | "Now that you are in the right place, you can call the Python interpreter, which to convert your code into a format that your computer can understand and executes the command. If you installed Anaconda, this includes a Python 3 interpreter (*python3*). So, to run the script, type:\n", 283 | "\n", 284 | "```\n", 285 | "python3 hello_world.py\n", 286 | "```\n", 287 | "\n", 288 | "If successful, “Hello Earth” should print to your screen.\n", 289 | "\n", 290 | "A second method is to use iPython, which allows you to open Python in interactive mode. Unlike the command line method, iPython will let you run code line-by-line. So, like Jupyter Notebook, you have the option to copy and paste you code from the text editor in chunks into the iPython window. You can also call the entire script inside iPython. This is done by starting iPython and using the command %run \\[script name\\].py. Below is a capture from my terminal:\n", 291 | "\n", 292 | "```\n", 293 | "Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]\n", 294 | "Type 'copyright', 'credits' or 'license' for more information\n", 295 | "IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.\n", 296 | "\n", 297 | "In [1]: %run script_example.ipynb\n", 298 | "Hello Earth\n", 299 | "```\n", 300 | "\n", 301 | "One advantage of using iPython is that after the script finishes running, variables that were generated in the script are still in memory. Then, you can print or operate on the variables to either debug or to develop your code further. \n", 302 | "\n", 303 | "You may have noted two differences in workflow for write code in scripts versus notebooks, (1) that code cannot be inline and (2) the program must run fully to the end.\n", 304 | "\n", 305 | "\n", 306 | "### Handling output when scripting\n", 307 | "\n", 308 | "In the previous example, you printed text to the screen but Python’s capable of saving figures and data. To save plots, replace *plt.show()* with the *plt.savefig()* command.\n", 309 | "\n", 310 | "It is possible to directly display your graphics using the X11 protocol (by default in Linux) with XQuartz (Mac) or PuTTy (Windows). \n", 311 | "\n", 312 | "I typically discourage this because satellite imagery tends to be very large and thus slow to display remotely. From my experience, it is usually faster to write an image to a file and then view the plot after it is fully rendered.\n", 313 | "\n", 314 | "## Summary:\n", 315 | "\n", 316 | "You learned:\n", 317 | "\n", 318 | "* Aceess data from data archives, OPeNDAP, and cloud storage\n", 319 | "* How to save data and graphics\n", 320 | "* How to run scripts\n", 321 | "\n", 322 | "## Conclusion\n", 323 | "\n", 324 | "I hope you feel empowered find relevant satellite data for your project are equipped with the tools to visualize it. Practice regularly (daily!) to improve your skills. Here are some ways you can continue your journey:\n", 325 | "\n", 326 | "* Downlaod data. You can access data from ESA (https://earth.esa.int/eogateway/), NOAA’s threads data server: https://www.ncei.noaa.gov/thredds/catalog.html, or NASA's [Earthdata](https://earthdata.nasa.gov/) portals.\n", 327 | "* Read. \n", 328 | " * [Project Pythia Foundations](https://foundations.projectpythia.org/landing-page.html) a free and excellent coverage of Python basics for Earth Science. Covers the topics presented in more detail.\n", 329 | " * [Python for Data Science](https://jakevdp.github.io/PythonDataScienceHandbook/) (free) a more general book on Python programming.\n", 330 | " * [Research Software Engineering with Python](https://merely-useful.tech/py-rse/) Free eBook to enhance your workflow\n", 331 | " * Python Programming and Visualization for Scientists by Alex DeCaria (not free)\n", 332 | " * Python Machine Learning by Wei-Meng Lee (not free)\n", 333 | " * [Earth Observation Using Python](https://www.wiley.com/en-us/Earth+Observation+using+Python%3A+A+Practical+Programming+Guide-p-9781119606888) by Rebekah Esmaili (not free)\n", 334 | "* Watch.\n", 335 | " * [CS Dojo](https://www.youtube.com/channel/UCxX9wt5FWQUAAz4UrysqK9A) on YouTube has a lot of short, fun Python tutorials.\n", 336 | " * [Coursera](https://www.coursera.org/learn/interactive-python-1?specialization=computer-fundamentals) has some fundamental interactive Python courses if you want more structure.\n", 337 | " * [Python for Climate and Meteorology](https://www.youtube.com/watch?v=uQZAEPnUZ5o) Another focused Python workshop taught at AMS, a little more advanced.\n", 338 | "* Connect with an online community, such as Pangeo (https://discourse.pangeo.io/)" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [] 347 | } 348 | ], 349 | "metadata": { 350 | "kernelspec": { 351 | "display_name": "Python 3.11.0 ('notebook_demo')", 352 | "language": "python", 353 | "name": "python3" 354 | }, 355 | "language_info": { 356 | "codemirror_mode": { 357 | "name": "ipython", 358 | "version": 3 359 | }, 360 | "file_extension": ".py", 361 | "mimetype": "text/x-python", 362 | "name": "python", 363 | "nbconvert_exporter": "python", 364 | "pygments_lexer": "ipython3", 365 | "version": "3.11.0" 366 | }, 367 | "vscode": { 368 | "interpreter": { 369 | "hash": "4589143d4cda0c8671911bd60c16dc1d10ec327722e7574bc882b745b51509b4" 370 | } 371 | } 372 | }, 373 | "nbformat": 4, 374 | "nbformat_minor": 4 375 | } 376 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Rebekah Esmaili 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python for Earth Sciences 2 | 3 | Instructor: [Rebekah Esmaili](http://www.rebekahesmaili.com), PhD 4 | 5 | --- 6 | 7 | A crash course in Python focusing on reading and visualizing data-sets used in Earth sciences. 8 | 9 | This code is interactive! Click here: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/modern-tools-workshop/AGU-python-workshop-2022/HEAD) 10 | 11 | --- 12 | 13 | ## Getting Started 14 | 15 | This workshop will cover: 16 | 17 | * Launching Jupyter Notebooks 18 | * Working with arrays using the Numpy package 19 | * Importing text datasets using the Pandas package 20 | * Creating simple graphics with Matplotlib 21 | * Importing scientific data formats, such as netCDF and GRIB2 22 | * Creating maps from datasets 23 | 24 | --- 25 | 26 | ### Installation Requirements 27 | 28 | "I am really new to Python!" 29 | 30 | * I recommend launching binder, which is a "cloud version" of this course. No installation required! [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/modern-tools-workshop/AGU-python-workshop-2022/HEAD) 31 | * Need help with Binder? Video tutorial on [YouTube](https://youtu.be/3BrfFe4HsAw). 32 | 33 | "I have used Python before!" 34 | 35 | * If you wish to run the examples locally, I recommend installing [Anaconda](https://www.anaconda.com/products/individual). If you are having trouble with your installation, contact the instructor before the course or use binder. 36 | * Need help installing Anaconda? Video tutorial on [YouTube](https://youtu.be/zxSQCXXvOIM). 37 | * Download the contents of this GitHub repository to your computer. 38 | * Launch Jupyter Notebooks from the Anaconda Navigator. This will open a window in your default browser. Navigate to the folder that contains the notebooks (*.ipynb) and click on the tutorial for the day. 39 | * New to Jupyter? Here's a video tutorial on [YouTube](https://youtu.be/gmMCuR9JPpY). 40 | * Additional packages: 41 | * Launch the Anaconda Prompt (Windows) or Terminal (MacOS/Linux). 42 | * Use the environments.yml to install the necessary packages. You can do this in the terminal using: 43 | 44 | ```bash 45 | conda env create -f environment.yml 46 | ``` 47 | 48 | * Then, switch to the new environment once the installation is complete: 49 | 50 | ```bash 51 | conda activate python-workshop 52 | ``` 53 | * Note: The default environment is called 'base.' If you close the terminal, you will have to switch back to the environment using the above command again. 54 | 55 | I *do not* recommend: 56 | * Using Python on a remote server for this tutorial (I cannot help troubleshoot) 57 | * Using your operating system's Python or a shared Python installations unless you are advanced! 58 | 59 | --- 60 | ## Course Philosophy 61 | 62 | * Increase accessibility of satellite data and analysis 63 | * Teach Python using practical examples and real-world datasets 64 | * Promote reproducible and transparent scientific research 65 | 66 | ## Resources 67 | 68 | ### Packages and Tutorials 69 | 70 | Pandas 71 | * Short Introduction: https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html 72 | * Cookbook for more details: https://pandas.pydata.org/pandas-docs/stable/user_guide/cookbook.html#cookbook 73 | 74 | --- 75 | Matplotlib 76 | * Pyplot Tutorial: https://matplotlib.org/3.1.1/tutorials/introductory/pyplot.html 77 | 78 | --- 79 | Import/Export 80 | 81 | NetCDF files 82 | * Detailed tutorial on the netCDF4 package: https://unidata.github.io/netcdf4-python. 83 | * Xarray tutorial: https://xarray-contrib.github.io/xarray-tutorial/ 84 | 85 | HDF files 86 | * The package [h5py](https://www.h5py.org/) is similar to netcdf4. 87 | * User manual at http://docs.h5py.org/en/stable/. 88 | * Xarray can also open HDF files! 89 | 90 | GRIB/GRIB2 files 91 | * World Meteorology Association standard format, e.g. commonly used with weather-related models like ECMWF and GFS. 92 | * Can be opened using [pygrib](https://github.com/jswhit/pygrib). 93 | * Example usage at https://jswhit.github.io/pygrib/docs/. 94 | 95 | BUFR files 96 | * Another common table-driven format. 97 | * Open with [python-bufr](https://github.com/pytroll/python-bufr), part of the pytroll project. 98 | --- 99 | 100 | ### General Python Resources 101 | 102 | Beginner Tutorials 103 | * Youtube series for absolute beginners [CS Dojo](https://www.youtube.com/watch?v=Z1Yd7upQsXY&list=PLBZBJbE_rGRWeh5mIBhD-hhDwSEDxogDg) 104 | * [Research Software Engineering with Python](https://merely-useful.tech/py-rse/) Free eBook to enhance your workflow. 105 | 106 | Intermediate Tutorials 107 | * [Project Pythia Foundations Online Textbook](https://foundations.projectpythia.org/landing-page.html) A community learning resource for Python-based computing in the geosciences. Highly recommended! 108 | * [Python for Climate and Meteorology](https://www.youtube.com/watch?v=uQZAEPnUZ5o) Another tutorial taught at AMS, a little more advanced. 109 | * Learn more about [Python for Atmosphere and Ocean Scientists](https://carpentries-lab.github.io/python-aos-lesson/) using Software Carpentry lesson plans. 110 | * [Earth Observation using Python](https://www.wiley.com/en-us/Earth+Observation+using+Python%3A+A+Practical+Programming+Guide-p-9781119606888) is a book I wrote that builds on the content of the workshop. 111 | 112 | ## Granting Permission for Reuse 113 | These course materials are designed for use as part of the AGU Scientific Workshop and are the intellectual property of the instructor. However, I encourage others to reuse or adapt the material for their research communities or use cases. If you do not significantly modify the original material, please send me an email letting me know and acknowledge me in your content. -------------------------------------------------------------------------------- /Solutions_to_Exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Solutions to Exercises\n", 8 | "Author: Rebekah Esmaili (rebekah.esmaili@gmail.com)\n", 9 | " \n", 10 | "---" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "import numpy as np\n", 20 | "import pandas as pd\n", 21 | "import matplotlib.pyplot as plt\n", 22 | "import xarray as xr\n", 23 | "from cartopy import crs as ccrs\n", 24 | "import scipy.interpolate\n", 25 | "import s3fs" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "# 1. Basic Data Analysis and Visualization\n", 33 | "\n", 34 | "**Exercise 1:** Learning to use notebooks\n", 35 | "\n", 36 | "1. Launch Jupyter Notebook and create a new notebook\n", 37 | "2. Rename the notebook\n", 38 | "3. Create a new cell and use *type()* to see if the following are floats and integers:\n", 39 | " * 2+2\n", 40 | " * 2\\*2.0\n", 41 | " * var_float/var_int\n", 42 | "---\n", 43 | "**Solution:**" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "data": { 53 | "text/plain": [ 54 | "(int, float, float)" 55 | ] 56 | }, 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "output_type": "execute_result" 60 | } 61 | ], 62 | "source": [ 63 | "var_int = 8\n", 64 | "var_float = 15.0\n", 65 | "\n", 66 | "type(2+2), type(2*2.0), type(var_float/var_int)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "**Exercise 2:** Import an ascii file\n", 74 | "\n", 75 | "1. Import the dataset \"20200901_20200930_Monterey.lev15.csv\" and save it to a variable called *aeronet*.\n", 76 | "2. Print the column names\n", 77 | "3. Find a column that doesn't have only missing values (-999) and (challenge!) calculate the mean using the following syntax *variable\\[\"column\"\\].mean()*\n", 78 | "---\n", 79 | "**Solution:**" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 3, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "fname = \"data/20200901_20200930_Monterey.lev15.csv\"\n", 89 | "aeronet = pd.read_csv(fname, sep=',\\s*', engine='python')" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "data": { 99 | "text/html": [ 100 | "
\n", 101 | "\n", 114 | "\n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | "
Date(dd:mm:yyyy)Time(hh:mm:ss)Day_of_YearDay_of_Year(Fraction)AOD_1640nmAOD_1020nmAOD_870nmAOD_865nmAOD_779nmAOD_675nm...Exact_Wavelengths_of_AOD(um)_380nmExact_Wavelengths_of_AOD(um)_340nmExact_Wavelengths_of_PW(um)_935nmExact_Wavelengths_of_AOD(um)_681nmExact_Wavelengths_of_AOD(um)_709nmExact_Wavelengths_of_AOD(um)_EmptyExact_Wavelengths_of_AOD(um)_Empty.1Exact_Wavelengths_of_AOD(um)_Empty.2Exact_Wavelengths_of_AOD(um)_Empty.3Exact_Wavelengths_of_AOD(um)_Empty.4
00.07129620:53:18245245.8703470.0611690.1670120.238173-999-9990.400838...0.37940.34090.9365-999-999-999-999-999-999-999
10.07129620:58:18245245.8738190.0611550.1684170.239952-999-9990.404648...0.37940.34090.9365-999-999-999-999-999-999-999
20.07129621:03:18245245.8772920.0631350.1731430.246827-999-9990.414668...0.37940.34090.9365-999-999-999-999-999-999-999
30.07129621:08:18245245.8807640.0617540.1705410.241485-999-9990.405998...0.37940.34090.9365-999-999-999-999-999-999-999
40.07129621:18:18245245.8877080.0590590.1639190.232041-999-9990.391191...0.37940.34090.9365-999-999-999-999-999-999-999
\n", 264 | "

5 rows × 113 columns

\n", 265 | "
" 266 | ], 267 | "text/plain": [ 268 | " Date(dd:mm:yyyy) Time(hh:mm:ss) Day_of_Year Day_of_Year(Fraction) \\\n", 269 | "0 0.071296 20:53:18 245 245.870347 \n", 270 | "1 0.071296 20:58:18 245 245.873819 \n", 271 | "2 0.071296 21:03:18 245 245.877292 \n", 272 | "3 0.071296 21:08:18 245 245.880764 \n", 273 | "4 0.071296 21:18:18 245 245.887708 \n", 274 | "\n", 275 | " AOD_1640nm AOD_1020nm AOD_870nm AOD_865nm AOD_779nm AOD_675nm ... \\\n", 276 | "0 0.061169 0.167012 0.238173 -999 -999 0.400838 ... \n", 277 | "1 0.061155 0.168417 0.239952 -999 -999 0.404648 ... \n", 278 | "2 0.063135 0.173143 0.246827 -999 -999 0.414668 ... \n", 279 | "3 0.061754 0.170541 0.241485 -999 -999 0.405998 ... \n", 280 | "4 0.059059 0.163919 0.232041 -999 -999 0.391191 ... \n", 281 | "\n", 282 | " Exact_Wavelengths_of_AOD(um)_380nm Exact_Wavelengths_of_AOD(um)_340nm \\\n", 283 | "0 0.3794 0.3409 \n", 284 | "1 0.3794 0.3409 \n", 285 | "2 0.3794 0.3409 \n", 286 | "3 0.3794 0.3409 \n", 287 | "4 0.3794 0.3409 \n", 288 | "\n", 289 | " Exact_Wavelengths_of_PW(um)_935nm Exact_Wavelengths_of_AOD(um)_681nm \\\n", 290 | "0 0.9365 -999 \n", 291 | "1 0.9365 -999 \n", 292 | "2 0.9365 -999 \n", 293 | "3 0.9365 -999 \n", 294 | "4 0.9365 -999 \n", 295 | "\n", 296 | " Exact_Wavelengths_of_AOD(um)_709nm Exact_Wavelengths_of_AOD(um)_Empty \\\n", 297 | "0 -999 -999 \n", 298 | "1 -999 -999 \n", 299 | "2 -999 -999 \n", 300 | "3 -999 -999 \n", 301 | "4 -999 -999 \n", 302 | "\n", 303 | " Exact_Wavelengths_of_AOD(um)_Empty.1 Exact_Wavelengths_of_AOD(um)_Empty.2 \\\n", 304 | "0 -999 -999 \n", 305 | "1 -999 -999 \n", 306 | "2 -999 -999 \n", 307 | "3 -999 -999 \n", 308 | "4 -999 -999 \n", 309 | "\n", 310 | " Exact_Wavelengths_of_AOD(um)_Empty.3 Exact_Wavelengths_of_AOD(um)_Empty.4 \n", 311 | "0 -999 -999 \n", 312 | "1 -999 -999 \n", 313 | "2 -999 -999 \n", 314 | "3 -999 -999 \n", 315 | "4 -999 -999 \n", 316 | "\n", 317 | "[5 rows x 113 columns]" 318 | ] 319 | }, 320 | "execution_count": 4, 321 | "metadata": {}, 322 | "output_type": "execute_result" 323 | } 324 | ], 325 | "source": [ 326 | "aeronet.head()" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 5, 332 | "metadata": {}, 333 | "outputs": [ 334 | { 335 | "data": { 336 | "text/plain": [ 337 | "-1.7637041143410852" 338 | ] 339 | }, 340 | "execution_count": 5, 341 | "metadata": {}, 342 | "output_type": "execute_result" 343 | } 344 | ], 345 | "source": [ 346 | "aeronet[\"AOD_1640nm\"].mean()" 347 | ] 348 | }, 349 | { 350 | "cell_type": "markdown", 351 | "metadata": {}, 352 | "source": [ 353 | "---\n", 354 | "**Exercise 3:** Filtering data\n", 355 | "\n", 356 | "Using the dataset imported in the previous example (*aeronet*):\n", 357 | " \n", 358 | "1. Create a mask that filters the \"AOD_870nm\" column to only include values that are above 0.\n", 359 | "2. Create a new variables, *day_of_year*, with the mask applied to aeronet\\[\"Day_of_Year(Fraction)\"\\].\n", 360 | "3. Create a new variables, *aod_870*, with the mask applied to aeronet\\[\"AOD_870nm\"\\].\n", 361 | "4. Compare the mean value of *aeronet\\[\"AOD_870nm\"\\]* to *aod_870*.\n", 362 | " \n", 363 | "---\n", 364 | "**Solution**" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 6, 370 | "metadata": {}, 371 | "outputs": [], 372 | "source": [ 373 | "mask_aod = (aeronet[\"AOD_870nm\"] > 0 )" 374 | ] 375 | }, 376 | { 377 | "cell_type": "code", 378 | "execution_count": 7, 379 | "metadata": {}, 380 | "outputs": [], 381 | "source": [ 382 | "day_of_year = aeronet[\"Day_of_Year(Fraction)\"][mask_aod]\n", 383 | "aod_870 = aeronet[\"AOD_870nm\"][mask_aod]" 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": 8, 389 | "metadata": {}, 390 | "outputs": [ 391 | { 392 | "data": { 393 | "text/plain": [ 394 | "(-0.3344563769379846, 0.6341813957322987)" 395 | ] 396 | }, 397 | "execution_count": 8, 398 | "metadata": {}, 399 | "output_type": "execute_result" 400 | } 401 | ], 402 | "source": [ 403 | "aeronet[\"AOD_870nm\"].mean(), aod_870.mean()" 404 | ] 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "metadata": {}, 409 | "source": [ 410 | "---\n", 411 | "**Exercise 4:** Create a scatterplot\n", 412 | "\n", 413 | "Use the variables *aod_870* and *day_of_year* that you made in Exercise 3 to:\n", 414 | "\n", 415 | "1. Create a scatter plot showing the *day_of_year* (x-axis) and *aod_870* (y-axis)\n", 416 | "2. Add y-axis and x-axis labels using *.set_xlabel()* and *.set_ylabel()*\n", 417 | "3. Adjust the color and size of the scatterplot\n", 418 | "\n", 419 | "---\n", 420 | "**Solution**" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 9, 426 | "metadata": {}, 427 | "outputs": [ 428 | { 429 | "data": { 430 | "image/png": "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nU7dcccd6tixo8LDw3X11VcrJyfHm02pwRNtO3TokO644w717t1bYWFh6tatm+68804VFhZ6uzk1eOr/rooxRuPGjZPD4dDSpUu90IL6ebJ9vnpsaUz77Hhsaexxc+fOnbr66qsVFRWliIgIXXjhhdq7d6/rfjseVyTPtM+KY4vfBpW1a9dq2rRp+vzzz7Vq1SodP35cSUlJKikpqfHYpUuXasOGDYqJialx32effaaxY8cqKSlJX3zxhb788ktNnz69wS2BW5qn2jd58mTt2rVLy5cv17Zt23Tttddq4sSJ2rx5szeaUafGtm/s2LHKy8tzXf773/+63T9z5ky9++67Wrx4sdLS0nTkyBFdeeWVqqio8GZz3Hiibbm5ucrNzdXTTz+tbdu2aeHChVqxYoWSk5O93ZwaPPV/V2XevHktegqNpvJU+3z92NJQ++x4bGlM27755hslJibq7LPP1po1a7R161Y98sgjatu2resxdjyuSJ5pnyXHFgNjjDEHDhwwkszatWvdbs/JyTFnnHGG2b59u+nevbuZO3eu2/1DhgwxDz/8sBcrbZ7mti88PNy89tprbre1b9/e/OMf/2jpkpuktvZNmTLFjB8/vs7nFBQUmKCgILN48WLXbfv27TMBAQFmxYoVLVlukzSnbbV58803TXBwsDl27JiHKzw1p9K+LVu2mNjYWJOXl2ckmXfffbflCm2m5rbPl48tjWmfLxxbamvbxIkTzW9+85s6n+MrxxVjmte+2rT0scVve1ROVtVt1b59e9dtlZWVmjx5su6991717du3xnMOHDigDRs2qFOnTrrooovUuXNnXXLJJUpLS/Na3Y3VnPZJUmJiot544w0dOnRIlZWVWrx4sZxOp0aMGOGNshuttvZJ0po1a9SpUyedddZZ+t3vfqcDBw647ktPT9exY8eUlJTkui0mJkb9+vXTp59+6p3CG6E5bavrdSIjI9Wmjb1O8dXc9pWWluq6667Tc889py5dunit3qZqTvt8/dgiNfz/5wvHlpPbVllZqffff19nnXWWLrvsMnXq1ElDhgxxG3L0leOK1Lz21fU6LXpsaZH442MqKyvNVVddZRITE91u/9Of/mTGjBljKisrjTGmRo/DZ599ZiSZ9u3bm1deecVs2rTJzJw50wQHB5vdu3d7swn1am77jDnx18Fll11mJJk2bdqYyMhIs3LlSm+V3ih1tW/x4sXmvffeM9u2bTPLly83/fv3N3379jVHjx41xhizaNEiExwcXOP1xowZY2655Rav1N6Q5rbtZPn5+aZbt27moYce8kbZjXYq7bvllltMcnKy67ps2KPS3Pb5+rGlMf9/dj+21Na2qp67sLAw85e//MVs3rzZpKSkGIfDYdasWWOM8Y3jijHNb9/JvHFsIagYY26//XbTvXt3k52d7bpt48aNpnPnzmbfvn2u207+IP/kk0+MJDN79my31zv33HPNAw880OJ1N1Zz22eMMdOnTzcXXHCBWb16tdmyZYt57LHHTFRUlMnIyPBW+Q2qrX21yc3NNUFBQWbJkiXGmLoPKKNHjzZTp05tkVqbqrltq66wsNAMGTLEjB071pSXl7dUqc3S3PYtW7bM9OzZ0xQXF7seY8eg0tz2+fKxpTa1/Xza/dhSW9v27dtnJJnrrrvO7bFXXXWVmTRpkjHGN44rxjS/fdV569ji90Fl+vTpJjY21nz77bdut8+dO9c4HA4TGBjoukgyAQEBpnv37sYYY7799lsjyfzzn/90e+6vfvUrc/3113urCfU6lfbt2bPHSDLbt293e+6oUaNs8wtXV/vq0rNnTzNnzhxjjDH/+9//jCRz6NAht8ckJCSY3//+9x6vtalOpW1VioqKzNChQ82oUaNMWVlZS5TZbKfSvhkzZtT583vJJZe0YNWNdyrt8+VjS12qt8/ux5a62uZ0Ok2bNm3ME0884Xb7fffdZy666CJjjP2PK8acWvuqePPY4rdzVIwxmj59ut555x199NFHio+Pd7t/8uTJysjI0JYtW1yXmJgY3Xvvvfrwww8lST169FBMTEyN5V27d+9W9+7dvdaW2niifaWlpZJUY5VBYGCgKisrvdOQOjTUvtocPHhQ2dnZ6tq1qyRp0KBBCgoK0qpVq1yPycvL0/bt23XRRRe1WO0N8UTbJKmoqEhJSUkKDg7W8uXL3VYlWMkT7XvggQdq/PxK0ty5c7VgwYKWLL9BnmifLx9banNy++x6bGmobcHBwRo8eHC9/y92Pa5InmmfZMGxpUVjkI3ddtttJioqyqxZs8bk5eW5LqWlpXU+p7ahkblz55rIyEjz1ltvmczMTPPwww+btm3bmj179rRwC+rnifaVl5ebnj17mmHDhpkNGzaYPXv2mKeffto4HA7z/vvve6EVdWuofcXFxebuu+82n376qcnKyjIff/yxGTp0qDnjjDNMUVGR63VuvfVWExsba1avXm02bdpkRo4cafr372+OHz9uVdM80raioiIzZMgQc+6555o9e/a4vY6VbTPGc/93J5NNhn481T5fPbY0pn12PbY05rj5zjvvmKCgIPPSSy+ZzMxMM3/+fBMYGGjWr1/veowdjyvGeKZ9Vhxb/DaoSKr1smDBgjqfU1tQMcaYlJQUExsba8LCwszQoUPdfmCt4qn27d6921x77bWmU6dOJiwszCQkJNRYUmiFhtpXWlpqkpKSzOmnn26CgoJMt27dzJQpU8zevXvdXqesrMxMnz7dtG/f3oSGhporr7yyxmO8zRNt+/jjj+t8naysLGsa9hNP/d/V9rp2CCqebJ8vHlsa2z47Hlsae9xMTU01PXv2NG3btjX9+/c3S5cudbvfjscVYzzTPiuOLY6figcAALAdv52jAgAA7I+gAgAAbIugAgAAbIugAgAAbIugAgAAbIugAgAAbIugAgAAbIugAgAAbIugAsAnfPLJJzr33HMVFBSka665xupyAHgJQQWAbrzxRjkcDjkcDgUFBalz584aM2aMXnnlFctPQFll1qxZGjBggLKysrRw4UK3+5xOp/r27atbbrmlxvPuu+8+de/eXUVFRV6qFIAnEVQASJLGjh2rvLw8fffdd/rggw906aWXasaMGbryyit1/Phxq8vTN998o5EjRyo2NlbR0dFu94WEhOi1117TwoULtWLFCtftn3/+uebOnauFCxcqMjLSo/UYY2zx7wK0dgQVAJJOfNh36dJFZ5xxhgYOHKgHH3xQy5Yt0wcffODWg/GXv/xF5557rsLDwxUXF6fbb79dR44ckSSVlJQoMjJSb7/9tttr/+c//1F4eLiKi4trfW+n06k777xTnTp1Utu2bZWYmKgvv/xSkvTdd9/J4XDo4MGDuvnmm+VwOGr0qEjSoEGD9NBDD+m3v/2tCgoKdPToUd10002aNm2aLr30Un366acaPny4QkNDFRcXpzvvvFMlJSWu57/++us6//zzFRERoS5duuj666/XgQMHXPevWbNGDodDH374oc4//3yFhIRo/fr1zf3nBtBIBBUAdRo5cqT69++vd955x3VbQECAnn32WW3fvl2vvvqqPvroI913332SpPDwcE2aNEkLFixwe50FCxboF7/4hSIiImp9n/vuu09LlizRq6++qk2bNqlnz5667LLLdOjQIcXFxSkvL0+RkZGaN2+e8vLyNHHixFpf56GHHlLXrl1155136uGHH5YkpaSkaNu2bbrssst07bXXKiMjQ2+88YbS0tI0ffp013PLy8v1xBNPaOvWrVq6dKmysrJ044031lprSkqKdu7cqYSEhCb9ewJohhY5JzMAnzJlyhQzfvz4Wu+bOHGi6dOnT53PffPNN02HDh1c1zds2GACAwPNvn37jDHG/PjjjyYoKMisWbOm1ucfOXLEBAUFmUWLFrluKy8vNzExMeapp55y3RYVFVXjdPS12bFjh2nbtq0JDg42X3zxhTHGmMmTJ5tbbrnF7XHr1683AQEBpqysrNbX+eKLL4wkU1xcbIz5+fT21U95D6Dl0aMCoF7GGDkcDtf1jz/+WGPGjNEZZ5yhiIgI3XDDDTp48KBrGOWCCy5Q37599dprr0mS/vnPf6pbt24aPnx4ra//zTff6NixY7r44otdtwUFBemCCy7Qzp07m1xvnz59NGHCBI0ZM0aDBw+WJKWnp2vhwoU67bTTXJfLLrtMlZWVysrKkiRt3rxZ48ePV/fu3RUREaERI0ZIkvbu3ev2+ueff36TawLQfAQVAPXauXOn4uPjJUnff/+9Lr/8cvXr109LlixRenq6/va3v0mSjh075nrOb3/7W9fwz4IFC3TTTTe5hZ3qjDGSVOP+kwNSU7Rp00Zt2rRxXa+srNTUqVO1ZcsW12Xr1q3KzMzUmWeeqZKSEiUlJem0007T66+/ri+//FLvvvuupBNDQtWFh4c3qyYAzUNQAVCnjz76SNu2bdOECRMkSRs3btTx48f1zDPP6MILL9RZZ52l3NzcGs/7zW9+o7179+rZZ5/VV199pSlTptT5Hj179lRwcLDS0tJctx07dkwbN25Unz59PNKOgQMH6quvvlLPnj1rXIKDg/X1118rPz9fc+bM0bBhw3T22We7TaQFYJ02DT8EgD9wOp3av3+/Kioq9MMPP2jFihVKSUnRlVdeqRtuuEGSdOaZZ+r48eOaP3++rrrqKn3yySf6+9//XuO12rVrp2uvvVb33nuvkpKSFBsbW+f7hoeH67bbbtO9996r9u3bq1u3bnrqqadUWlqq5ORkj7Tt/vvv14UXXqhp06bpd7/7ncLDw7Vz506tWrVK8+fPV7du3RQcHKz58+fr1ltv1fbt2/XEE0945L0BnBp6VABIklasWKGuXbuqR48eGjt2rD7++GM9++yzWrZsmQIDAyVJAwYM0F/+8hc9+eST6tevnxYtWqSUlJRaXy85OVnl5eW6+eabG3zvOXPmaMKECZo8ebIGDhyoPXv26MMPP1S7du080raEhAStXbtWmZmZGjZsmM477zw98sgj6tq1qyTp9NNP18KFC/XWW2/pnHPO0Zw5c/T000975L0BnBqHqRogBgAPWrRokWbMmKHc3FwFBwdbXQ4AH8XQDwCPKi0tVVZWllJSUjR16lRCCoBTwtAPAI966qmnNGDAAHXu3FmzZ8+2uhwAPo6hHwAAYFv0qAAAANsiqAAAANsiqAAAANsiqAAAANsiqAAAANsiqAAAANsiqAAAANsiqAAAANv6/wEXyI43kU+R+gAAAABJRU5ErkJggg==", 431 | "text/plain": [ 432 | "
" 433 | ] 434 | }, 435 | "metadata": {}, 436 | "output_type": "display_data" 437 | } 438 | ], 439 | "source": [ 440 | "fig = plt.figure() \n", 441 | "ax = plt.subplot()\n", 442 | "ax.scatter(day_of_year, aod_870, s=0.5)\n", 443 | "ax.set_xlabel('Day of Year')\n", 444 | "ax.set_ylabel('AOD')\n", 445 | "plt.show()" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "metadata": {}, 451 | "source": [ 452 | "# 2. Scientific Data Formats and Advanced Plotting\n", 453 | "\n", 454 | "---\n", 455 | "**Exercise 1**: Importing netCDF files\n", 456 | "1. Open the file \"MOP03JM-201811-L3V95.6.3_thinned.nc\" using the xarray library\n", 457 | "2. Print the variable names\n", 458 | "3. What are the dimensions?\n", 459 | "---\n", 460 | "\n", 461 | "**Solution:**" 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "execution_count": 10, 467 | "metadata": {}, 468 | "outputs": [], 469 | "source": [ 470 | "fname = 'data/MOP03JM-201811-L3V95.6.3_thinned.nc' \n", 471 | "mop_file_id = xr.open_dataset(fname, engine='h5netcdf')" 472 | ] 473 | }, 474 | { 475 | "cell_type": "code", 476 | "execution_count": 11, 477 | "metadata": {}, 478 | "outputs": [ 479 | { 480 | "data": { 481 | "text/html": [ 482 | "
\n", 483 | "\n", 484 | "\n", 485 | "\n", 486 | "\n", 487 | "\n", 488 | "\n", 489 | "\n", 490 | "\n", 491 | "\n", 492 | "\n", 493 | "\n", 494 | "\n", 495 | "\n", 496 | "\n", 497 | "
<xarray.Dataset>\n",
 846 |        "Dimensions:                    (YDim: 180, XDim: 360)\n",
 847 |        "Dimensions without coordinates: YDim, XDim\n",
 848 |        "Data variables:\n",
 849 |        "    Latitude                   (YDim) float32 ...\n",
 850 |        "    Longitude                  (XDim) float32 ...\n",
 851 |        "    RetrievedCOTotalColumnDay  (XDim, YDim) float32 ...
" 852 | ], 853 | "text/plain": [ 854 | "\n", 855 | "Dimensions: (YDim: 180, XDim: 360)\n", 856 | "Dimensions without coordinates: YDim, XDim\n", 857 | "Data variables:\n", 858 | " Latitude (YDim) float32 ...\n", 859 | " Longitude (XDim) float32 ...\n", 860 | " RetrievedCOTotalColumnDay (XDim, YDim) float32 ..." 861 | ] 862 | }, 863 | "execution_count": 11, 864 | "metadata": {}, 865 | "output_type": "execute_result" 866 | } 867 | ], 868 | "source": [ 869 | "mop_file_id" 870 | ] 871 | }, 872 | { 873 | "cell_type": "markdown", 874 | "metadata": {}, 875 | "source": [ 876 | "---\n", 877 | "**Exercise 2**: Plot 3-dimensional data\n", 878 | "\n", 879 | "Plot *AOD_lat*, *AOD_lon*, and *AOD_500* (which we imported from the \"JRR-AOD_v2r3_j01_...\" netCDF file as:\n", 880 | "\n", 881 | "1. Check the dimensions for all variables using *.shape*.\n", 882 | "2. Do you need to generate a meshgrid with *np.meshgrid()*?\n", 883 | "3. Create a contour plot\n", 884 | "\n", 885 | "---\n", 886 | "**Solution:**" 887 | ] 888 | }, 889 | { 890 | "cell_type": "code", 891 | "execution_count": 12, 892 | "metadata": {}, 893 | "outputs": [], 894 | "source": [ 895 | "fname='data/JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc'\n", 896 | "aod_file_id = xr.open_dataset(fname, engine='h5netcdf')\n", 897 | "\n", 898 | "AOD_550 = aod_file_id['AOD550']\n", 899 | "AOD_lat = aod_file_id['Latitude']\n", 900 | "AOD_lon = aod_file_id['Longitude']" 901 | ] 902 | }, 903 | { 904 | "cell_type": "code", 905 | "execution_count": 13, 906 | "metadata": {}, 907 | "outputs": [ 908 | { 909 | "data": { 910 | "text/plain": [ 911 | "((768, 3200), (768, 3200))" 912 | ] 913 | }, 914 | "execution_count": 13, 915 | "metadata": {}, 916 | "output_type": "execute_result" 917 | } 918 | ], 919 | "source": [ 920 | "AOD_lat.shape, AOD_lon.shape" 921 | ] 922 | }, 923 | { 924 | "cell_type": "code", 925 | "execution_count": 14, 926 | "metadata": {}, 927 | "outputs": [ 928 | { 929 | "data": { 930 | "image/png": "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", 931 | "text/plain": [ 932 | "
" 933 | ] 934 | }, 935 | "metadata": {}, 936 | "output_type": "display_data" 937 | } 938 | ], 939 | "source": [ 940 | "fig = plt.figure() \n", 941 | "ax = plt.subplot()\n", 942 | "co_plot = ax.contourf(AOD_lon, AOD_lat, AOD_550)\n", 943 | "fig.colorbar(co_plot, orientation='horizontal')\n", 944 | "plt.show()" 945 | ] 946 | }, 947 | { 948 | "cell_type": "markdown", 949 | "metadata": {}, 950 | "source": [ 951 | "---\n", 952 | "**Exercise 3** Adding maps to plots\n", 953 | "\n", 954 | "Using *AOD_lat*, *AOD_lon*, and *AOD_550* (which we imported from the \"JRR-AOD_v2r3_j01_...\" netCDF file):\n", 955 | "\n", 956 | "1. Create a *contourf* plot (same as Exercise 2)\n", 957 | "2. Add the coastlines to a standard Plate Caree plot using *projection=* option.\n", 958 | "\n", 959 | "---\n", 960 | "**Solution**:" 961 | ] 962 | }, 963 | { 964 | "cell_type": "code", 965 | "execution_count": 15, 966 | "metadata": {}, 967 | "outputs": [ 968 | { 969 | "data": { 970 | "image/png": "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", 971 | "text/plain": [ 972 | "
" 973 | ] 974 | }, 975 | "metadata": {}, 976 | "output_type": "display_data" 977 | } 978 | ], 979 | "source": [ 980 | "fig = plt.figure()\n", 981 | "ax = plt.subplot(projection=ccrs.PlateCarree())\n", 982 | "\n", 983 | "ax.contourf(AOD_lon, AOD_lat, AOD_550)\n", 984 | "\n", 985 | "ax.coastlines('50m')\n", 986 | "plt.show()" 987 | ] 988 | } 989 | ], 990 | "metadata": { 991 | "kernelspec": { 992 | "display_name": "Python 3.11.0 ('notebook_demo')", 993 | "language": "python", 994 | "name": "python3" 995 | }, 996 | "language_info": { 997 | "codemirror_mode": { 998 | "name": "ipython", 999 | "version": 3 1000 | }, 1001 | "file_extension": ".py", 1002 | "mimetype": "text/x-python", 1003 | "name": "python", 1004 | "nbconvert_exporter": "python", 1005 | "pygments_lexer": "ipython3", 1006 | "version": "3.11.0" 1007 | }, 1008 | "vscode": { 1009 | "interpreter": { 1010 | "hash": "4589143d4cda0c8671911bd60c16dc1d10ec327722e7574bc882b745b51509b4" 1011 | } 1012 | } 1013 | }, 1014 | "nbformat": 4, 1015 | "nbformat_minor": 4 1016 | } 1017 | -------------------------------------------------------------------------------- /data/JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-tools-workshop/AGU-python-workshop-2022/3bcc622e8b92ba9bfb61e188860f75298371df24/data/JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc -------------------------------------------------------------------------------- /data/MOP03JM-201811-L3V95.6.3_thinned.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-tools-workshop/AGU-python-workshop-2022/3bcc622e8b92ba9bfb61e188860f75298371df24/data/MOP03JM-201811-L3V95.6.3_thinned.nc -------------------------------------------------------------------------------- /data/gfs_3_20200915_0000_000.grb2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-tools-workshop/AGU-python-workshop-2022/3bcc622e8b92ba9bfb61e188860f75298371df24/data/gfs_3_20200915_0000_000.grb2 -------------------------------------------------------------------------------- /data/sst.mon.ltm.1981-2010.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-tools-workshop/AGU-python-workshop-2022/3bcc622e8b92ba9bfb61e188860f75298371df24/data/sst.mon.ltm.1981-2010.nc -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: python-workshop 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python=3.9 6 | - numpy 7 | - matplotlib 8 | - pandas 9 | - cartopy 10 | - h5netcdf 11 | - netcdf4 12 | - pydap 13 | - pyproj 14 | - eccodes 15 | - cython 16 | - pygrib 17 | - s3fs 18 | - scipy 19 | - xarray 20 | -------------------------------------------------------------------------------- /img/flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-tools-workshop/AGU-python-workshop-2022/3bcc622e8b92ba9bfb61e188860f75298371df24/img/flowchart.png -------------------------------------------------------------------------------- /sample_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import numpy as np 5 | import pandas as pd 6 | import matplotlib.pyplot as plt 7 | from netCDF4 import Dataset 8 | from cartopy import crs as ccrs 9 | 10 | # Open file 11 | fname='data/JRR-AOD_v2r3_j01_s202009152044026_e202009152045271_c202009152113150_thinned.nc' 12 | aod_file_id = Dataset(fname) 13 | 14 | # Import variables 15 | AOD_550 = aod_file_id.variables['AOD550'][:,:] 16 | AOD_lat = aod_file_id.variables['Latitude'][:,:] 17 | AOD_lon = aod_file_id.variables['Longitude'][:,:] 18 | 19 | # Make figure 20 | fig = plt.figure() 21 | ax = plt.subplot() 22 | co_plot = ax.contourf(AOD_lon, AOD_lat, AOD_550) 23 | fig.colorbar(co_plot, orientation='horizontal') 24 | plt.savefig("AOD_plot.png") 25 | --------------------------------------------------------------------------------