{ "cells": [ { "cell_type": "markdown", "id": "1ca2a6f5-bd5a-4520-8380-baf5cb536d41", "metadata": {}, "source": [ "## ADF Diagnostics In Jupyter\n", "This notebook will run the Atmospheric Diagnostic Framework using the settings in a config.yaml file in your ADF directory. \n", "\n", "Note that it was developed to run on Cheyenne/Caspar *with the NPL (conda) kernel*" ] }, { "cell_type": "markdown", "id": "7eea8d1a-d6a7-4464-bd6d-8194aa2368d0", "metadata": { "tags": [] }, "source": [ "### Setup\n", "#### Required packages" ] }, { "cell_type": "code", "execution_count": null, "id": "4d0264e2-c116-4e18-af33-0ce3adabcd60", "metadata": {}, "outputs": [], "source": [ "import os.path\n", "from pathlib import Path\n", "import sys" ] }, { "cell_type": "markdown", "id": "6566766f-9d8f-4428-bf01-3c36a1ffeb63", "metadata": {}, "source": [ "#### Paths" ] }, { "cell_type": "code", "execution_count": null, "id": "9e627890-a0a9-42d9-bb23-302abfedd944", "metadata": {}, "outputs": [], "source": [ "### default parameters\n", "# adf_path = \"../../externals/ADF\"\n", "# config_path = \".\"\n", "# config_fil_str = \"config_f.cam6_3_119.FLTHIST_ne30.r328_gamma0.33_soae_numcin3.001_vs_f.cam6_3_119.FLTHIST_ne30.r328_gamma0.33_soae.001.yaml\"" ] }, { "cell_type": "code", "execution_count": null, "id": "5ec97fae-f7f3-40cc-adf0-3f6726753215", "metadata": { "tags": [ "parameters" ] }, "outputs": [], "source": [ "# cell to insert parameters" ] }, { "cell_type": "markdown", "id": "a88e305c-5473-4de6-9aa5-bf674ecd899f", "metadata": {}, "source": [ "#### All path processing:\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "66a55cfa-2d81-4298-8623-4ceaf3c0fb1f", "metadata": {}, "outputs": [], "source": [ "# Determine ADF directory path\n", "# If it is in your cwd, set adf_path = local_path,\n", "# otherwise set adf_path appropriately\n", "\n", "local_path = os.path.abspath(\"\")\n", "\n", "# Set up the ADF for your location/user name\n", "# user = \"richling\"\n", "# adf_path = f\"/glade/work/{user}/ADF/\"\n", "\n", "print(f\"current working directory = {local_path}\")\n", "print(f\"ADF path = {adf_path}\")" ] }, { "cell_type": "code", "execution_count": null, "id": "1689b448-daf6-44ca-9c9e-b1345490b552", "metadata": {}, "outputs": [], "source": [ "# set path to ADF lib\n", "lib_path = os.path.join(adf_path, \"lib\")\n", "print(f\"The lib scripts live here, right? {lib_path}\")\n", "\n", "# Add paths to python path:\n", "sys.path.append(lib_path)" ] }, { "cell_type": "code", "execution_count": null, "id": "f927cc3e-7fa9-4347-b44e-956c7ebdc742", "metadata": {}, "outputs": [], "source": [ "# set path to ADF plotting scripts directory\n", "plotting_scripts_path = os.path.join(adf_path, \"scripts\", \"plotting\")\n", "print(f\"The plotting scripts live here, right? {plotting_scripts_path}\")\n", "\n", "# Add paths to python path:\n", "sys.path.append(plotting_scripts_path)" ] }, { "cell_type": "markdown", "id": "159be7f2-8593-483a-b200-daf8c3c992c8", "metadata": {}, "source": [ "#### Import config file into ADF object\n", "If there are errors, here, it is likely due to path errors above" ] }, { "cell_type": "code", "execution_count": null, "id": "cd4918d2-dcc0-417b-8867-d368c4cb1d78", "metadata": {}, "outputs": [], "source": [ "config_file = os.path.join(config_path, config_fil_str)" ] }, { "cell_type": "code", "execution_count": null, "id": "f553607f-cd31-4aa3-8142-4959b3569a1a", "metadata": {}, "outputs": [], "source": [ "# import ADF diagnostics object\n", "from adf_diag import AdfDiag\n", "\n", "# If this fails, check your paths output in the cells above,\n", "# and that you are running the NPL (conda) Kernel\n", "# You can see all the paths being examined by un-commenting the following:\n", "# sys.path" ] }, { "cell_type": "code", "execution_count": null, "id": "4ac46243-f980-41e1-9f8c-8d8ad361bb89", "metadata": {}, "outputs": [], "source": [ "# Initialize ADF object\n", "adf = AdfDiag(config_file)\n", "adf" ] }, { "cell_type": "markdown", "id": "c7d266a8-f006-468d-96d5-51d9a93dd6dd", "metadata": { "tags": [] }, "source": [ "### ADF Standard Work Flow" ] }, { "cell_type": "markdown", "id": "1b1d075b-232d-4466-a6be-192c457ae5a9", "metadata": {}, "source": [ "#### Calculate the Time Series files\n", "\n", "* NOTE: If not comparing against observations, you must run _create_time_series()_ again with baseline flag" ] }, { "cell_type": "code", "execution_count": null, "id": "5f056e6d-5828-434d-b70b-f60627f30ba1", "metadata": { "tags": [] }, "outputs": [], "source": [ "# Create model time series.\n", "adf.create_time_series()\n", "\n", "# Create model baseline time series (if needed):\n", "if not adf.compare_obs:\n", " adf.create_time_series(baseline=True)" ] }, { "cell_type": "markdown", "id": "4ec72ce9-8167-435c-8334-728e2df24a01", "metadata": {}, "source": [ "#### Calculate the Climo files\n", "\n", "* NOTE: Do not need to specify or repeat for baseline case unlike time series generation" ] }, { "cell_type": "code", "execution_count": null, "id": "85a611c7-a90b-4d24-a518-046407564e35", "metadata": { "tags": [] }, "outputs": [], "source": [ "# Create model climatology (climo) files.\n", "adf.create_climo()" ] }, { "cell_type": "markdown", "id": "0dc28ffb-f501-4a42-8e21-cd8b993163ea", "metadata": {}, "source": [ "#### Regrid the Climo files" ] }, { "cell_type": "code", "execution_count": null, "id": "9673eada-6eeb-4c68-b59a-bd7baf62aca1", "metadata": { "tags": [] }, "outputs": [], "source": [ "# Regrid model climatology files to match either\n", "# observations or CAM baseline climatologies.\n", "# This call uses the \"regridding_scripts\" specified in the config file:\n", "adf.regrid_climo()" ] }, { "cell_type": "markdown", "id": "56434dfe-187d-43a8-967c-5cf027e1b05b", "metadata": {}, "source": [ "#### Run statistics on Time Series files" ] }, { "cell_type": "markdown", "id": "e40c90be-b041-46b6-b268-3f3f02ea855a", "metadata": { "tags": [] }, "source": [ "#Perform analyses on the simulation(s).\n", "#This call uses the \"analysis_scripts\" specified in the config file:\n", "adf.perform_analyses()" ] }, { "cell_type": "markdown", "id": "e12c5b56-2a54-49c9-816c-9d447d511a9d", "metadata": {}, "source": [ "#### Create Plots" ] }, { "cell_type": "markdown", "id": "31c8782b-1492-4260-bfea-48a69169e30a", "metadata": { "tags": [] }, "source": [ "#Create plots.\n", "#This call uses the \"plotting_scripts\" specified in the config file:\n", "adf.create_plots()\n" ] }, { "cell_type": "markdown", "id": "898b1090-aad9-45b2-a0f2-2882ae8f9834", "metadata": {}, "source": [ "#### Generate HTML files\n", "\n", "* This will create html files that you can view via webbrower either:\n", " - in Casper/Cheyenne\n", " - pushing it to CGD projects webpage through Tungsten" ] }, { "cell_type": "markdown", "id": "f391772b-8f17-40bc-b87d-d9b27b0a8bba", "metadata": { "tags": [] }, "source": [ "#Create website.\n", "if adf.create_html:\n", " adf.create_website()" ] }, { "cell_type": "markdown", "id": "11d4e7cd-49f5-4a68-85a1-ad18fa2a6706", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "29b2605d-519c-4305-ab2b-47c5c053a00c", "metadata": {}, "source": [ "## ADF Helpful Methods and Structures \n", "\n", "Demonstration of a few methods to get information from the ADF object" ] }, { "cell_type": "markdown", "id": "cdd8063d-195b-42bc-99a4-37ea0f9a62a0", "metadata": {}, "source": [ "#### List all adf object related methods" ] }, { "cell_type": "code", "execution_count": null, "id": "d3d9703e-5053-4a3f-9745-2a6cddfa4f6c", "metadata": {}, "outputs": [], "source": [ "dir(adf)" ] }, { "cell_type": "code", "execution_count": null, "id": "b6f3971d-14de-4d7d-996b-39e4bda99d1d", "metadata": {}, "outputs": [], "source": [ "adf.num_procs" ] }, { "cell_type": "markdown", "id": "4583376e-6ac3-4f0f-81d0-f4e92ce13124", "metadata": {}, "source": [ "### Get information from the subsections of the config yaml file\n", "\n", "Remember the different sub-sections?" ] }, { "cell_type": "markdown", "id": "ad924a19-81ba-49dc-8e3b-2bb44f2b5114", "metadata": {}, "source": [ "#### Basic Info Section" ] }, { "cell_type": "code", "execution_count": null, "id": "e3904cb9-a618-43af-9605-e6fcd4e7fd59", "metadata": {}, "outputs": [], "source": [ "basic_info_dict = adf.read_config_var(\"diag_basic_info\")\n", "\n", "for key, val in basic_info_dict.items():\n", " print(f\"{key}: {val}\")" ] }, { "cell_type": "markdown", "id": "e8b1de2f-2a36-472f-b0ae-517845245473", "metadata": {}, "source": [ "#### Test Case Info Section" ] }, { "cell_type": "code", "execution_count": null, "id": "cccdb0b2-ba50-45d5-8ce5-af6a9161c762", "metadata": {}, "outputs": [], "source": [ "test_dict = adf.read_config_var(\"diag_cam_climo\")\n", "\n", "for key, val in test_dict.items():\n", " print(f\"{key}: {val}\")" ] }, { "cell_type": "markdown", "id": "33a7da55-13a0-49a6-988b-ab7451b49dac", "metadata": {}, "source": [ "#### Baseline Case Info Section" ] }, { "cell_type": "code", "execution_count": null, "id": "9cf8b802-300f-41f6-b6ad-32c4f08c463f", "metadata": {}, "outputs": [], "source": [ "baseline_dict = adf.read_config_var(\"diag_cam_baseline_climo\")\n", "\n", "for key, val in baseline_dict.items():\n", " print(f\"{key}: {val}\")" ] }, { "cell_type": "markdown", "id": "b878fc07-a39a-4ef6-a04c-499280d3d6cb", "metadata": {}, "source": [ "### Get information not directly from the subsections of the config yaml file\n", "\n", "This just represents a different way to get some ADF info" ] }, { "cell_type": "markdown", "id": "721ba2f9-29c8-40ee-a813-181194f46b40", "metadata": {}, "source": [ "#### Get Case/Baseline Names\n", "\n", "This is a different wat to get case names than from the *adf.read_config_var()* method that read in data from sub-sections above" ] }, { "cell_type": "code", "execution_count": null, "id": "55b72978-0af4-4d04-87d6-0c56de58400b", "metadata": {}, "outputs": [], "source": [ "# List of case names (list by default)\n", "case_names = adf.get_cam_info(\"cam_case_name\", required=True)\n", "print(case_names)\n", "\n", "base_name = adf.get_baseline_info(\"cam_case_name\")\n", "print(base_name)" ] }, { "cell_type": "markdown", "id": "898f441c-b001-4165-a614-766183b638ed", "metadata": {}, "source": [ "#### Get Case/Baseline Climo file locations\n", "\n", "Here we are calling directly from the config file, no subsection " ] }, { "cell_type": "code", "execution_count": null, "id": "77ba4bcb-70d7-47cd-a7c5-0b1827baaaf3", "metadata": {}, "outputs": [], "source": [ "case_climo_loc = adf.get_cam_info(\"cam_climo_loc\", required=True)\n", "base_climo_loc = adf.get_baseline_info(\"cam_climo_loc\")\n", "case_climo_loc, base_climo_loc" ] }, { "cell_type": "markdown", "id": "864e9b1f-fef8-4d45-94b6-5e4cc8e099c9", "metadata": {}, "source": [ "#### Get Desired Variable Names\n", "\n", "Here we are calling directly from the config file, no subsection " ] }, { "cell_type": "code", "execution_count": null, "id": "ff7a34b1-6795-46f3-a3b5-a40507b6aa52", "metadata": {}, "outputs": [], "source": [ "var_list = adf.diag_var_list\n", "print(var_list)" ] }, { "cell_type": "markdown", "id": "e8504642-fcfc-482c-b5a8-7494f9fde680", "metadata": {}, "source": [ "#### Get variable defaults from adf_variable_defaults.yaml\n", "\n", "Take a look at what defaults are for TS" ] }, { "cell_type": "code", "execution_count": null, "id": "a3a780fd-6234-4574-8535-ebf6e7bba3fc", "metadata": {}, "outputs": [], "source": [ "adf.variable_defaults[\"TS\"]" ] }, { "cell_type": "markdown", "id": "b2701110-87da-44be-8cc5-a67fe759870e", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "id": "4e847946-aed1-4226-be42-46b46fc945ea", "metadata": {}, "source": [ "## Exploration of the Output Data\n", "\n", "Now that the ADF has created all the necessary timeseries/climo/regridded data let's run a quick set of functions to plot time series for RESTOM, TS, and ICEFRAC" ] }, { "cell_type": "markdown", "id": "5eddc165-065b-4874-a53d-0a53486c1817", "metadata": {}, "source": [ "##### Let's grab the case names, time series locations, variable defaults dictionary and climo years" ] }, { "cell_type": "code", "execution_count": null, "id": "001f31de-2897-4cfd-a7a2-a63a47b63827", "metadata": {}, "outputs": [], "source": [ "case_names = adf.get_cam_info(\"cam_case_name\", required=True)\n", "case_names_len = len(case_names)\n", "data_name = adf.get_baseline_info(\"cam_case_name\", required=False)\n", "\n", "case_ts_locs = adf.get_cam_info(\"cam_ts_loc\", required=True)\n", "data_ts_loc = adf.get_baseline_info(\"cam_ts_loc\", required=False)\n", "\n", "res = adf.variable_defaults # dict of variable-specific plot preferences\n", "# or an empty dictionary if use_defaults was not specified in YAML.\n", "\n", "start_year = adf.climo_yrs[\"syears\"]\n", "end_year = adf.climo_yrs[\"eyears\"]" ] }, { "cell_type": "markdown", "id": "40e35c52-2044-4677-8b7c-d8266bd19b20", "metadata": {}, "source": [ "### Time Series Plotting Functions" ] }, { "cell_type": "code", "execution_count": null, "id": "a123c21a-e27b-4b2b-b674-c77b7912d996", "metadata": {}, "outputs": [], "source": [ "def _load_dataset(fils):\n", " if len(fils) == 0:\n", " print(\"Input file list is empty.\")\n", " return None\n", " elif len(fils) > 1:\n", " return xr.open_mfdataset(fils, combine=\"by_coords\")\n", " else:\n", " sfil = str(fils[0])\n", " return xr.open_dataset(sfil)\n", " # End if\n", "\n", "\n", "# End def" ] }, { "cell_type": "code", "execution_count": null, "id": "eff599aa-4ad7-43b0-8381-a94177e40c6e", "metadata": {}, "outputs": [], "source": [ "def _data_calcs(ts_loc, var, subset=None):\n", " \"\"\"\n", " args\n", " ----\n", " - ts_loc: Path\n", " path to time series file\n", "\n", " - var: str\n", " name of variable\n", "\n", " - subset (optional): dict\n", " lat/lon extents (south, north, east, west)\n", " \"\"\"\n", " fils = sorted(list(Path(ts_loc).glob(f\"*{var}*.nc\")))\n", "\n", " ts_ds = _load_dataset(fils)\n", "\n", " time = ts_ds[\"time\"]\n", " time = xr.DataArray(\n", " ts_ds[\"time_bnds\"].load().mean(dim=\"nbnd\").values,\n", " dims=time.dims,\n", " attrs=time.attrs,\n", " )\n", " ts_ds[\"time\"] = time\n", " ts_ds.assign_coords(time=time)\n", " ts_ds = xr.decode_cf(ts_ds)\n", "\n", " if subset != None:\n", " ts_ds = ts_ds.sel(\n", " lat=slice(subset[\"s\"], subset[\"n\"]), lon=slice(subset[\"w\"], subset[\"e\"])\n", " )\n", "\n", " data = ts_ds[var].squeeze()\n", " unit = data.units\n", "\n", " # global weighting\n", " w = np.cos(np.radians(data.lat))\n", " avg = data.weighted(w).mean(dim=(\"lat\", \"lon\"))\n", "\n", " yrs = np.unique(\n", " [\n", " str(val.item().timetuple().tm_year).zfill(4)\n", " for _, val in enumerate(ts_ds[\"time\"])\n", " ]\n", " )\n", "\n", " return avg, yrs, unit" ] }, { "cell_type": "code", "execution_count": null, "id": "8141a995-7a66-4562-9ea6-472cde4e21f2", "metadata": {}, "outputs": [], "source": [ "def ts_plot(ax, name, vals, yrs, unit, color_dict, linewidth=None, zorder=1):\n", " \"\"\"\n", " args\n", " ----\n", " - color_dict: dict\n", " color and marker style for variable\n", " \"\"\"\n", "\n", " ax.plot(\n", " yrs,\n", " vals,\n", " color_dict[\"marker\"],\n", " c=color_dict[\"color\"],\n", " label=name,\n", " linewidth=linewidth,\n", " zorder=zorder,\n", " )\n", "\n", " ax.set_xlabel(\"Years\", fontsize=15, labelpad=20)\n", " ax.set_ylabel(unit, fontsize=15, labelpad=20)\n", "\n", " # For the minor ticks, use no labels; default NullFormatter.\n", " ax.tick_params(which=\"major\", length=7)\n", " ax.tick_params(which=\"minor\", length=5)\n", "\n", " return ax" ] }, { "cell_type": "code", "execution_count": null, "id": "d7aaeed2-b21f-4610-8b2e-0530d5556b69", "metadata": {}, "outputs": [], "source": [ "def plot_var_details(ax, var, vals_cases, vals_base):\n", " mins = []\n", " maxs = []\n", " for i, val in enumerate(vals_cases):\n", " mins.append(np.nanmin(vals_cases[i]))\n", " maxs.append(np.nanmax(vals_cases[i]))\n", "\n", " mins.append(np.nanmin(vals_base))\n", " maxs.append(np.nanmax(vals_base))\n", "\n", " if var == \"SST\":\n", " ax.set_ylabel(\"K\", fontsize=20, labelpad=12)\n", " tick_spacing = 0.5\n", " ax.yaxis.set_major_locator(MultipleLocator(1))\n", " ax.set_title(f\"Time Series Global: {var} - ANN\", loc=\"left\", fontsize=22)\n", "\n", " if var == \"TS\":\n", " ax.set_ylabel(\"K\", fontsize=20, labelpad=12)\n", " tick_spacing = 0.5\n", " ax.yaxis.set_minor_locator(MultipleLocator(0.5))\n", " ax.set_title(f\"Time Series Global: {var} - ANN\", loc=\"left\", fontsize=22)\n", "\n", " if var == \"ICEFRAC\":\n", " ax.set_ylabel(\"frac\", fontsize=20, labelpad=12)\n", " tick_spacing = 0.1\n", " ax.set_ylim(np.floor(min(mins)), np.ceil(max(maxs)))\n", " ax.set_title(f\"Time Series LabSea: {var} - ANN\", loc=\"left\", fontsize=22)\n", "\n", " if var == \"RESTOM\":\n", " ax.set_ylabel(\"W/m2\", fontsize=20, labelpad=12)\n", " tick_spacing = 0.5\n", " ax.yaxis.set_minor_locator(MultipleLocator(0.1))\n", " ax.set_title(f\"Time Series Global: {var} - ANN\", loc=\"left\", fontsize=22)\n", "\n", " # Set label to show if RESTOM is 1 or 5-yr avg\n", " line_1yr = Line2D(\n", " [],\n", " [],\n", " label=\"1-yr avg\",\n", " color=\"k\",\n", " linewidth=1,\n", " marker=\"*\",\n", " )\n", " line_5yr = Line2D(\n", " [],\n", " [],\n", " label=\"5-yr avg\",\n", " color=\"k\",\n", " linewidth=1,\n", " )\n", " ax.legend(handles=[line_1yr, line_5yr], bbox_to_anchor=(0.99, 0.99))\n", "\n", " # Add extra space on the y-axis, except for ICEFRAC\n", " if var != \"ICEFRAC\":\n", " ax.set_ylim(np.floor(min(mins)), np.ceil(max(maxs)) + tick_spacing)\n", "\n", " ax.yaxis.set_major_locator(MultipleLocator(tick_spacing))\n", "\n", " ax.tick_params(axis=\"y\", which=\"major\", labelsize=16)\n", " ax.tick_params(axis=\"y\", which=\"minor\", labelsize=16)\n", "\n", " ax.tick_params(axis=\"x\", which=\"major\", labelsize=14)\n", " ax.tick_params(axis=\"x\", which=\"minor\", labelsize=14)\n", "\n", " return ax" ] }, { "cell_type": "code", "execution_count": null, "id": "26eb6dfb-eec3-4c89-9964-6495891ca572", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "1fa7a0d8-6d8f-45e1-b606-9507a11764dc", "metadata": {}, "source": [ "### Plot the time series!" ] }, { "cell_type": "code", "execution_count": null, "id": "67e22347-a3b8-4b3c-a68f-38a84ff58454", "metadata": {}, "outputs": [], "source": [ "ts_var_list = [\"RESTOM\", \"TS\", \"ICEFRAC\"]" ] }, { "cell_type": "code", "execution_count": null, "id": "90848bf6-403d-4a3b-a69a-b4ff12f3891b", "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "import matplotlib.pyplot as plt\n", "import xarray as xr\n", "import numpy as np\n", "from matplotlib.ticker import MultipleLocator\n", "from matplotlib.lines import Line2D\n", "\n", "fig = plt.figure(figsize=(30, 15))\n", "\n", "# Change the layout/number of subplots based off number of variables desired\n", "rows = 2\n", "cols = 3\n", "gs = fig.add_gridspec(rows, cols, hspace=0.3, wspace=0.2)\n", "\n", "# Rough subset for Lab Sea\n", "w = -63.5 + 360\n", "e = -47.5 + 360\n", "s = 53.5\n", "n = 65.5\n", "subset = {\"s\": s, \"n\": n, \"e\": e, \"w\": w}\n", "\n", "# Add more colors as needed for number of test cases\n", "# ** Baseline is already added as green dashed line in plotting function **\n", "# matplotlib colors here: https://matplotlib.org/stable/gallery/color/named_colors.html\n", "colors = [\"k\", \"aqua\", \"orange\", \"b\", \"magenta\", \"goldenrod\", \"slategrey\", \"rosybrown\"]\n", "\n", "# Setup plotting\n", "# ---------------\n", "\n", "# Loop over variables:\n", "for i, var in enumerate(ts_var_list):\n", " print(\"Plotting variable:\", var)\n", "\n", " if var == \"RESTOM\":\n", " ax = plt.subplot(gs[0, 0])\n", " if var == \"TS\":\n", " ax = plt.subplot(gs[0, 1])\n", " if var == \"ICEFRAC\":\n", " ax = plt.subplot(gs[0, 2])\n", "\n", " # Grab baseline case:\n", " # --------------------\n", "\n", " if var == \"RESTOM\":\n", " avg_base_FSNT, yrs_base, unit = _data_calcs(data_ts_loc, \"FSNT\")\n", " avg_base_FLNT, _, _ = _data_calcs(data_ts_loc, \"FLNT\")\n", " if len(yrs_base) < 5:\n", " print(\n", " f\"Not a lot of climo years for {data_name}, only doing 1-yr avg for RESTOM...\"\n", " )\n", " FSNT_base = avg_base_FSNT\n", " FLNT_base = avg_base_FLNT\n", " else:\n", " FSNT_base = avg_base_FSNT.rolling(time=60, center=True).mean()\n", " FLNT_base = avg_base_FLNT.rolling(time=60, center=True).mean()\n", "\n", " avg_base = FSNT_base - FLNT_base\n", "\n", " if var == \"TS\" or var == \"SST\":\n", " avg_base, yrs_base, unit = _data_calcs(data_ts_loc, var)\n", "\n", " if var == \"ICEFRAC\":\n", " avg_base, yrs_base, unit = _data_calcs(data_ts_loc, var, subset)\n", "\n", " # Get int of years for plotting on x-axis\n", " yrs_base_int = yrs_base.astype(int)\n", "\n", " # Create yearly averages\n", " vals_base = [avg_base.sel(time=i).mean() for i in yrs_base]\n", "\n", " # Plot baseline data\n", " color_dict = {\"color\": \"g\", \"marker\": \"--\"}\n", " ax = ts_plot(ax, data_name, vals_base, yrs_base_int, unit, color_dict)\n", "\n", " # Loop over test cases:\n", " # ----------------------\n", " # Create lists to hold all sets of years (for each case) and\n", " # sets of var data (for each case)\n", " vals_cases = []\n", " yrs_cases = []\n", " for case_idx, case_name in enumerate(case_names):\n", " if var == \"RESTOM\":\n", " avg_case_FSNT, yrs_case, unit = _data_calcs(case_ts_locs[case_idx], \"FSNT\")\n", " avg_case_FLNT, _, _ = _data_calcs(case_ts_locs[case_idx], \"FLNT\")\n", " if len(yrs_case) < 5:\n", " print(\n", " f\"Not a lot of climo years for {case_name}, only doing 1-yr avg for RESTOM...\"\n", " )\n", " FSNT_case = avg_case_FSNT\n", " FLNT_case = avg_case_FLNT\n", " color_dict = {\"color\": colors[case_idx], \"marker\": \"-*\"}\n", " else:\n", " FSNT_case = avg_case_FSNT.rolling(time=60, center=True).mean()\n", " FLNT_case = avg_case_FLNT.rolling(time=60, center=True).mean()\n", " color_dict = {\"color\": colors[case_idx], \"marker\": \"-\"}\n", "\n", " avg_case = FSNT_case - FLNT_case\n", "\n", " if var == \"TS\":\n", " avg_case, yrs_case, unit = _data_calcs(case_ts_locs[case_idx], var)\n", " color_dict = {\"color\": colors[case_idx], \"marker\": \"-\"}\n", "\n", " if var == \"ICEFRAC\":\n", " avg_case, yrs_case, unit = _data_calcs(case_ts_locs[case_idx], var, subset)\n", " color_dict = {\"color\": colors[case_idx], \"marker\": \"-\"}\n", "\n", " # Get yearly averages for all available years\n", " vals_case = [avg_case.sel(time=i).mean() for i in yrs_case]\n", " vals_cases.append(vals_case)\n", "\n", " # Get int of years for plotting on x-axis\n", " yrs_case_int = yrs_case.astype(int)\n", " yrs_cases.append(yrs_case_int)\n", "\n", " # Add case to plot (ax)\n", " ax = ts_plot(ax, case_name, vals_case, yrs_case_int, unit, color_dict)\n", "\n", " # End for (case names)\n", "\n", " # Get variable details\n", " ax = plot_var_details(ax, var, vals_cases, vals_base)\n", "\n", " # Grab all unique years and find min/max years\n", " uniq_yrs = sorted(x for v in yrs_cases for x in v)\n", " max_year = int(max(uniq_yrs))\n", " min_year = int(min(uniq_yrs))\n", "\n", " last_year = max_year - max_year % 5\n", " if (max_year > 5) and (last_year < max_year):\n", " last_year += 5\n", "\n", " first_year = min_year - min_year % 5\n", " if min_year < 5:\n", " first_year = 0\n", "\n", " ax.set_xlim(first_year, last_year)\n", " ax.set_xlabel(\"Years\", fontsize=15, labelpad=20)\n", " # Set the x-axis plot limits\n", " # to guarantee data from all cases (including baseline) are on plot\n", " ax.set_xlim(min_year, max_year + 1)\n", "\n", " # x-axis ticks and numbers\n", " if max_year - min_year > 120:\n", " ax.xaxis.set_major_locator(MultipleLocator(20))\n", " ax.xaxis.set_minor_locator(MultipleLocator(10))\n", " if 10 <= max_year - min_year <= 120:\n", " ax.xaxis.set_major_locator(MultipleLocator(5))\n", " ax.xaxis.set_minor_locator(MultipleLocator(1))\n", " if 0 < max_year - min_year < 10:\n", " ax.xaxis.set_major_locator(MultipleLocator(1))\n", " ax.xaxis.set_minor_locator(MultipleLocator(1))\n", "\n", " # End for (case loop)\n", "# End for (variables loop)\n", "\n", "# Set up legend\n", "# Gather labels based on case names and plotted line format (color, style, etc)\n", "lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]\n", "lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]\n", "fig.legend(\n", " lines[: case_names_len + 1],\n", " labels[: case_names_len + 1],\n", " loc=\"center left\",\n", " fontsize=18,\n", " bbox_to_anchor=(0.365, 0.4, 0.02, 0.05),\n", ") # bbox_to_anchor(x0, y0, width, height)\n", "\n", "fig.show()\n", "\n", "# plt.savefig(\"TimeSeries_ANN.png\", facecolor='w',bbox_inches=\"tight\")" ] }, { "cell_type": "code", "execution_count": null, "id": "7b037d2f-85c0-4849-a8f1-f4a18d3ddc31", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "NPL 2023a", "language": "python", "name": "npl-2023a" }, "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.9.16" } }, "nbformat": 4, "nbformat_minor": 5 }