{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# NCL_dev_2.py\nThis script illustrates the following concepts:\n   - Calculating deviation from zonal mean\n   - Drawing zonal average plots\n   - Moving the contour informational label into the plot\n   - Changing the background color of the contour line labels\n   - Spanning part of a color map for contour fill\n   - Making the colorbar be vertical\n   - Paneling four subplots in a two by two grid using `gridspec`\n   - Changing the aspect ratio of a subplot\n   - Drawing color-filled contours over a cylindrical equidistant map\n   - Using a blue-white-red color map\n\nSee following URLs to see the reproduced NCL plot & script:\n    - Original NCL script: https://www.ncl.ucar.edu/Applications/Scripts/dev_2.ncl\n    - Original NCL plot: https://www.ncl.ucar.edu/Applications/Images/dev_2_lg.png\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Import packages:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import cartopy.crs as ccrs\nfrom cartopy.mpl.gridliner import LongitudeFormatter, LatitudeFormatter\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport xarray as xr\n\nimport geocat.datafiles as gdf\nfrom geocat.viz import cmaps as gvcmaps\nimport geocat.viz.util as gvutil"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Read in data:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Open a netCDF data file using xarray default engine and load the data into xarrays\nds = xr.open_dataset(gdf.get(\"netcdf_files/b003_TS_200-299.nc\"),\n                     decode_times=False)\n\n# Extract slice of data at first timestep\nTS_0 = ds.TS.isel(time=0).drop('time')\n\n# Calculate zonal mean\nmean = TS_0.mean(dim='lon')\n\n# Calculate deviation from time average by finding the temperatures averaged\n# over all timesteps. Then that average is subtracted from the first timestep\ntime_avg = ds.TS.mean(dim='time')\ntime_dev = TS_0 - time_avg\n\n# Fix the artifact of not-shown-data around 0 and 360-degree longitudes\nTS_0 = gvutil.xr_add_cyclic_longitudes(TS_0, \"lon\")\ntime_dev = gvutil.xr_add_cyclic_longitudes(time_dev, \"lon\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Plot:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Specify projection for maps\nproj = ccrs.PlateCarree()\n\n# Generate figure (set its size (width, height) in inches)\nfig = plt.figure(figsize=(8, 8))\n\n# Create girdspec for layout, width_ratio is used to make the plots on the\n# right narrower than the ones on the left\ngrid = fig.add_gridspec(ncols=2, nrows=2, width_ratios=[0.85, 0.15],\n                        wspace=0.08)\n\n# Create axis for plot with data from first timestep\nax1 = fig.add_subplot(grid[0, 0], projection=ccrs.PlateCarree())\nax1.coastlines(linewidths=0.25)\n\n# Create axis for zonal mean temperature plot\nax2 = fig.add_subplot(grid[0, 1], aspect=1.73)\n\n# Create axis for deviation from time data plot\nax3 = fig.add_subplot(grid[1, 0], projection=ccrs.PlateCarree())\nax3.coastlines(linewidths=0.25)\n\n# Create axis for colorbar\nax4 = fig.add_subplot(grid[1, 1], aspect=10)\n\n# Format ticks and ticklabels for the map axes\nfor ax in [ax1, ax3]:\n    # Use the geocat.viz function to set axes limits and ticks\n    gvutil.set_axes_limits_and_ticks(ax, xlim=[-180, 180], ylim=[-90, 90],\n                                     xticks=np.arange(-180, 181, 30),\n                                     yticks=np.arange(-90, 91, 30))\n\n    # Use the geocat.viz function to add minor ticks\n    gvutil.add_major_minor_ticks(ax)\n\n    # Use geocat.viz.util convenience function to make plots look like NCL\n    # plots by using latitude, longitude tick labels\n    gvutil.add_lat_lon_ticklabels(ax)\n\n    # Removing degree symbol from tick labels to resemble NCL example\n    ax.yaxis.set_major_formatter(LatitudeFormatter(degree_symbol=''))\n    ax.xaxis.set_major_formatter(LongitudeFormatter(degree_symbol=''))\n\n# Use the geocat.viz function to set axes limits and ticks for zonal average plot\ngvutil.set_axes_limits_and_ticks(ax2, xlim=[200, 310], ylim=[-90, 90],\n                                 xticks=[200, 240, 280], yticks=[])\n\n# Use the geocat.viz function to add minor ticks to zonal average plot\ngvutil.add_major_minor_ticks(ax2, x_minor_per_major=2)\n\n\n# Plot contour lines for data at first timestep\ncontour = TS_0.plot.contour(ax=ax1, transform=proj, vmin=235, vmax=305,\n                            levels=np.arange(210, 311, 10), colors='black',\n                            linewidths=0.25, add_labels=False)\n\n# Label every other contour lines\nax1.clabel(contour, np.arange(220, 311, 20), fmt='%d', inline=True,\n           fontsize=10)\n\n# Set label backgrounds white\nfor txt in contour.labelTexts:\n    txt.set_bbox(dict(facecolor='white', edgecolor='none', pad=0))\n\n# Add lower text box\nax1.text(0.995, 0.03, \"CONTOUR FROM 210 TO 310 BY 10\",\n         horizontalalignment='right',\n         transform=ax1.transAxes,\n         fontsize=8,\n         bbox=dict(boxstyle='square, pad=0.25', facecolor='white',\n                   edgecolor='black'),\n         zorder=5)\n\n# Add titles to top plot\nsize = 10\ny = 1.05\nax1.set_title('Time(0)', fontsize=size, y=y)\nax1.set_title(TS_0.long_name, fontsize=size, loc='left', y=y)\nax1.set_title(TS_0.units, fontsize=size, loc='right', y=y)\n\n# Plot zonal mean temperature\nax2.plot(mean.data, mean.lat, color='black', linewidth=0.5)\n\n# Plot vertical reference line in zonal mean plot\nax2.axvline(273.15, color='black', linewidth=0.5)\n\n# Import color map\ncmap = gvcmaps.BlWhRe\n\n# Truncate colormap to only use paler colors in the center of the colormap\ncmap = gvutil.truncate_colormap(cmap, minval=0.22, maxval=0.74, n=14)\n\n# Plot filled contour for deviation from time avg plot\ndeviations = time_dev.plot.contourf(ax=ax3, transform=proj, vmin=-14, vmax=18,\n                                    levels=np.arange(-14, 20, 2), cmap=cmap,\n                                    add_colorbar=False, add_labels=False)\n\n# Draw contour lines for deviation from time avg plot\ntime_dev.plot.contour(ax=ax3, transform=proj, vmin=-14, vmax=18,\n                      levels=np.arange(-14, 20, 2), colors='black',\n                      linewidths=0.25, linestyles='solid', add_labels=False)\n\n# Add titles to bottom plot\nax3.set_title('Deviation from time ave', fontsize=size, y=y)\nax3.set_title(ds.TS.long_name, fontsize=size, loc='left', y=y)\nax3.set_title(ds.TS.units, fontsize=size, loc='right', y=y)\n\n# Add colorbar\nplt.colorbar(deviations, cax=ax4, ticks=np.linspace(-12, 16, 15),\n             drawedges=True)\n\nplt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}