From cf69015a464b68ee28cfdd4a27cee4e9d6ca2ca9 Mon Sep 17 00:00:00 2001 From: mgrover1 Date: Thu, 13 Jun 2024 14:20:19 -0600 Subject: [PATCH 1/3] ADD: Add intake-rooki example --- notebooks/use-intake-esgf-with-rooki.ipynb | 409 +++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 notebooks/use-intake-esgf-with-rooki.ipynb diff --git a/notebooks/use-intake-esgf-with-rooki.ipynb b/notebooks/use-intake-esgf-with-rooki.ipynb new file mode 100644 index 0000000..0813a71 --- /dev/null +++ b/notebooks/use-intake-esgf-with-rooki.ipynb @@ -0,0 +1,409 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5191269c-944c-4516-9f51-6cdfc704852a", + "metadata": {}, + "source": [ + "![](http://link.com/to/image.png \"image alt text\")" + ] + }, + { + "cell_type": "markdown", + "id": "fa96801d-4d1a-4264-94f9-9bf12a77421a", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "545103ee-abac-4da8-af3b-c8877a3d2d6c", + "metadata": {}, + "source": [ + "# Using intake-esgf with rooki\n", + "Here we dig into using intake-esgf to search for data, then rooki to do server-side computing!" + ] + }, + { + "cell_type": "markdown", + "id": "7f90a23b-fd23-4339-924f-d665f1d36472", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "d57fa890-a874-4282-bdf2-dfb905678467", + "metadata": {}, + "source": [ + "## Overview\n", + "If you have an introductory paragraph, lead with it here! Keep it short and tied to your material, then be sure to continue into the required list of topics below,\n", + "\n", + "1. This is a numbered list of the specific topics\n", + "1. These should map approximately to your main sections of content\n", + "1. Or each second-level, `##`, header in your notebook\n", + "1. Keep the size and scope of your notebook in check\n", + "1. And be sure to let the reader know up front the important concepts they'll be leaving with" + ] + }, + { + "cell_type": "markdown", + "id": "0b633dab-4c9d-482a-b148-8f9b09102e78", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "| Concepts | Importance | Notes |\n", + "| --- | --- | --- |\n", + "| [Intro to Cartopy](https://foundations.projectpythia.org/core/cartopy/cartopy.html) | Necessary | |\n", + "| [Understanding of NetCDF](https://foundations.projectpythia.org/core/data-formats/netcdf-cf.html) | Helpful | Familiarity with metadata structure |\n", + "| Project management | Helpful | |\n", + "\n", + "- **Time to learn**: estimate in minutes. For a rough idea, use 5 mins per subsection, 10 if longer; add these up for a total. Safer to round up and overestimate.\n", + "- **System requirements**:\n", + " - Populate with any system, version, or non-Python software requirements if necessary\n", + " - Otherwise use the concepts table above and the Imports section below to describe required packages as necessary\n", + " - If no extra requirements, remove the **System requirements** point altogether" + ] + }, + { + "cell_type": "markdown", + "id": "64a5b6f9-eeee-4726-abdc-686e96dfc3cf", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "f7571ba4-43cf-4f61-b74a-a51cdee373aa", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c12d0875-9794-4101-b74f-346148cb36c0", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from rooki import rooki\n", + "from intake_esgf import ESGFCatalog\n", + "import xarray as xr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5dfdb4b-af1f-4dba-a696-eaa59aef95a5", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "363d5d3b-3da5-45a2-9981-e66969fbb227", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def separate_dataset_id(full_dataset):\n", + " return full_dataset[0].split(\"|\")[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "044b088b-a9e0-48e9-ab93-a5a107341367", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ca36d2261499419d8abaf9dc829d1b58", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " Searching indices: 0%| |0/2 [ ?index/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "['CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.tas.gn.v20190308',\n", + " 'CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Amon.tas.gn.v20210114',\n", + " 'CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120',\n", + " 'CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429']" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cat = ESGFCatalog()\n", + "cat.search(\n", + " activity_id='CMIP',\n", + " experiment_id=[\"historical\",],\n", + " variable_id=[\"tas\"],\n", + " member_id='r1i1p1f1',\n", + " grid_label='gn',\n", + " table_id=\"Amon\",\n", + " source_id = [ \"CMCC-ESM2\", \"CanESM5\", \"CESM2\", \"CESM2-FV2\", ]\n", + " )\n", + "\n", + "dsets = [separate_dataset_id(dataset) for dataset in list(cat.df.id.values)]\n", + "dsets" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "399583f8-1889-4939-ba74-2cd448befef6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def query_compute_data(dset_id):\n", + " resp = rooki.subset(\n", + " collection=dset,\n", + " time='1900-01-01/2000-01-31',\n", + " area='65,0,100,35',\n", + " )\n", + " \n", + " if resp.ok:\n", + " ds = resp.datasets()[0]\n", + " else:\n", + " ds = xr.Dataset()\n", + " \n", + " return ds\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "b9a934cf-cda7-4bc4-8859-a2ce247f7066", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from rooki import operators as ops" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "94b2078e-d58b-4a1e-a79f-0011c514a592", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[0;31mInit signature:\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mDocstring:\u001b[0m \n", + "\u001b[0;31mFile:\u001b[0m ~/mambaforge/envs/esgf-cookbook-dev/lib/python3.10/site-packages/rooki/operators.py\n", + "\u001b[0;31mType:\u001b[0m type\n", + "\u001b[0;31mSubclasses:\u001b[0m " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ops.AverageByTime?" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "6036bdce-2e32-49ae-9a6e-34de5ab9e85c", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wf = ops.Input('tas', dsets[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "e756f75d-0c35-4f5b-9d8e-e7c65fd97500", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[0;31mInit signature:\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mDocstring:\u001b[0m \n", + "\u001b[0;31mSource:\u001b[0m \n", + "\u001b[0;32mclass\u001b[0m \u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mOperator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mMETHOD\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"average_time\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFile:\u001b[0m ~/mambaforge/envs/esgf-cookbook-dev/lib/python3.10/site-packages/rooki/operators.py\n", + "\u001b[0;31mType:\u001b[0m type\n", + "\u001b[0;31mSubclasses:\u001b[0m " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ops.AverageByTime??" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "38704069-b1ad-474f-99f6-3273554df831", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def compute_annual_mean_subset(dset_id):\n", + " # Subset by area then time\n", + " wf = ops.AverageByTime(\n", + " ops.Subset(\n", + " ops.Input(\n", + " 'tas', [dsets[0]]\n", + " ),\n", + " time='1900-01-01/2000-12-31',\n", + " area='65,0,100,35',\n", + " ),\n", + " freq=\"year\"\n", + " )\n", + " \n", + " resp = wf.orchestrate()\n", + " \n", + " if resp.ok:\n", + " ds = resp.datasets()[0]\n", + " else:\n", + " ds = xr.Dataset()\n", + " return ds" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "a52e7d71-18fd-4bbe-91a7-fa86725ad4de", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_tvqe5twj/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_xtxuxms6/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_9ntc6sns/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_7hstq_2a/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n" + ] + } + ], + "source": [ + "dset_dict = {}\n", + "for dset in dsets:\n", + " dset_dict[dset] = compute_annual_mean_subset(dset)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "1b08b0a0-7add-4a50-8e62-9bb88b98cc7c", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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cyYmT56MU6dOQavVwt/fH87OzkY1hIiIqDyxtDkqeTp06IAOHToUW30GD5A6OjqiWbNmaNGiBYMUIiKicm706NFYuHBhvv1fffUVxo4da3C9inpUevXqpbjC9evXG9wYIiKicsPChn7WrVuHTZs25dvfpk0bzJ49G/PnzzeoXkWBiqurq+7/hRCIjo6Gq6srmjVrBgBISEhAWlqaVEBDRERUnlna0M+tW7f04oU8Go0GN2/eNLheRYFKVFSU7v8nTpyI1157DYsXL4a1tTUAIDc3F8OHD5daFImIiIgsR+3atRETE5PvxZotW7YYlb5EejLtDz/8gD179uiCFACwtrZGeHg42rRpg88++8zgxhAREZUbFjb0Ex4ejpEjR+LGjRu6ybR//vknvvjiC4OHfQADApWcnBycPn0a9erV09t/+vRpaLVyCauIiIjKLQsLVAYPHozMzEzMnDkTM2bMAAD4+flh0aJFGDBggMH1SgcqgwYNwuDBg/H333+jVatWAIADBw5g9uzZGDRokMENKWlatRZQmnHWXnm2WVv7HMVl7e2UlwUAR9ssxWWdJcq62DySaoezjfK6bVTKv3baMphJtCTJZni1lcg2K6xL7mst026ZDKiy3x8y/04qyXYoXE7lcd0S2WNl25GbI1F3tsQLoFkll003167EqjZLqv/fjDnf3Lz77rt49913cePGDTg4OBTLW8HSgcrnn38OT09PzJs3DykpKQAep9WfMGEC3nvvPaMbRERERGWbMWv7PE06ULGyssKECRMwYcIE3eJDnERLREQkycKGfgDg119/xS+//IIrV64gK0u/N/7IkSMG1WlUH55Go2GQQkREZIC815ON2czJwoULMWjQILi7u+Po0aNo0aIFKlWqhIsXL6JLly4G1yvdo1KjRg2onrG66sWLFw1uDBEREZVN33zzDZYsWYK+ffti2bJlmDBhAmrWrImPP/4Yt2/fNrhe6UDl6TS42dnZOHr0KGJiYjB+/HiDG0JERFSuWNjQz5UrV9CmTRsAgIODA+7evQsA6N+/P1q1aoWvvvrKoHqlA5UxY8YUuP/rr7/G4cOHDWoEERFRuWRmwYYxPD09cevWLfj6+sLX1xcHDhxA48aNkZSUBCHzOtxTiu09sy5dumDdunXFVR0RERGVIR06dMBvv/0GABgyZAjGjRuHTp06oU+fPujZs6fB9Ur3qBTm119/hZubW3FVR0REZNEsba2fJUuW6BK/Dhs2DG5ubtizZw+6deuGYcOGGVyvdKDywgsv6E2mFUIgNTUVN27cwDfffGNwQ4iIiMoVC5ij0qtXL/z444/QaDRYsWIF+vTpAxubx6HFa6+9htdee83oa0gHKqGhoXqBipWVFapUqYKgoCDUr1/f6AYRERFR2fD777/j/v370Gg0GDRoEEJCQuDu7l6s15AOVCIiIoq1AaXGPldxanyptPjqbMVlHe2Up6IHAEcb5XXbWysv6yBRFgCcrZWn3FdbydUtI+JEqPKyARtLrB0lxUYlt1aWsFKeQNtGIv26lWR/ckml0M/VyiUIz4Z10YX+n0y6fdmJfDkSafFlvtLaXMlU/hLlRa7EXeZILm1gp/wusyqYY1L4kmMJQz/169fHpEmT0L59ewgh8MsvvxSaX83Q9X6kAxVra2ukpKTki5hu3boFd3d35OYqX+uFiIio3LKAoZ/FixcjPDwcmzdvhkqlwpQpUwrMtaZSqUovUCnsFaPMzEzY2ZWzFaWIiIgMZAk9Km3atMGBAwcAPJ4Kcu7cOdMN/SxcuBDA46jo+++/11sRMTc3F7t27eIcFSIionIoJycHAwYMQGZmZrHXrThQmTdvHoDHPSqLFy+GtfX/xoPt7Ozg5+eHxYsXF3sDiYiILJIFDP3ksbGxwbp160pkHqviQCUpKQkA0L59e6xfvx4VK1Ys9sYQERGVGxYUqADASy+9hLi4OISFhRVrvdJzVHbu3FmsDSAiIqKyr0uXLpg0aRJOnDiBpk2bwsnJSe949+7dDapXUaASHh6OGTNmwMnJCeHh4c8sO3fuXIMaQkREVJ5YwmTaJ7377rsACo4DVCqVwW8FKwpUjh49iuzsx/kxjhw5UuCrR0RERCTBwoZ+tDIJiiQoClSeHO6Ji4srkYYQERERPU16jsrgwYOxYMECuLi46O2/f/8+Ro0ahR9++KHYGlecbB2yYe2oLHOlTLZZF3vlr2K52inP8AoAGonyTjbK26G2Up5593F5iQy5Krm6ZVhbmdk/H4qZtVXJ/GtEtm4ryX+mlVRm2myt8kyzAKCS6FXOlcjqmyOTtRVyv1Szc5Tfo9l0ZFvLfX/kOij/3svRWPbP+NNUQkBVSG4ypeebk+nTpz/z+Mcff2xQvdKByrJlyzB79ux8gcrDhw+xfPlysw1UiIiIzIqFDf1ER0frfc7OzkZSUhJsbGxQq1atkg9UMjIyIISAEAJ3796Fvb297lhubi7++OOPYs9GR0RERGXD0aNH8+3LyMhAWFgYevbsaXC9igOVChUqQKVSQaVSoW7duvmOq1QqTJs2zeCGEBERlSeW9tZPQTQaDaZPn45XXnkF/fv3N6gOxYHKzp07IYRAhw4dsG7dOri5uemO2dnZwdfXF97e3gY1goiIqNyxsKGfwqSlpSE9Pd3g8xUHKoGBgQAeZ6j18fGBlZXs4udERESUx9J6VPLWBMwjhEBKSgp++uknhISEGFyv9GRaX19fAMCDBw9w5coVZGVl6R1v1KiRwY0hIiKikhEZGYn169fjzJkzcHBwQJs2bfDpp5+iXr16ujJhYWFYtmyZ3nktW7bUrZD8LHlrAuaxsrJClSpVMHDgQEyaNMngdksHKjdu3MCgQYOwZcuWAo/LZJ7btWsXPvvsMyQkJCAlJQXR0dHo0aOH7rgQAtOmTcOSJUtw584dtGzZEl9//TUaNGgg22wiIiLzUspDP/Hx8RgxYgSaN2+OnJwcTJ48GcHBwTh16pReuvuQkBBERUXpPtvZ2SmqP29NwOImPX4zduxY3LlzBwcOHICDgwNiYmKwbNky1KlTB5s2bZKq6/79+2jcuDG++uqrAo/PmTMHc+fOxVdffYVDhw7B09MTnTp1wt27d2WbTUREZFbyhn6M2WTExMQgLCwMDRo0QOPGjREVFYUrV64gISFBr5xarYanp6due3JOqozLly/j1KlTRmesle5R2bFjBzZu3IjmzZvDysoKvr6+6NSpEzQaDSIjI/Hyyy8rrqtLly7o0qVLgceEEJg/fz4mT56MXr16AXicw8XDwwOrVq3CO++8I9t0IiIii5ORkaH3Wa1WQ61WF3le3gTXpwORuLg4uLu7o0KFCggMDMTMmTOfmX5k2bJluHPnDsaOHavbN3ToUCxduhQAUK9ePWzduhU+Pj5Kb0mPdI/K/fv3dQ12c3PDjRs3AAANGzbEkSNHDGpEQZKSkpCamorg4GDdPrVajcDAQOzbt6/Q8zIzM5GRkaG3ERERmR1RDBsAHx8fuLq66rbIyMiiLy0EwsPD0bZtWwQEBOj2d+nSBStXrsSOHTvwxRdf4NChQ+jQoQMyMwvPfr548WK4urrqPsfExCAqKgrLly/HoUOHUKFCBaPSl0j3qNSrVw9nz56Fn58fnn/+eXz77bfw8/PD4sWL4eXlZXBDnpaamgoA8PDw0Nvv4eGBy5cvF3peZGRkgV8QF6dMWDsqu7aLnfJ09DJlK9g9VFwWAFxslafQd7ZW3g57iZT4AGBtJu/AZQu5lOrmIOjP9xWXdbCVXFnUWnl5rUTqell2VoatiFqULMkU+lm5ysvnCuX/RsvKkfs1KdMOGbI/hVqtxDPPlajdTrIbX6IZMssxWIriuOXk5GRoNBrdZyW9KSNHjsTx48exZ88evf19+vTR/X9AQACaNWsGX19fbN68WTe68bRz586hWbNmus8bN25E9+7d8cYbbwAAZs2ahUGDBknd05MMmqOSkpICAJg6dSpiYmJQvXp1LFy4ELNmzTK4IYV5eqVmIcQzV2+eNGkS0tPTdVtycnKxt4mIiMhcaDQava2oQGXUqFHYtGkTdu7ciWrVqj2zrJeXF3x9fXH+/PlCyzx8+FAvUNq3bx/atWun+1yzZk1d54MhpHtU8iIkAHjhhRdw6dIlnDlzBtWrV0flypUNbsjTPD09ATzuWXmyp+b69ev5elmepHRsjoiIyKSEeLwZc75UcYFRo0YhOjoacXFxqFGjRpHn3Lp1C8nJyc8cMfH19UVCQgJ8fX1x8+ZNnDx5Em3bttUdT01N1RsakmV01jZHR0c0adKkWIMUAKhRowY8PT0RGxur25eVlYX4+Hi0adOmWK9FRERU2kr7rZ8RI0ZgxYoVWLVqFVxcXJCamorU1FQ8fPh4WsK9e/fw/vvvY//+/bh06RLi4uLQrVs3VK5c+Zlr9QwYMAAjRozAjBkz8Oqrr6J+/fpo2rSp7vi+ffv05sHIUtSjEh4errjCuXPnKi577949/P3337rPSUlJOHbsGNzc3FC9enWMHTsWs2bNQp06dVCnTh3MmjULjo6O6Nevn+JrEBEREbBo0SIAQFBQkN7+qKgohIWFwdraGomJiVi+fDnS0tLg5eWF9u3bY82aNXBxcSm03okTJ+LBgwdYv349PD09sXbtWr3je/fuRd++fQ1ut6JApaAVEQvyrLkjBTl8+DDat2+v+5wXEA0cOBA//vgjJkyYgIcPH2L48OG6hG/btm175heMiIioTCjlhG+iiKEiBwcHbN26VboZVlZWmDFjBmbMmFHg8acDF1mKApWdO3cadZHCBAUFPfMLp1KpEBERgYiIiBK5PhERkamotI83Y84vD6Qn0xIREVExKCerJxuLSyATERGR2WKPChERkQkY8ubO0+eXBwxUiIiITKGU86iUVeUmUKnkcB82jjmKympslaejd7TJUly2gu0DxWUBubT4jtbK22GrKpmU54BcmnvZlPiPtLaKy4468kbRhf7fl01WSrWj74Ghist6ORVdJs/PrZZItaPb7lHKC0u8kGdjJTdDTyaFvpXE7L8srdyvpxxribT4Eun5bSWXCLDOUf59ai3x9ZBNLy/zDqaVlfK6pVLzS9ZNZd8///yDTZs24cqVK8jK0v+7JJO+5EnlJlAhIiIyJ5Y29PPnn3+ie/fuqFGjBs6ePYuAgABcunQJQgg0adLE4Ho5mZaIiMgUimn1ZHMxadIkvPfeezhx4gTs7e2xbt06JCcnIzAwEK+++qrB9TJQISIiIqOdPn0aAwcOBADY2Njg4cOHcHZ2xvTp0/Hpp58aXC8DFSIiIhMo7bV+SpqTkxMyMx/PrfT29saFCxd0x27evGlwvZyjQkREZAoW9tZPq1atsHfvXvj7++Pll1/Ge++9h8TERKxfvx6tWrUyuF4GKkRERGS0uXPn4t69ewCAiIgI3Lt3D2vWrEHt2rUxb948g+tloEJERGQClvbWT82aNXX/7+joiG+++aZY6uUcFSIiIlOwsLd+ACAtLQ3ff/89Jk2ahNu3bwMAjhw5gqtXrxpcJ3tUiIiITMDSelSOHz+Ojh07wtXVFZcuXcLbb78NNzc3REdH4/Lly1i+fLlB9ZabQMXd/h7sHJRlb3WykckIm624rMb6oeKyj+tW3g7rEgytcyVyXMpkm80Vch16WqG8HWprZVmIAWD4kTel2uFqq7wdWsl7lPHbv75UXPbVfe8qLmsn8bUDAAeJn4FsiYyw8srerzNriSzANtZyGYPVNsqfo8xzkc1MW1Kei54mVf50z6kl1BLKEx4ejrCwMMyZMwcuLi66/V26dEG/fv0Mrrfs/WQTERFZAq14vBlzvhk5dOgQvv3223z7q1atitTUVIPrZaBCRERkCsbOMzGvOAX29vbIyMjIt//s2bOoUqWKwfVyMi0REREZLTQ0FNOnT0d29uPhYJVKhStXruCDDz5A7969Da6XgQoREZEJqGBkZlpT38BTPv/8c9y4cQPu7u54+PAhAgMDUbt2bbi4uGDmzJkG18uhHyIiIlOwsMy0Go0Ge/bswY4dO3DkyBFotVo0adIEHTt2NKpeBipERERUbDp06IAOHToUW30c+iEiIjIBS1mU8ODBg9iyZYvevuXLl6NGjRpwd3fH0KFDdYsVGoKBChERkSlYSGbaiIgIHD9+XPc5MTERQ4YMQceOHfHBBx/gt99+Q2RkpMH1M1AhIiIigx07dgwvvfSS7vPq1avRsmVLfPfddwgPD8fChQvxyy+/GFw/56gQERGZgEoIqIyYEGvMucXpzp078PDw0H2Oj49HSEiI7nPz5s2RnJxscP3lJlCpap8Gtb2torJqK+Wpp2XS3DtaKUvhn8dOJZfKXCnZ1PUyafGlUvmXZH+eRLZxK8nU5FqJhmdrS+4m+x98S3FZRxvlz8XBWu771FYl9/VTKkfy+9RGph0l+L1nZ5VbcpWXkEe5yv8U3MtSS9WdW1I/A3bKl24AgLbbJygql3Pf8LkU0rSQ+l1V4PlmwMPDA0lJSfDx8UFWVhaOHDmCadP+t8TB3bt3YWur7O9vQTj0Q0REZAJ5PSrGbOYgJCQEH3zwAXbv3o1JkybB0dER//rXv3THjx8/jlq1ahlcf7npUSEiIqLi98knn6BXr14IDAyEs7Mzli1bBjs7O93xH374AcHBwQbXz0CFiIjIFCxkrZ8qVapg9+7dSE9Ph7OzM6yt9acLrF27Fs7OzgbXz0CFiIjIFCwsM62rq2uB+93c3Iyql3NUiIiIyGyxR4WIiMgEjM0uay6ZaUsaAxUiIiJTsLChn5LCoR8iIiIyW+xRISIiMgGV9vFmzPnlQbkJVDzs0uFgp+x27a2UZzxUq5SXlakXAKxLKO1gtpB77FkSmWkzhfLsg7ZauUyFj1QSdUtkF86UbEe2VvnXw8pKedlxx16XaoebnUp5OyQGs21VcplVZTIX20F5m2XlSjxza4mvh5XkO6Ayma2dbJRnQXWxfiTVDplM2DLPMPZ6fal2yGayVUqjlvt6VLa/r6hctlUWDhrSIENw6EcRDv0QERGVA5GRkWjevDlcXFzg7u6OHj164OzZs4WWf+edd6BSqTB//vzSa2QBGKgQERGZgiiGTUJ8fDxGjBiBAwcOIDY2Fjk5OQgODsb9+/l7mzZs2ICDBw/C29vbwJsrPuVm6IeIiMiclPbqyTExMXqfo6Ki4O7ujoSEBLRr1063/+rVqxg5ciS2bt2Kl19+2eD2FRcGKkRERKZg4jkq6enpAPQzx2q1WvTv3x/jx49HgwYNjKq/uDBQISIiKsMyMjL0PqvVaqjVz57ELIRAeHg42rZti4CAAN3+Tz/9FDY2Nhg9enSJtNUQnKNCRERkCgKA1ojt/ztUfHx84OrqqtsiIyOLvPTIkSNx/Phx/Pzzz7p9CQkJWLBgAX788UeoVCX3hp4ssw9UIiIioFKp9DZPT09TN4uIiMgoeXNUjNkAIDk5Genp6bpt0qRJz7zuqFGjsGnTJuzcuRPVqlXT7d+9ezeuX7+O6tWrw8bGBjY2Nrh8+TLee+89+Pn5leSX4pnKxNBPgwYNsH37dt3np5eQJiIiKq80Gg00Gk2R5YQQGDVqFKKjoxEXF4caNWroHe/fvz86duyot69z587o378/Bg0aVKxtllEmAhUbGxv2ohARkWURMHIyrVzxESNGYNWqVdi4cSNcXFyQmpoKAHB1dYWDgwMqVaqESpUq6Z1ja2sLT09P1KtXz/B2Gsnsh34A4Pz58/D29kaNGjXw+uuv4+LFi4WWzczMREZGht5GRERkdvLe+jFmk7Bo0SKkp6cjKCgIXl5eum3NmjUldIPFw+x7VFq2bInly5ejbt26uHbtGj755BO0adMGJ0+ezBf5AY8z702bNi3ffi+bNDjaKhsykkl1bwvl6cbtJdLtA4C1xEIOuUJ5zJkNuaGzRxJp8e9rlafLVkukxAcAe4l2ZEksE5AtkWockEs3LlNWK/EMAcCqhBb6kG2HzD3KfJ9qhdxkPlsr5T+LMssEyKSiBwAX64fKy1opTwPvZn1Pqh0aibplllho73xaqh3Nq1+SKq/UoENyQxHe6nRF5TJz5X5PlyXCgN6bS5cuFX9DJJl9j0qXLl3Qu3dvNGzYEB07dsTmzZsBAMuWLSuw/KRJk/QmFSUnJ5dmc4mIiJQx5o2fvK0cMPselac5OTmhYcOGOH/+fIHHlbw/TkREZGqlnZm2rDL7HpWnZWZm4vTp0/Dy8jJ1U4iIiAxXynNUyiqzD1Tef/99xMfHIykpCQcPHsS///1vZGRkYODAgaZuGhEREZUwsx/6+eeff9C3b1/cvHkTVapUQatWrXDgwAH4+vqaumlERESGM/FaP2WF2Qcqq1evNnUTiIiIih8DFUXMfuiHiIiIyi+z71EhIiKySFoAxqz9x9eTiYiIqKTw9WRlyk2g4m2TDicbZSNdMlkrbSWyg1pLLswgUz5XIizPlsw8miWRydZJpTyL5yMruW+/R8JOcdksiWypj7RyGXK1EiOmMplYZclkLrYqwX96yXw9ZMi2WSajtEyWaNmM0k5WmcrLStTtYpUj1Q5HlfLfCbYqiYzBkr/HUq96Ky7rWfW/istGNY+SaodSGRkZ+AKuJVI3GabcBCpERERmhZNpFWGgQkREZApaAUiss1Tg+eUA3/ohIiIis8UeFSIiIlPg0I8iDFSIiIhMwtj1ehioEBERUUlhj4oinKNCREREZos9KkRERKagFTBq+KacvPXDQIWIiMgUhPbxZsz55QCHfoiIiMhslZselYrWmXC2Lv64TKbnzUpy8SmZuqXS80ukXgcg1TOplUgJLpsiXWZpg2yJFPoaq4dS7ciViO+tJe7RSnaJhRJavqEk0+2XVJuBklv6wl7y58VeIoGXvUTqejXklnqwVSn/GZChlfz+yJYof+u/1RSXreT9j1Q7zBIn0ypSbgIVIiIis8I5Kopw6IeIiIjMFntUiIiITIFDP4owUCEiIjIFASMDlWJriVnj0A8RERGZLfaoEBERmQKHfhRhoEJERGQKWi1gTDoAbflI+MZAhYiIyBTYo6II56gQERGR2So3PSpWEIozXeZCeQpZmbJZQjI1rQStRN0ybQbksrzK1i1DJlOptSpHcVnZTKwy2VWl6pWcwm8lkQFVJkNuybajZMoCgK1EO2wlvk1lsscCgFri16pM9lirEvzZkiP39ZD5WpeXtWt02KOiSLkJVIiIiMwKM9MqwqEfIiIiMlvsUSEiIjIBIbQQRgx3GXNuWcJAhYiIyBSEMG74ppzMUeHQDxEREZkt9qgQERGZgjByMm056VFhoEJERGQKWi1gTLqDcjJHhUM/RERE5UBkZCSaN28OFxcXuLu7o0ePHjh79qxemYiICNSvXx9OTk6oWLEiOnbsiIMHD5qoxY8xUCEiIjKFvIRvxmwS4uPjMWLECBw4cACxsbHIyclBcHAw7t+/rytTt25dfPXVV0hMTMSePXvg5+eH4OBg3Lhxo7jvXjGVEJY9yJWRkQFXV1ccO+UOFxdlcZlMdtXsEswIK6MsZqbNFXJxsraE4mpmpi3NdpSHzLTKf17KYmZareRz0Up872VLDGVU8E6WaodSeX8z0tPTodFoSvQaHRxfh43KzuB6ckQWdjxYbXBbb9y4AXd3d8THx6Ndu3bPbOv27dvx0ksvGdxWY5SbOSq2KuW/nKxkYjeJ3x3WkjGhVEAhUTRXMpV/SQUfJRV4lDSZeyypoKYkyQQegFxAIRNMyAYq9irl36dqieDDXiKYeFy3reKyViX4MyATIOSayVwHmWAs7b8+UnWXVGBjlGKaTJuRkaG3W61WQ61WF3l6eno6AMDNza3A41lZWViyZAlcXV3RuHFjw9tppLL5l4KIiIgAAD4+PnB1ddVtkZGRRZ4jhEB4eDjatm2LgIAAvWO///47nJ2dYW9vj3nz5iE2NhaVK1cuqeYXqdz0qBAREZkVrQAkezD1/H+PSnJyst7Qj5LelJEjR+L48ePYs2dPvmPt27fHsWPHcPPmTXz33Xd47bXXcPDgQbi7uxveViOwR4WIiMgUhHj8irHB2+NARaPR6G1FBSqjRo3Cpk2bsHPnTlSrVi3fcScnJ9SuXRutWrXC0qVLYWNjg6VLl5bIl0AJ9qgQERGVA0IIjBo1CtHR0YiLi0ONGjUUn5eZmVnCrSscAxUiIiITEFoBYcTQj+xLuyNGjMCqVauwceNGuLi4IDU1FQDg6uoKBwcH3L9/HzNnzkT37t3h5eWFW7du4ZtvvsE///yDV1991eB2GqtMDP188803qFGjBuzt7dG0aVPs3r3b1E0iIiIyjlHDPlrpzLSLFi1Ceno6goKC4OXlpdvWrFkDALC2tsaZM2fQu3dv1K1bF6+88gpu3LiB3bt3o0GDBiXxFVDE7HtU1qxZg7Fjx+Kbb77Biy++iG+//RZdunTBqVOnUL16dVM3j4iIqEwoqgfG3t4e69evL6XWKGf2PSpz587FkCFD8NZbb+G5557D/Pnz4ePjg0WLFpm6aURERAYTWmH0Vh6YdaCSlZWFhIQEBAcH6+0PDg7Gvn37TNQqIiKiYlDKQz9llVkP/dy8eRO5ubnw8PDQ2+/h4aGbBPS0zMxMvdnJeZn37t2TydKovI05EpkUZYNfqYywUmn/5dqRKfHDIPO1k03FXVKsSrAdMplpZTOxqkoohb6tZDbdkspMK/tcsiUy02ZJJGfOkqgXANQSX7+S/N6T+fmSyUxbkin0cyUmh8q2w+qp7K2FycvyWhqry+Qg26jEtDnILr7GmDGzDlTyqJ76RSGEyLcvT2RkJKZNm5Zvf8vmN0ukbUREVBa4SpW+desWXF3lzlHKzs4Onp6e2JP6h9F1eXp6ws7O8PWCygKzDlQqV64Ma2vrfL0n169fz9fLkmfSpEkIDw/XfU5LS4Ovry+uXLlSYt90ppaRkQEfH5982QktiaXfo6XfH8B7tASWfn/A41746tWrF7r+TXGwt7dHUlISsrKyjK7Lzs4O9vb2xdAq82XWgYqdnR2aNm2K2NhY9OzZU7c/NjYWoaGhBZ5T2GJMrq6uFvuDlScvK6Els/R7tPT7A3iPlsDS7w8ArKxKdgqnvb29xQcYxcWsAxUACA8PR//+/dGsWTO0bt0aS5YswZUrVzBs2DBTN42IiIhKmNkHKn369MGtW7cwffp0pKSkICAgAH/88Qd8fX1N3TQiIiIqYWYfqADA8OHDMXz4cIPOVavVmDp1qqLVJMsq3mPZZ+n3B/AeLYGl3x9QPu6xrFGJ0ngHi4iIiMgAZp3wjYiIiMo3BipERERkthioEBERkdlioEJERERmy2IClatXr+LNN99EpUqV4OjoiOeffx4JCQm642FhYVCpVHpbq1atTNhiOX5+fvnar1KpMGLECACPlxWIiIiAt7c3HBwcEBQUhJMnT5q41XKKusey/gxzcnIwZcoU1KhRAw4ODqhZsyamT58OrfZ/a6GU9eeo5B7L+nMEgLt372Ls2LHw9fWFg4MD2rRpg0OHDumOl/XnWNT9lbVnuGvXLnTr1g3e3t5QqVTYsGGD3nElzyszMxOjRo1C5cqV4eTkhO7du+Off/4pxbsox4QFuH37tvD19RVhYWHi4MGDIikpSWzfvl38/fffujIDBw4UISEhIiUlRbfdunXLhK2Wc/36db22x8bGCgBi586dQgghZs+eLVxcXMS6detEYmKi6NOnj/Dy8hIZGRmmbbiEou6xrD/DTz75RFSqVEn8/vvvIikpSaxdu1Y4OzuL+fPn68qU9eeo5B7L+nMUQojXXntN+Pv7i/j4eHH+/HkxdepUodFoxD///COEKPvPsaj7K2vP8I8//hCTJ08W69atEwBEdHS03nElz2vYsGGiatWqIjY2Vhw5ckS0b99eNG7cWOTk5JTy3ZQ/FhGoTJw4UbRt2/aZZQYOHChCQ0NLp0GlYMyYMaJWrVpCq9UKrVYrPD09xezZs3XHHz16JFxdXcXixYtN2ErjPHmPQpT9Z/jyyy+LwYMH6+3r1auXePPNN4UQwiKeY1H3KETZf44PHjwQ1tbW4vfff9fb37hxYzF58uQy/xyLuj8hyvYzfDpQUfK80tLShK2trVi9erWuzNWrV4WVlZWIiYkptbaXVxYx9LNp0yY0a9YMr776Ktzd3fHCCy/gu+++y1cuLi4O7u7uqFu3Lt5++21cv37dBK01XlZWFlasWIHBgwdDpVIhKSkJqampCA4O1pVRq9UIDAzEvn37TNhSwz19j3nK8jNs27Yt/vzzT5w7dw4A8J///Ad79uxB165dAcAinmNR95inLD/HnJwc5Obm5lunxcHBAXv27Cnzz7Go+8tTlp/hk5Q8r4SEBGRnZ+uV8fb2RkBAQJl4pmVdmchMW5SLFy9i0aJFCA8Px4cffoi//voLo0ePhlqtxoABAwAAXbp0wauvvgpfX18kJSXho48+QocOHZCQkFDmMhBu2LABaWlpCAsLAwDd6tJPryjt4eGBy5cvl3bzisXT9wiU/Wc4ceJEpKeno379+rC2tkZubi5mzpyJvn37ArCM51jUPQJl/zm6uLigdevWmDFjBp577jl4eHjg559/xsGDB1GnTp0y/xyLuj+g7D/DJyl5XqmpqbCzs0PFihXzlck7n0qORQQqWq0WzZo1w6xZswAAL7zwAk6ePIlFixbpApU+ffroygcEBKBZs2bw9fXF5s2b0atXL5O021BLly5Fly5d4O3trbf/yZ4H4PEEsaf3lRUF3WNZf4Zr1qzBihUrsGrVKjRo0ADHjh3D2LFj4e3tjYEDB+rKleXnqOQey/pzBICffvoJgwcPRtWqVWFtbY0mTZqgX79+OHLkiK5MWX6ORd2fJTzDpxnyvMrSMy3LLGLox8vLC/7+/nr7nnvuOVy5cuWZ5/j6+uL8+fMl3bxidfnyZWzfvh1vvfWWbp+npycA5Ivsr1+/nu9fCWVBQfdYkLL2DMePH48PPvgAr7/+Oho2bIj+/ftj3LhxiIyMBGAZz7GoeyxIWXuOAFCrVi3Ex8fj3r17SE5Oxl9//YXs7GzUqFHDIp7js+6vIGXxGeZR8rw8PT2RlZWFO3fuFFqGSo5FBCovvvgizp49q7fv3Llzz1xh+datW0hOToaXl1dJN69YRUVFwd3dHS+//LJuX94vx9jYWN2+rKwsxMfHo02bNqZoplEKuseClLVn+ODBA1hZ6f/IWVtb617dtYTnWNQ9FqSsPccnOTk5wcvLC3fu3MHWrVsRGhpqEc8xT0H3V5Cy/AyVPK+mTZvC1tZWr0xKSgpOnDhR5p5pmWTSqbzF5K+//hI2NjZi5syZ4vz582LlypXC0dFRrFixQgghxN27d8V7770n9u3bJ5KSksTOnTtF69atRdWqVcvM64JCCJGbmyuqV68uJk6cmO/Y7Nmzhaurq1i/fr1ITEwUffv2LVOvQ+Yp7B4t4RkOHDhQVK1aVffq7vr160XlypXFhAkTdGXK+nMs6h4t4TkKIURMTIzYsmWLuHjxoti2bZto3LixaNGihcjKyhJClP3n+Kz7K4vP8O7du+Lo0aPi6NGjAoCYO3euOHr0qLh8+bIQQtnzGjZsmKhWrZrYvn27OHLkiOjQoQNfTy4lFhGoCCHEb7/9JgICAoRarRb169cXS5Ys0R178OCBCA4OFlWqVBG2traievXqYuDAgeLKlSsmbLG8rVu3CgDi7Nmz+Y5ptVoxdepU4enpKdRqtWjXrp1ITEw0QSuNU9g9WsIzzMjIEGPGjBHVq1cX9vb2ombNmmLy5MkiMzNTV6asP8ei7tESnqMQQqxZs0bUrFlT2NnZCU9PTzFixAiRlpamO17Wn+Oz7q8sPsOdO3cKAPm2gQMHCiGUPa+HDx+KkSNHCjc3N+Hg4CBeeeUVs75nS6ISQgjT9ecQERERFc4i5qgQERGRZWKgQkRERGaLgQoRERGZLQYqREREZLYYqBAREZHZYqBCREREZouBChEREZktBipUJgQFBWHs2LEWdd2wsDD06NHDqDr8/PygUqmgUqmQlpZWaLkff/wRFSpUMOpaVLiwsDDdc9iwYYOpm0NkURioED3D+vXrMWPGDN1nPz8/zJ8/33QNKsD06dORkpICV1dXUzfF4sXFxRUYFC5YsAApKSmmaRSRhbMxdQOIzJmbm5upm1AkFxcX3QqwppadnQ1bW1tTN6PUubq6MlAkKiHsUaEy6c6dOxgwYAAqVqwIR0dHdOnSRW+J+byhjq1bt+K5556Ds7MzQkJC9P7Vm5OTg9GjR6NChQqoVKkSJk6ciIEDB+oNxzw59BMUFITLly9j3Lhxum5+AIiIiMDzzz+v17758+fDz89P9zk3Nxfh4eG6a02YMAFPr14hhMCcOXNQs2ZNODg4oHHjxvj1118N+vr8+OOPqF69OhwdHdGzZ0/cunUrX5nffvsNTZs2hb29PWrWrIlp06YhJydHd/zMmTNo27Yt7O3t4e/vj+3bt+sNbVy6dAkqlQq//PILgoKCYG9vjxUrVgB4vAL2c889B3t7e9SvXx/ffPON3rWvXr2KPn36oGLFiqhUqRJCQ0Nx6dIl3fG4uDi0aNECTk5OqFChAl588UVcvnxZ0b0XdV9z585Fw4YN4eTkBB8fHwwfPhz37t3THb98+TK6deuGihUrwsnJCQ0aNMAff/yBS5cuoX379gCAihUrQqVSISwsTFGbiMhwDFSoTAoLC8Phw4exadMm7N+/H0IIdO3aFdnZ2boyDx48wOeff46ffvoJu3btwpUrV/D+++/rjn/66adYuXIloqKisHfvXmRkZDxzfsH69etRrVo13VCLTFf/F198gR9++AFLly7Fnj17cPv2bURHR+uVmTJlCqKiorBo0SKcPHkS48aNw5tvvon4+HjlXxgABw8exODBgzF8+HAcO3YM7du3xyeffKJXZuvWrXjzzTcxevRonDp1Ct9++y1+/PFHzJw5EwCg1WrRo0cPODo64uDBg1iyZAkmT55c4PUmTpyI0aNH4/Tp0+jcuTO+++47TJ48GTNnzsTp06cxa9YsfPTRR1i2bBmAx8+lffv2cHZ2xq5du7Bnzx5dIJmVlYWcnBz06NEDgYGBOH78OPbv34+hQ4fqAsNnKeq+AMDKygoLFy7EiRMnsGzZMuzYsQMTJkzQHR8xYgQyMzOxa9cuJCYm4tNPP4WzszN8fHywbt06AMDZs2eRkpKCBQsWSD0bIjKASZdEJFIoMDBQjBkzRgghxLlz5wQAsXfvXt3xmzdvCgcHB/HLL78IIYSIiooSAMTff/+tK/P1118LDw8P3WcPDw/x2Wef6T7n5OSI6tWri9DQ0AKvK4QQvr6+Yt68eXptmzp1qmjcuLHevnnz5glfX1/dZy8vLzF79mzd5+zsbFGtWjXdte7duyfs7e3Fvn379OoZMmSI6Nu3b6Ffl4La07dvXxESEqK3r0+fPsLV1VX3+V//+peYNWuWXpmffvpJeHl5CSGE2LJli7CxsREpKSm647GxsQKAiI6OFkIIkZSUJACI+fPn69Xj4+MjVq1apbdvxowZonXr1kIIIZYuXSrq1asntFqt7nhmZqZwcHAQW7duFbdu3RIARFxcXKH3XZii7qsgv/zyi6hUqZLuc8OGDUVERESBZfNW4b1z506Bx5/8+hBR8eAcFSpzTp8+DRsbG7Rs2VK3r1KlSqhXrx5Onz6t2+fo6IhatWrpPnt5eeH69esAgPT0dFy7dg0tWrTQHbe2tkbTpk2h1WqLtb3p6elISUlB69atdftsbGzQrFkz3fDPqVOn8OjRI3Tq1Env3KysLLzwwgtS1zt9+jR69uypt69169aIiYnRfU5ISMChQ4f0ehpyc3Px6NEjPHjwAGfPnoWPj4/e3Jcnv1ZPatasme7/b9y4geTkZAwZMgRvv/22bn9OTo5uDkdCQgL+/vtvuLi46NXz6NEjXLhwAcHBwQgLC0Pnzp3RqVMndOzYEa+99hq8vLyKvPei7svR0RE7d+7ErFmzcOrUKWRkZCAnJwePHj3C/fv34eTkhNGjR+Pdd9/Ftm3b0LFjR/Tu3RuNGjUq8tpEVDIYqFCZI56a2/Hk/ieHB56e1KlSqfKd+/RwQmF1P4uVlVW+854cglIiLzjavHkzqlatqndMrVZL1aXkHrRaLaZNm4ZevXrlO2Zvb5/va/ksTk5OevUCwHfffacXSAKPA8G8Mk2bNsXKlSvz1VWlShUAj+e4jB49GjExMVizZg2mTJmC2NhYtGrVyqj7unz5Mrp27Yphw4ZhxowZcHNzw549ezBkyBDdM3vrrbfQuXNnbN68Gdu2bUNkZCS++OILjBo1StHXg4iKFwMVKnP8/f2Rk5ODgwcPok2bNgCAW7du4dy5c3juuecU1eHq6goPDw/89ddf+Ne//gXg8b+8jx49mm9i7JPs7OyQm5urt69KlSpITU3V++N+7NgxvWt5eXnhwIEDaNeuHYDHPQwJCQlo0qSJ7p7UajWuXLmCwMBARfdQGH9/fxw4cEBv39OfmzRpgrNnz6J27doF1lG/fn1cuXIF165dg4eHBwDg0KFDRV7bw8MDVatWxcWLF/HGG28UWKZJkyZYs2YN3N3dodFoCq3rhRdewAsvvIBJkyahdevWWLVqVZGBSlH3dfjwYeTk5OCLL76AldXjKXq//PJLvnI+Pj4YNmwYhg0bhkmTJuG7777DqFGjYGdnBwD5vgeIqOQwUKEyp06dOggNDcXbb7+Nb7/9Fi4uLvjggw9QtWpVhIaGKq5n1KhRiIyMRO3atVG/fn18+eWXuHPnzjN7Evz8/LBr1y68/vrrUKvVqFy5MoKCgnDjxg3MmTMH//73vxETE4MtW7bo/REeM2YMZs+ejTp16uC5557D3Llz9XJxuLi44P3338e4ceOg1WrRtm1bZGRkYN++fXB2dsbAgQMV39fo0aPRpk0bzJkzBz169MC2bdv0hn0A4OOPP8Yrr7wCHx8fvPrqq7CyssLx48eRmJiITz75BJ06dUKtWrUwcOBAzJkzB3fv3tVNpi2qpyUiIgKjR4+GRqNBly5dkJmZicOHD+POnTsIDw/HG2+8gc8++wyhoaGYPn06qlWrhitXrmD9+vUYP348srOzsWTJEnTv3h3e3t44e/Yszp07hwEDBhR570XdV61atZCTk4Mvv/wS3bp1w969e7F48WK9OsaOHYsuXbqgbt26uHPnDnbs2KELgH19faFSqfD777+ja9eucHBwgLOzs+JnQ0QGMNnsGCIJT09qvX37tujfv79wdXUVDg4OonPnzuLcuXO641FRUXqTR4UQIjo6Wjz5LZ+dnS1GjhwpNBqNqFixopg4caJ49dVXxeuvv17odffv3y8aNWok1Gq1Xl2LFi0SPj4+wsnJSQwYMEDMnDlTbzJtdna2GDNmjNBoNKJChQoiPDxcDBgwQG/irlarFQsWLBD16tUTtra2okqVKqJz584iPj6+0K9LQZNphXg8YbVatWrCwcFBdOvWTXz++ef5vh4xMTGiTZs2wsHBQWg0GtGiRQuxZMkS3fHTp0+LF198UdjZ2Yn69euL3377TQAQMTExQoj/TaY9evRovuuvXLlSPP/888LOzk5UrFhRtGvXTqxfv153PCUlRQwYMEBUrlxZqNVqUbNmTfH222+L9PR0kZqaKnr06CG8vLyEnZ2d8PX1FR9//LHIzc0t9Osgc19z584VXl5euu+b5cuX602QHTlypKhVq5ZQq9WiSpUqon///uLmzZu686dPny48PT2FSqUSAwcO1Ls2OJmWqNiphDBgUJ7IAmm1Wjz33HN47bXX9LLRmjM/Pz+MHTu2VJYX2Lt3L9q2bYu///5bb5Iy/Y9KpUJ0dLTRSyMQ0f8wjwqVW5cvX8Z3332Hc+fOITExEe+++y6SkpLQr18/UzdNysSJE+Hs7Iz09PRirTc6OhqxsbG4dOkStm/fjqFDh+LFF19kkFKAYcOGcQiIqISwR4XKreTkZLz++us4ceIEhBAICAjA7NmzdRNey4LLly/r3lapWbOmboJocVi+fDlmzJiB5ORkVK5cGR07dsQXX3yBSpUqFds1ZDVo0KDQDLXffvttoRN4S9r169eRkZEB4PFr8E++CUVExmGgQkRlxpOB2dM8PDzy5WYhorKPgQoRERGZLc5RISIiIrPFQIWIiIjMFgMVIiIiMlsMVIiIiMhsMVAhIiIis8VAhYiIiMwWAxUiIiIyWwxUiIiIyGz9HyeVL1K8dghAAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ds.tos.isel(time=0).plot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d953c577-720d-46b1-b8c6-040df6455dd1", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 743b25fe63699e89805ba71915cf8a883e16b634 Mon Sep 17 00:00:00 2001 From: mgrover1 Date: Thu, 13 Jun 2024 16:13:21 -0600 Subject: [PATCH 2/3] ADD: Add new section to intake-rooki notebook --- notebooks/use-intake-esgf-with-rooki.ipynb | 2263 +++++++++++++++++++- 1 file changed, 2154 insertions(+), 109 deletions(-) diff --git a/notebooks/use-intake-esgf-with-rooki.ipynb b/notebooks/use-intake-esgf-with-rooki.ipynb index 0813a71..208fb3a 100644 --- a/notebooks/use-intake-esgf-with-rooki.ipynb +++ b/notebooks/use-intake-esgf-with-rooki.ipynb @@ -41,11 +41,9 @@ "## Overview\n", "If you have an introductory paragraph, lead with it here! Keep it short and tied to your material, then be sure to continue into the required list of topics below,\n", "\n", - "1. This is a numbered list of the specific topics\n", - "1. These should map approximately to your main sections of content\n", - "1. Or each second-level, `##`, header in your notebook\n", - "1. Keep the size and scope of your notebook in check\n", - "1. And be sure to let the reader know up front the important concepts they'll be leaving with" + "1. Search and find data using intake-esgf, returning the dataset ids\n", + "1. Feed the dataset ids to rooki to subset and average the data remotely\n", + "1. Visualize the results on the end-user side" ] }, { @@ -57,15 +55,10 @@ "\n", "| Concepts | Importance | Notes |\n", "| --- | --- | --- |\n", - "| [Intro to Cartopy](https://foundations.projectpythia.org/core/cartopy/cartopy.html) | Necessary | |\n", - "| [Understanding of NetCDF](https://foundations.projectpythia.org/core/data-formats/netcdf-cf.html) | Helpful | Familiarity with metadata structure |\n", - "| Project management | Helpful | |\n", + "| [Intro to Intake-ESGF](intro-search) | Necessary | |\n", + "| [Intro to Rooki](rooki) | Helpful | Familiarity with metadata structure |\n", "\n", - "- **Time to learn**: estimate in minutes. For a rough idea, use 5 mins per subsection, 10 if longer; add these up for a total. Safer to round up and overestimate.\n", - "- **System requirements**:\n", - " - Populate with any system, version, or non-Python software requirements if necessary\n", - " - Otherwise use the concepts table above and the Imports section below to describe required packages as necessary\n", - " - If no extra requirements, remove the **System requirements** point altogether" + "- **Time to learn**: 30 minutes" ] }, { @@ -86,45 +79,1180 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 45, "id": "c12d0875-9794-4101-b74f-346148cb36c0", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + " var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " var reloading = false;\n", + " var Bokeh = root.Bokeh;\n", + "\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " if (!reloading) {\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error() {\n", + " console.error(\"failed to load \" + url);\n", + " }\n", + "\n", + " var skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", + " root._bokeh_is_loading = css_urls.length + 0;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " var existing_stylesheets = []\n", + " var links = document.getElementsByTagName('link')\n", + " for (var i = 0; i < links.length; i++) {\n", + " var link = links[i]\n", + " if (link.href != null) {\n", + "\texisting_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (var i = 0; i < css_urls.length; i++) {\n", + " var url = css_urls[i];\n", + " if (existing_stylesheets.indexOf(url) !== -1) {\n", + "\ton_load()\n", + "\tcontinue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } var existing_scripts = []\n", + " var scripts = document.getElementsByTagName('script')\n", + " for (var i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + "\texisting_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (var i = 0; i < js_modules.length; i++) {\n", + " var url = js_modules[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " var url = js_exports[name];\n", + " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\"];\n", + " var js_modules = [];\n", + " var js_exports = {};\n", + " var css_urls = [];\n", + " var inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + "\ttry {\n", + " inline_js[i].call(root, root.Bokeh);\n", + "\t} catch(e) {\n", + "\t if (!reloading) {\n", + "\t throw e;\n", + "\t }\n", + "\t}\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + "\tvar NewBokeh = root.Bokeh;\n", + "\tif (Bokeh.versions === undefined) {\n", + "\t Bokeh.versions = new Map();\n", + "\t}\n", + "\tif (NewBokeh.version !== Bokeh.version) {\n", + "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + "\t}\n", + "\troot.Bokeh = Bokeh;\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + "\troot.Bokeh = undefined;\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + "\trun_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " }) \n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + " var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " var reloading = true;\n", + " var Bokeh = root.Bokeh;\n", + "\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " if (!reloading) {\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error() {\n", + " console.error(\"failed to load \" + url);\n", + " }\n", + "\n", + " var skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", + " root._bokeh_is_loading = css_urls.length + 0;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " var existing_stylesheets = []\n", + " var links = document.getElementsByTagName('link')\n", + " for (var i = 0; i < links.length; i++) {\n", + " var link = links[i]\n", + " if (link.href != null) {\n", + "\texisting_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (var i = 0; i < css_urls.length; i++) {\n", + " var url = css_urls[i];\n", + " if (existing_stylesheets.indexOf(url) !== -1) {\n", + "\ton_load()\n", + "\tcontinue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } var existing_scripts = []\n", + " var scripts = document.getElementsByTagName('script')\n", + " for (var i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + "\texisting_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (var i = 0; i < js_modules.length; i++) {\n", + " var url = js_modules[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " var url = js_exports[name];\n", + " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var js_urls = [];\n", + " var js_modules = [];\n", + " var js_exports = {};\n", + " var css_urls = [];\n", + " var inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + "\ttry {\n", + " inline_js[i].call(root, root.Bokeh);\n", + "\t} catch(e) {\n", + "\t if (!reloading) {\n", + "\t throw e;\n", + "\t }\n", + "\t}\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + "\tvar NewBokeh = root.Bokeh;\n", + "\tif (Bokeh.versions === undefined) {\n", + "\t Bokeh.versions = new Map();\n", + "\t}\n", + "\tif (NewBokeh.version !== Bokeh.version) {\n", + "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + "\t}\n", + "\troot.Bokeh = Bokeh;\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + "\troot.Bokeh = undefined;\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + "\trun_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = true;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " }) \n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import os\n", "\n", "from rooki import rooki\n", + "from rooki import operators as ops\n", + "import intake_esgf\n", "from intake_esgf import ESGFCatalog\n", - "import xarray as xr" + "import xarray as xr\n", + "import hvplot.xarray\n", + "import holoviews as hv\n", + "hv.extension(\"bokeh\")" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "d5dfdb4b-af1f-4dba-a696-eaa59aef95a5", + "cell_type": "markdown", + "id": "7dd9b81a-9aeb-4769-8c67-4db88a089859", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "## Search and Find Data for Surface Temperature on DKRZ Node\n", + "\n", + "Let's start with refining which index we would like to search from. For this analysis, we are remotely computing on the DKRZ node since this is where rooki is running. We know this from checking the `._url` method of rooki!" + ] }, { "cell_type": "code", - "execution_count": 5, - "id": "363d5d3b-3da5-45a2-9981-e66969fbb227", + "execution_count": 18, + "id": "d3cdea76-9a74-4001-91b4-6c1b664835b2", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'http://rook.dkrz.de/wps'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "def separate_dataset_id(full_dataset):\n", - " return full_dataset[0].split(\"|\")[0]" + "rooki._url" + ] + }, + { + "cell_type": "markdown", + "id": "4a4442f9-6c41-4a56-ac66-4299d0c4ddda", + "metadata": {}, + "source": [ + "### Set the Index Node and Search\n", + "We need to turn off the new index nodes (Argonne National Lab (`anl-dev`) and Oak Ridge National Lab (`ornl-dev`)), and turn on the German Climate Computation Center (`esgf-data.dkrz.de`) node." ] }, { "cell_type": "code", - "execution_count": 6, - "id": "044b088b-a9e0-48e9-ab93-a5a107341367", + "execution_count": 31, + "id": "d0f5ede4-feb0-4896-9e65-e100cbfadee4", "metadata": { "tags": [] }, @@ -132,12 +1260,12 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ca36d2261499419d8abaf9dc829d1b58", + "model_id": "7eef94748b8743ed8a8dc1fae67b7926", "version_major": 2, "version_minor": 0 }, "text/plain": [ - " Searching indices: 0%| |0/2 [ ?index/s]" + " Searching indices: 0%| |0/1 [ ?index/s]" ] }, "metadata": {}, @@ -145,19 +1273,246 @@ }, { "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mip_erasource_idtable_idgrid_labelactivity_drsexperiment_idversionmember_idvariable_idinstitution_idprojectid
0CMIP6CESM2-WACCM-FV2AmongnCMIPhistorical20191120r1i1p1f1tasNCARCMIP6[CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1...
1CMIP6GISS-E2-1-GAmongnCMIPhistorical20180827r1i1p1f1tasNASA-GISSCMIP6[CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r...
2CMIP6CESM2-FV2AmongnCMIPhistorical20191120r1i1p1f1tasNCARCMIP6[CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1...
3CMIP6CESM2AmongnCMIPhistorical20190308r1i1p1f1tasNCARCMIP6[CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amo...
4CMIP6GISS-E2-1-HAmongnCMIPhistorical20190403r1i1p1f1tasNASA-GISSCMIP6[CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r...
5CMIP6CESM2-WACCMAmongnCMIPhistorical20190227r1i1p1f1tasNCARCMIP6[CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1...
6CMIP6MIROC6AmongnCMIPhistorical20181212r1i1p1f1tasMIROCCMIP6[CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.A...
7CMIP6CMCC-CM2-SR5AmongnCMIPhistorical20200616r1i1p1f1tasCMCCCMIP6[CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p...
8CMIP6CMCC-CM2-HR4AmongnCMIPhistorical20200904r1i1p1f1tasCMCCCMIP6[CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p...
11CMIP6CMCC-ESM2AmongnCMIPhistorical20210114r1i1p1f1tasCMCCCMIP6[CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1...
\n", + "
" + ], "text/plain": [ - "['CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.tas.gn.v20190308',\n", - " 'CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Amon.tas.gn.v20210114',\n", - " 'CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120',\n", - " 'CMIP6.CMIP.CCCma.CanESM5.historical.r1i1p1f1.Amon.tas.gn.v20190429']" + " mip_era source_id table_id grid_label activity_drs experiment_id \\\n", + "0 CMIP6 CESM2-WACCM-FV2 Amon gn CMIP historical \n", + "1 CMIP6 GISS-E2-1-G Amon gn CMIP historical \n", + "2 CMIP6 CESM2-FV2 Amon gn CMIP historical \n", + "3 CMIP6 CESM2 Amon gn CMIP historical \n", + "4 CMIP6 GISS-E2-1-H Amon gn CMIP historical \n", + "5 CMIP6 CESM2-WACCM Amon gn CMIP historical \n", + "6 CMIP6 MIROC6 Amon gn CMIP historical \n", + "7 CMIP6 CMCC-CM2-SR5 Amon gn CMIP historical \n", + "8 CMIP6 CMCC-CM2-HR4 Amon gn CMIP historical \n", + "11 CMIP6 CMCC-ESM2 Amon gn CMIP historical \n", + "\n", + " version member_id variable_id institution_id project \\\n", + "0 20191120 r1i1p1f1 tas NCAR CMIP6 \n", + "1 20180827 r1i1p1f1 tas NASA-GISS CMIP6 \n", + "2 20191120 r1i1p1f1 tas NCAR CMIP6 \n", + "3 20190308 r1i1p1f1 tas NCAR CMIP6 \n", + "4 20190403 r1i1p1f1 tas NASA-GISS CMIP6 \n", + "5 20190227 r1i1p1f1 tas NCAR CMIP6 \n", + "6 20181212 r1i1p1f1 tas MIROC CMIP6 \n", + "7 20200616 r1i1p1f1 tas CMCC CMIP6 \n", + "8 20200904 r1i1p1f1 tas CMCC CMIP6 \n", + "11 20210114 r1i1p1f1 tas CMCC CMIP6 \n", + "\n", + " id \n", + "0 [CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1... \n", + "1 [CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r... \n", + "2 [CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1... \n", + "3 [CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amo... \n", + "4 [CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r... \n", + "5 [CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1... \n", + "6 [CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.A... \n", + "7 [CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p... \n", + "8 [CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p... \n", + "11 [CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1... " ] }, - "execution_count": 6, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "intake_esgf.conf.set(indices={\"anl-dev\":False,\n", + " \"ornl-dev\":False,\n", + " \"esgf-data.dkrz.de\":True,\n", + " }\n", + " )\n", + "\n", + "cat = ESGFCatalog()\n", + "\n", "cat = ESGFCatalog()\n", "cat.search(\n", " activity_id='CMIP',\n", @@ -166,53 +1521,34 @@ " member_id='r1i1p1f1',\n", " grid_label='gn',\n", " table_id=\"Amon\",\n", - " source_id = [ \"CMCC-ESM2\", \"CanESM5\", \"CESM2\", \"CESM2-FV2\", ]\n", + " institution_id=[\"MIROC\", \"NCAR\", \"NASA-GISS\", \"CMCC\"]\n", " )\n", - "\n", - "dsets = [separate_dataset_id(dataset) for dataset in list(cat.df.id.values)]\n", - "dsets" + "cat.df" ] }, { - "cell_type": "code", - "execution_count": 7, - "id": "399583f8-1889-4939-ba74-2cd448befef6", + "cell_type": "markdown", + "id": "b00d07ff-58a7-4141-922c-9f7a97772f1e", "metadata": { "tags": [] }, - "outputs": [], "source": [ - "def query_compute_data(dset_id):\n", - " resp = rooki.subset(\n", - " collection=dset,\n", - " time='1900-01-01/2000-01-31',\n", - " area='65,0,100,35',\n", - " )\n", - " \n", - " if resp.ok:\n", - " ds = resp.datasets()[0]\n", - " else:\n", - " ds = xr.Dataset()\n", - " \n", - " return ds\n" + "## Extract the Dataset ID and Pass to Rooki\n", + "Now that we have set of datasets, we need to extract the `dataset_id`, which is the unique identifier for the dataset. We can pull this from the `id` column from `intake-esgf`" ] }, { - "cell_type": "code", - "execution_count": 15, - "id": "b9a934cf-cda7-4bc4-8859-a2ce247f7066", - "metadata": { - "tags": [] - }, - "outputs": [], + "cell_type": "markdown", + "id": "6c8ee46c-06e3-4a25-ad5d-23c7e10aa9ff", + "metadata": {}, "source": [ - "from rooki import operators as ops" + "### Separate the Dataset ID" ] }, { "cell_type": "code", - "execution_count": 20, - "id": "94b2078e-d58b-4a1e-a79f-0011c514a592", + "execution_count": 35, + "id": "e44f6c32-e4b9-4767-88eb-8099bee603e8", "metadata": { "tags": [] }, @@ -220,25 +1556,30 @@ { "data": { "text/plain": [ - "\u001b[0;31mInit signature:\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mDocstring:\u001b[0m \n", - "\u001b[0;31mFile:\u001b[0m ~/mambaforge/envs/esgf-cookbook-dev/lib/python3.10/site-packages/rooki/operators.py\n", - "\u001b[0;31mType:\u001b[0m type\n", - "\u001b[0;31mSubclasses:\u001b[0m " + "['CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120|esgf3.dkrz.de']" ] }, + "execution_count": 35, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "ops.AverageByTime?" + "cat.df.id.values[0]" + ] + }, + { + "cell_type": "markdown", + "id": "85d44542-5ca7-4884-b77b-aa7a469efd34", + "metadata": {}, + "source": [ + "Notice how the node information is added onto end of the file id. We need to \"chop off\" that last bit, leaving everything before the `|` character. We put this into a function to make it easier to generalize and apply." ] }, { "cell_type": "code", - "execution_count": 24, - "id": "6036bdce-2e32-49ae-9a6e-34de5ab9e85c", + "execution_count": 37, + "id": "363d5d3b-3da5-45a2-9981-e66969fbb227", "metadata": { "tags": [] }, @@ -246,22 +1587,33 @@ { "data": { "text/plain": [ - "" + "'CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120'" ] }, - "execution_count": 24, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "wf = ops.Input('tas', dsets[0])" + "def separate_dataset_id(full_dataset):\n", + " return full_dataset[0].split(\"|\")[0]\n", + "\n", + "separate_dataset_id(cat.df.id.values[0])" + ] + }, + { + "cell_type": "markdown", + "id": "6e443d8c-f1d7-4f92-a0ab-ed0bbc588ced", + "metadata": {}, + "source": [ + "Now, we can apply this to the entire list within our dataframe using the following" ] }, { "cell_type": "code", - "execution_count": 35, - "id": "e756f75d-0c35-4f5b-9d8e-e7c65fd97500", + "execution_count": 39, + "id": "044b088b-a9e0-48e9-ab93-a5a107341367", "metadata": { "tags": [] }, @@ -269,27 +1621,47 @@ { "data": { "text/plain": [ - "\u001b[0;31mInit signature:\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mDocstring:\u001b[0m \n", - "\u001b[0;31mSource:\u001b[0m \n", - "\u001b[0;32mclass\u001b[0m \u001b[0mAverageByTime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mOperator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mMETHOD\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"average_time\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mFile:\u001b[0m ~/mambaforge/envs/esgf-cookbook-dev/lib/python3.10/site-packages/rooki/operators.py\n", - "\u001b[0;31mType:\u001b[0m type\n", - "\u001b[0;31mSubclasses:\u001b[0m " + "['CMIP6.CMIP.NCAR.CESM2-WACCM-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120',\n", + " 'CMIP6.CMIP.NASA-GISS.GISS-E2-1-G.historical.r1i1p1f1.Amon.tas.gn.v20180827',\n", + " 'CMIP6.CMIP.NCAR.CESM2-FV2.historical.r1i1p1f1.Amon.tas.gn.v20191120',\n", + " 'CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.tas.gn.v20190308',\n", + " 'CMIP6.CMIP.NASA-GISS.GISS-E2-1-H.historical.r1i1p1f1.Amon.tas.gn.v20190403',\n", + " 'CMIP6.CMIP.NCAR.CESM2-WACCM.historical.r1i1p1f1.Amon.tas.gn.v20190227',\n", + " 'CMIP6.CMIP.MIROC.MIROC6.historical.r1i1p1f1.Amon.tas.gn.v20181212',\n", + " 'CMIP6.CMIP.CMCC.CMCC-CM2-SR5.historical.r1i1p1f1.Amon.tas.gn.v20200616',\n", + " 'CMIP6.CMIP.CMCC.CMCC-CM2-HR4.historical.r1i1p1f1.Amon.tas.gn.v20200904',\n", + " 'CMIP6.CMIP.CMCC.CMCC-ESM2.historical.r1i1p1f1.Amon.tas.gn.v20210114']" ] }, + "execution_count": 39, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "ops.AverageByTime??" + "dsets = [separate_dataset_id(dataset) for dataset in list(cat.df.id.values)]\n", + "dsets" + ] + }, + { + "cell_type": "markdown", + "id": "4a470bea-581c-4796-a716-a02fd02e1531", + "metadata": {}, + "source": [ + "### Compute with Rooki\n", + "Now that we have a list of IDs to pass to rooki, let's compute!\n", + "\n", + "In this case, we are:\n", + "- Subsetting from the year 1900 to 2000\n", + "- Subsetting near India using the bounds `65,0,100,35`\n", + "- Computing the yealy average\n", + "\n", + "We then check to make sure the response is okay, and if it is, return that to the user!" ] }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 41, "id": "38704069-b1ad-474f-99f6-3273554df831", "metadata": { "tags": [] @@ -320,7 +1692,582 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 42, + "id": "94609894-705d-4fdc-a235-b2f1f5747305", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_gze8fnoi/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset> Size: 165kB\n",
+       "Dimensions:    (time: 101, lat: 18, lon: 15, nbnd: 2)\n",
+       "Coordinates:\n",
+       "  * lat        (lat) float64 144B 0.9474 2.842 4.737 6.632 ... 29.37 31.26 33.16\n",
+       "  * lon        (lon) float64 120B 65.0 67.5 70.0 72.5 ... 92.5 95.0 97.5 100.0\n",
+       "  * time       (time) object 808B 1900-01-01 00:00:00 ... 2000-01-01 00:00:00\n",
+       "Dimensions without coordinates: nbnd\n",
+       "Data variables:\n",
+       "    tas        (time, lat, lon) float32 109kB ...\n",
+       "    lat_bnds   (time, lat, nbnd) float64 29kB ...\n",
+       "    lon_bnds   (time, lon, nbnd) float64 24kB ...\n",
+       "    time_bnds  (time, nbnd) object 2kB ...\n",
+       "Attributes: (12/45)\n",
+       "    Conventions:            CF-1.7 CMIP-6.2\n",
+       "    activity_id:            CMIP\n",
+       "    branch_method:          standard\n",
+       "    branch_time_in_child:   674885.0\n",
+       "    branch_time_in_parent:  10950.0\n",
+       "    case_id:                1562\n",
+       "    ...                     ...\n",
+       "    sub_experiment_id:      none\n",
+       "    table_id:               Amon\n",
+       "    tracking_id:            hdl:21.14100/2ebbfd9d-97bf-4858-b893-80d31ffe8cc7\n",
+       "    variable_id:            tas\n",
+       "    variant_info:           CMIP6 CESM2 historical ensemble with WACCM6-FV2 (...\n",
+       "    variant_label:          r1i1p1f1
" + ], + "text/plain": [ + " Size: 165kB\n", + "Dimensions: (time: 101, lat: 18, lon: 15, nbnd: 2)\n", + "Coordinates:\n", + " * lat (lat) float64 144B 0.9474 2.842 4.737 6.632 ... 29.37 31.26 33.16\n", + " * lon (lon) float64 120B 65.0 67.5 70.0 72.5 ... 92.5 95.0 97.5 100.0\n", + " * time (time) object 808B 1900-01-01 00:00:00 ... 2000-01-01 00:00:00\n", + "Dimensions without coordinates: nbnd\n", + "Data variables:\n", + " tas (time, lat, lon) float32 109kB ...\n", + " lat_bnds (time, lat, nbnd) float64 29kB ...\n", + " lon_bnds (time, lon, nbnd) float64 24kB ...\n", + " time_bnds (time, nbnd) object 2kB ...\n", + "Attributes: (12/45)\n", + " Conventions: CF-1.7 CMIP-6.2\n", + " activity_id: CMIP\n", + " branch_method: standard\n", + " branch_time_in_child: 674885.0\n", + " branch_time_in_parent: 10950.0\n", + " case_id: 1562\n", + " ... ...\n", + " sub_experiment_id: none\n", + " table_id: Amon\n", + " tracking_id: hdl:21.14100/2ebbfd9d-97bf-4858-b893-80d31ffe8cc7\n", + " variable_id: tas\n", + " variant_info: CMIP6 CESM2 historical ensemble with WACCM6-FV2 (...\n", + " variant_label: r1i1p1f1" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compute_annual_mean_subset(dsets[0])" + ] + }, + { + "cell_type": "markdown", + "id": "4ecacf51-e35f-4810-8250-3e90a1b5888a", + "metadata": {}, + "source": [ + "Now that it works with a single dataset, let's do this for all the datasets and put them into a dictionary with the dataset ids as the keys." + ] + }, + { + "cell_type": "code", + "execution_count": 43, "id": "a52e7d71-18fd-4bbe-91a7-fa86725ad4de", "metadata": { "tags": [] @@ -330,10 +2277,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_tvqe5twj/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", - "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_xtxuxms6/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", - "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_9ntc6sns/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", - "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_7hstq_2a/tas_Amon_CESM2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n" + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_shm9lihm/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_knwmboqr/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_hwnk7sbm/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_j_w92ac9/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_0qmd9id3/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_53g0pvrs/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_4p48gwjo/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_5p_02p66/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_0d20f3r4/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n", + "Downloading to /var/folders/bw/c9j8z20x45s2y20vv6528qjc0000gq/T/metalink_xncn6l3t/tas_Amon_CESM2-WACCM-FV2_historical_r1i1p1f1_gn_19000101-20000101_avg-year.nc.\n" ] } ], @@ -343,37 +2296,129 @@ " dset_dict[dset] = compute_annual_mean_subset(dset)" ] }, + { + "cell_type": "markdown", + "id": "4a77cda9-536f-4fc2-8e89-9ce2e4937810", + "metadata": {}, + "source": [ + "## Visualize the Output" + ] + }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 73, "id": "1b08b0a0-7add-4a50-8e62-9bb88b98cc7c", "metadata": { "tags": [] }, "outputs": [ { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 30, + "data": {}, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" + }, + { + "data": {}, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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cyYmT56MU6dOQavVwt/fH87OzkY1hIiIqDyxtDkqeTp06IAOHToUW30GD5A6OjqiWbNmaNGiBYMUIiKicm706NFYuHBhvv1fffUVxo4da3C9inpUevXqpbjC9evXG9wYIiKicsPChn7WrVuHTZs25dvfpk0bzJ49G/PnzzeoXkWBiqurq+7/hRCIjo6Gq6srmjVrBgBISEhAWlqaVEBDRERUnlna0M+tW7f04oU8Go0GN2/eNLheRYFKVFSU7v8nTpyI1157DYsXL4a1tTUAIDc3F8OHD5daFImIiIgsR+3atRETE5PvxZotW7YYlb5EejLtDz/8gD179uiCFACwtrZGeHg42rRpg88++8zgxhAREZUbFjb0Ex4ejpEjR+LGjRu6ybR//vknvvjiC4OHfQADApWcnBycPn0a9erV09t/+vRpaLVyCauIiIjKLQsLVAYPHozMzEzMnDkTM2bMAAD4+flh0aJFGDBggMH1SgcqgwYNwuDBg/H333+jVatWAIADBw5g9uzZGDRokMENKWlatRZQmnHWXnm2WVv7HMVl7e2UlwUAR9ssxWWdJcq62DySaoezjfK6bVTKv3baMphJtCTJZni1lcg2K6xL7mst026ZDKiy3x8y/04qyXYoXE7lcd0S2WNl25GbI1F3tsQLoFkll003167EqjZLqv/fjDnf3Lz77rt49913cePGDTg4OBTLW8HSgcrnn38OT09PzJs3DykpKQAep9WfMGEC3nvvPaMbRERERGWbMWv7PE06ULGyssKECRMwYcIE3eJDnERLREQkycKGfgDg119/xS+//IIrV64gK0u/N/7IkSMG1WlUH55Go2GQQkREZIC815ON2czJwoULMWjQILi7u+Po0aNo0aIFKlWqhIsXL6JLly4G1yvdo1KjRg2onrG66sWLFw1uDBEREZVN33zzDZYsWYK+ffti2bJlmDBhAmrWrImPP/4Yt2/fNrhe6UDl6TS42dnZOHr0KGJiYjB+/HiDG0JERFSuWNjQz5UrV9CmTRsAgIODA+7evQsA6N+/P1q1aoWvvvrKoHqlA5UxY8YUuP/rr7/G4cOHDWoEERFRuWRmwYYxPD09cevWLfj6+sLX1xcHDhxA48aNkZSUBCHzOtxTiu09sy5dumDdunXFVR0RERGVIR06dMBvv/0GABgyZAjGjRuHTp06oU+fPujZ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", + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], "text/plain": [ - "
" + "Column\n", + " [0] HoloViews(DynamicMap, sizing_mode='fixed', widget_location='bottom')\n", + " [1] WidgetBox(align=('center', 'end'))\n", + " [0] DiscreteSlider(name='time', options={'1900-01-01 00:00:00': cf...}, value=cftime.DatetimeNoLeap(1900...)" ] }, - "metadata": {}, - "output_type": "display_data" + "execution_count": 73, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p9597" + } + }, + "output_type": "execute_result" } ], "source": [ - "ds.tos.isel(time=0).plot()" + "dset_dict['CMIP6.CMIP.NCAR.CESM2.historical.r1i1p1f1.Amon.tas.gn.v20190308'].tas.hvplot.contourf(x='lon',\n", + " y='lat',\n", + " cmap='Reds',\n", + " levels=20,\n", + " clim=(250, 320),\n", + " features=[\"land\", \"ocean\"],\n", + " alpha=0.7,\n", + " widget_location='bottom',\n", + " clabel=\"Yearly Average Temperature (K)\",\n", + " geo=True)" ] }, { From 238bae6207ba6ea9ace1fc6f17a0ca2f7a3e0a4d Mon Sep 17 00:00:00 2001 From: mgrover1 Date: Thu, 13 Jun 2024 16:43:18 -0600 Subject: [PATCH 3/3] ADD: Add last conclusion section --- notebooks/use-intake-esgf-with-rooki.ipynb | 686 +++++---------------- 1 file changed, 160 insertions(+), 526 deletions(-) diff --git a/notebooks/use-intake-esgf-with-rooki.ipynb b/notebooks/use-intake-esgf-with-rooki.ipynb index 208fb3a..3f508c2 100644 --- a/notebooks/use-intake-esgf-with-rooki.ipynb +++ b/notebooks/use-intake-esgf-with-rooki.ipynb @@ -5,7 +5,7 @@ "id": "5191269c-944c-4516-9f51-6cdfc704852a", "metadata": {}, "source": [ - "![](http://link.com/to/image.png \"image alt text\")" + "\"Intake" ] }, { @@ -55,8 +55,9 @@ "\n", "| Concepts | Importance | Notes |\n", "| --- | --- | --- |\n", - "| [Intro to Intake-ESGF](intro-search) | Necessary | |\n", - "| [Intro to Rooki](rooki) | Helpful | Familiarity with metadata structure |\n", + "| [Intro to Intake-ESGF](intro-search) | Necessary | How to configure a search and use output |\n", + "| [Intro to Rooki](rooki) | Helpful | How to initialize and run rooki |\n", + "| [Intro to hvPlot](https://hvplot.holoviz.org/user_guide/Geographic_Data.html) | Necessary | How to plot interactive visualizations |\n", "\n", "- **Time to learn**: 30 minutes" ] @@ -79,7 +80,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 89, "id": "c12d0875-9794-4101-b74f-346148cb36c0", "metadata": { "tags": [] @@ -250,7 +251,7 @@ " document.body.appendChild(element);\n", " }\n", "\n", - " var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\"];\n", + " var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\", \"https://cdn.jsdelivr.net/npm/@holoviz/geoviews@1.12.0/dist/geoviews.min.js\"];\n", " var js_modules = [];\n", " var js_exports = {};\n", " var css_urls = [];\n", @@ -323,7 +324,7 @@ " setTimeout(load_or_wait, 100)\n", "}(window));" ], - "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.1/dist/panel.min.js\", \"https://cdn.jsdelivr.net/npm/@holoviz/geoviews@1.12.0/dist/geoviews.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" }, "metadata": {}, "output_type": "display_data" @@ -604,12 +605,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "