{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# NCL_panel_6.py\nThis script illustrates the following concepts:\n   - Paneling four plots on a page\n   - Adding white space around paneled plots\n\nSee following URLs to see the reproduced NCL plot & script:\n    - Original NCL script: https://www.ncl.ucar.edu/Applications/Scripts/panel_6.ncl\n    - Original NCL plot: https://www.ncl.ucar.edu/Applications/Images/panel_6_1_lg.png and https://www.ncl.ucar.edu/Applications/Images/panel_6_2_lg.png\nNote:\n    A different colormap was used in this example than in the NCL example\n    because rainbow colormaps do not translate well to black and white formats,\n    are not accessible for individuals affected by color blindness, and\n    vary widely in how they are percieved by different people. See this\n    `example <https://geocat-examples.readthedocs.io/en/latest/gallery/Colors/CB_Temperature.html#sphx-glr-gallery-colors-cb-temperature-py>`_\n    for more information on choosing colormaps.\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\nimport cartopy.feature as cfeature\nimport matplotlib.pyplot as plt\nimport matplotlib.ticker as mticker\nimport matplotlib.contour as mcontour\nfrom mpl_toolkits.axes_grid1.inset_locator import inset_axes\nimport numpy as np\nimport xarray as xr\n\nimport geocat.datafiles as gdf\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/h_avg_Y0191_D000.00.nc\"),\n                     decode_times=False)\n\ndata0 = ds.T.isel(time=0, drop=True).isel(z_t=0, drop=True)\ndata1 = ds.T.isel(time=0, drop=True).isel(z_t=5, drop=True)\ndata2 = ds.S.isel(time=0, drop=True).isel(z_t=0, drop=True)\ndata3 = ds.S.isel(time=0, drop=True).isel(z_t=3, drop=True)\n\ndata0 = gvutil.xr_add_cyclic_longitudes(data0, \"lon_t\")\ndata1 = gvutil.xr_add_cyclic_longitudes(data1, \"lon_t\")\ndata2 = gvutil.xr_add_cyclic_longitudes(data2, \"lon_t\")\ndata3 = gvutil.xr_add_cyclic_longitudes(data3, \"lon_t\")\n\ndata = [[data0, data1], [data2, data3]]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Plot without extra whitespace:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "projection = ccrs.NorthPolarStereo()\nfig, axs = plt.subplots(2,\n                        2,\n                        figsize=(8, 8),\n                        subplot_kw=dict(projection=projection))\n\n# Format axes and inset axes for color bars\ncax = np.empty((2, 2), dtype=plt.Axes)\nfor row in range(0, 2):\n    for col in range(0, 2):\n        # Add map features\n        axs[row][col].add_feature(cfeature.LAND, facecolor='silver', zorder=2)\n        axs[row][col].add_feature(cfeature.COASTLINE, linewidth=0.5, zorder=3)\n        axs[row][col].add_feature(cfeature.LAKES,\n                                  linewidth=0.5,\n                                  edgecolor='black',\n                                  facecolor='None',\n                                  zorder=4)\n\n        # Add gridlines\n        gl = axs[row][col].gridlines(ccrs.PlateCarree(),\n                                     draw_labels=False,\n                                     color='gray',\n                                     linestyle=\"--\",\n                                     zorder=5)\n        gl.xlocator = mticker.FixedLocator(np.linspace(-180, 150, 12))\n\n        # Add latitude and longitude labels\n        x = np.arange(0, 360, 30)\n        # Array specifying 8S, this makes an offset from the circle boundary\n        # which lies at the equator\n        y = np.full_like(x, -8)\n        labels = [\n            '0', '30E', '60E', '90E', '120E', '150E', '180', '150W', '120W',\n            '90W', '60W', '30W'\n        ]\n        for x, y, label in zip(x, y, labels):\n            if label == '180':\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='top',\n                                   transform=ccrs.Geodetic())\n            elif label == '0':\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='bottom',\n                                   transform=ccrs.Geodetic())\n            else:\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='center',\n                                   transform=ccrs.Geodetic())\n\n        # Set boundary of plot to be circular\n        gvutil.set_map_boundary(axs[row][col], (-180, 180), (0, 90),\n                                south_pad=1)\n        # Create inset axes for color bars\n        cax[row][col] = inset_axes(axs[row][col],\n                                   width='5%',\n                                   height='100%',\n                                   loc='lower right',\n                                   bbox_to_anchor=(0.175, 0, 1, 1),\n                                   bbox_transform=axs[row][col].transAxes,\n                                   borderpad=0)\n# Import color map\ncmap = \"magma\"\n\n# Plot filled contours\ncontour = np.empty((2, 2), dtype=mcontour.ContourSet)\ncontour[0][0] = data[0][0].plot.contourf(ax=axs[0][0],\n                                         cmap=cmap,\n                                         levels=np.arange(-2, 34, 2),\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[0][1] = data[0][1].plot.contourf(ax=axs[0][1],\n                                         cmap=cmap,\n                                         levels=np.arange(-4, 30, 2),\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[1][0] = data[1][0].plot.contourf(ax=axs[1][0],\n                                         cmap=cmap,\n                                         levels=15,\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[1][1] = data[1][1].plot.contourf(ax=axs[1][1],\n                                         cmap=cmap,\n                                         levels=12,\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\n\n# Plot contour lines\ndata[0][0].plot.contour(ax=axs[0][0],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=np.arange(-2, 34, 2),\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[0][1].plot.contour(ax=axs[0][1],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=np.arange(-4, 30, 2),\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[1][0].plot.contour(ax=axs[1][0],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=15,\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[1][1].plot.contour(ax=axs[1][1],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=12,\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\n\n# Create colorbars and reduce the font size\nfor row in range(0, 2):\n    for col in range(0, 2):\n        cbar = plt.colorbar(contour[row][col], cax=cax[row][col])\n        cbar.ax.tick_params(labelsize=7)\n\n# Format titles for each subplot\nfor row in range(0, 2):\n    for col in range(0, 2):\n        axs[row][col].set_title(data[row][col].long_name,\n                                loc='left',\n                                fontsize=7,\n                                pad=20)\n        axs[row][col].set_title(data[row][col].units,\n                                loc='right',\n                                fontsize=7,\n                                pad=20)\n\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Plot with extra whitespace:\n\nThe keyword argument ``gridspec_kw`` accepts a dictionary with keywords passed\nto the GridSpec constructor used to create the grid the subplots are placed\non. See the documentation for `GridSpec <https://matplotlib.org/3.2.2/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec>`_\nfor more information on how to manipulate the gridlayout.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "projection = ccrs.NorthPolarStereo()\nfig, axs = plt.subplots(2,\n                        2,\n                        figsize=(8, 8),\n                        gridspec_kw=(dict(wspace=0.5)),\n                        subplot_kw=dict(projection=projection))\n#\n# Everything beyond this is the same code for the example without extra white space\n#\n\n# Format axes and inset axes for color bars\ncax = np.empty((2, 2), dtype=plt.Axes)\nfor row in range(0, 2):\n    for col in range(0, 2):\n        # Add map features\n        axs[row][col].add_feature(cfeature.LAND, facecolor='silver', zorder=2)\n        axs[row][col].add_feature(cfeature.COASTLINE, linewidth=0.5, zorder=3)\n        axs[row][col].add_feature(cfeature.LAKES,\n                                  linewidth=0.5,\n                                  edgecolor='black',\n                                  facecolor='None',\n                                  zorder=4)\n\n        # Add gridlines\n        gl = axs[row][col].gridlines(ccrs.PlateCarree(),\n                                     draw_labels=False,\n                                     color='gray',\n                                     linestyle=\"--\",\n                                     zorder=5)\n        gl.xlocator = mticker.FixedLocator(np.linspace(-180, 150, 12))\n\n        # Add latitude and longitude labels\n        x = np.arange(0, 360, 30)\n        # Array specifying 8S, this makes an offset from the circle boundary\n        # which lies at the equator\n        y = np.full_like(x, -8)\n        labels = [\n            '0', '30E', '60E', '90E', '120E', '150E', '180', '150W', '120W',\n            '90W', '60W', '30W'\n        ]\n        for x, y, label in zip(x, y, labels):\n            if label == '180':\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='top',\n                                   transform=ccrs.Geodetic())\n            elif label == '0':\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='bottom',\n                                   transform=ccrs.Geodetic())\n            else:\n                axs[row][col].text(x,\n                                   y,\n                                   label,\n                                   fontsize=7,\n                                   horizontalalignment='center',\n                                   verticalalignment='center',\n                                   transform=ccrs.Geodetic())\n\n        # Set boundary of plot to be circular\n        gvutil.set_map_boundary(axs[row][col], (-180, 180), (0, 90),\n                                south_pad=1)\n        # Create inset axes for color bars\n        cax[row][col] = inset_axes(axs[row][col],\n                                   width='5%',\n                                   height='100%',\n                                   loc='lower right',\n                                   bbox_to_anchor=(0.175, 0, 1, 1),\n                                   bbox_transform=axs[row][col].transAxes,\n                                   borderpad=0)\n# Import color map\ncmap = \"magma\"\n\n# Plot filled contours\ncontour = np.empty((2, 2), dtype=mcontour.ContourSet)\ncontour[0][0] = data[0][0].plot.contourf(ax=axs[0][0],\n                                         cmap=cmap,\n                                         levels=np.arange(-2, 34, 2),\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[0][1] = data[0][1].plot.contourf(ax=axs[0][1],\n                                         cmap=cmap,\n                                         levels=np.arange(-4, 30, 2),\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[1][0] = data[1][0].plot.contourf(ax=axs[1][0],\n                                         cmap=cmap,\n                                         levels=15,\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\ncontour[1][1] = data[1][1].plot.contourf(ax=axs[1][1],\n                                         cmap=cmap,\n                                         levels=12,\n                                         transform=ccrs.PlateCarree(),\n                                         add_colorbar=False,\n                                         zorder=0)\n\n# Plot contour lines\ndata[0][0].plot.contour(ax=axs[0][0],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=np.arange(-2, 34, 2),\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[0][1].plot.contour(ax=axs[0][1],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=np.arange(-4, 30, 2),\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[1][0].plot.contour(ax=axs[1][0],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=15,\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\ndata[1][1].plot.contour(ax=axs[1][1],\n                        colors='black',\n                        linestyles='solid',\n                        linewidths=0.5,\n                        levels=12,\n                        transform=ccrs.PlateCarree(),\n                        zorder=1)\n\n# Create colorbars and reduce the font size\nfor row in range(0, 2):\n    for col in range(0, 2):\n        cbar = plt.colorbar(contour[row][col], cax=cax[row][col])\n        cbar.ax.tick_params(labelsize=7)\n\n# Format titles for each subplot\nfor row in range(0, 2):\n    for col in range(0, 2):\n        axs[row][col].set_title(data[row][col].long_name,\n                                loc='left',\n                                fontsize=7,\n                                pad=20)\n        axs[row][col].set_title(data[row][col].units,\n                                loc='right',\n                                fontsize=7,\n                                pad=20)\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
}