{ "cells": [ { "cell_type": "markdown", "id": "4712c176", "metadata": {}, "source": [ "# Imports" ] }, { "cell_type": "markdown", "id": "52d46fef", "metadata": {}, "source": [ "## Useful packages" ] }, { "cell_type": "code", "execution_count": null, "id": "56355a52", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from functools import partial\n", "import pandas as pd\n", "import netCDF4\n", "from scipy.interpolate import interp1d" ] }, { "cell_type": "markdown", "id": "64c9441f", "metadata": {}, "source": [ "## plotting" ] }, { "cell_type": "code", "execution_count": null, "id": "1d1d65e1", "metadata": {}, "outputs": [], "source": [ "import holoviews as hv\n", "from holoviews import opts\n", "from holoviews.streams import Stream, param\n", "from holoviews.plotting.links import RangeToolLink\n", "import panel as pn\n", "from bokeh.models.formatters import PrintfTickFormatter\n", "from bokeh.models.renderers import GlyphRenderer\n", "from bokeh.models import Range1d, LinearAxis\n", "from bokeh.models import HoverTool" ] }, { "cell_type": "markdown", "id": "f9541e25", "metadata": {}, "source": [ "## Define css objects used in layout template" ] }, { "cell_type": "code", "execution_count": null, "id": "517fa202", "metadata": {}, "outputs": [], "source": [ "css = '''\n", "app {\n", " display: flex;\n", " flex-direction: column;\n", " height: 97vh;\n", "}\n", "\n", "menu_and_figures {\n", " flex: 1;\n", "}\n", "'''" ] }, { "cell_type": "markdown", "id": "265e6cbe", "metadata": {}, "source": [ "## set panel and holoviews extension" ] }, { "cell_type": "code", "execution_count": null, "id": "fe815e88", "metadata": {}, "outputs": [], "source": [ "pn.extension('katex', raw_css=[css], loading_color='#000000')\n", "hv.extension('bokeh', width=100)" ] }, { "cell_type": "markdown", "id": "0e6f1d76", "metadata": {}, "source": [ "## OGGM" ] }, { "cell_type": "code", "execution_count": null, "id": "4deefb86", "metadata": {}, "outputs": [], "source": [ "from oggm.core.massbalance import MassBalanceModel, PastMassBalance, ConstantMassBalance\n", "from oggm.utils import ncDataset, date_to_floatyear, floatyear_to_date\n", "from oggm import cfg\n", "from oggm.cfg import SEC_IN_YEAR, SEC_IN_MONTH\n", "\n", "cfg.initialize_minimal()" ] }, { "cell_type": "markdown", "id": "5a6d8d68", "metadata": {}, "source": [ "## Other Stuff" ] }, { "cell_type": "code", "execution_count": null, "id": "cc2d16a5", "metadata": {}, "outputs": [], "source": [ "from app_template import template\n", "from version import __version__" ] }, { "cell_type": "markdown", "id": "718a434f-c833-44d6-b283-e0573248397b", "metadata": {}, "source": [ "## Analytics" ] }, { "cell_type": "code", "execution_count": null, "id": "f7641b2b-6f80-46e7-a95a-43c70df4cd9c", "metadata": {}, "outputs": [], "source": [ "analytics = pn.pane.HTML('')" ] }, { "cell_type": "markdown", "id": "af113f5f", "metadata": {}, "source": [ "# define some settings" ] }, { "cell_type": "code", "execution_count": null, "id": "1b09aaa9", "metadata": {}, "outputs": [], "source": [ "cfg.PARAMS['use_bias_for_run'] = False\n", "\n", "climate_data_dir = 'climate_data/'" ] }, { "cell_type": "markdown", "id": "cf82a780", "metadata": {}, "source": [ "# Define some default values" ] }, { "cell_type": "code", "execution_count": null, "id": "ac7cb54d", "metadata": {}, "outputs": [], "source": [ "# set default language\n", "language = 'en'\n", "\n", "# help variable for setting a new base climate (needed for different languages)\n", "climate_meta_data = ['_HEF', 1300, 4600]\n", "\n", "# variable to keep track which figures are already updated (for each tab)\n", "tab_figures_updated = [True, True, True]\n", "climographs_updated = [True, True, True]\n", "active_tab = 0" ] }, { "cell_type": "markdown", "id": "6b780c2b", "metadata": {}, "source": [ "# Define Language Selector" ] }, { "cell_type": "markdown", "id": "caec48c4", "metadata": {}, "source": [ "Help functions to set new language" ] }, { "cell_type": "code", "execution_count": null, "id": "4864e777", "metadata": {}, "outputs": [], "source": [ "def language_selector_function(arg=None):\n", " global language\n", " language = language_selector.value\n", " change_language()\n", "\n", "\n", "def change_language():\n", " toogle_figures_loading()\n", "\n", " set_climate_tab_language()\n", "\n", " set_mb_months_language()\n", "\n", " # change base climate name language for mb models (use filesuffix)\n", " for i, climate_meta_data in enumerate(climate_tab_text['base_climate_meta_data']):\n", " file_suffix = climate_meta_data[0]\n", " if file_suffix == mb_models[0].input_filesuffix:\n", " mb_models[0].base_climate_name = climate_tab_text['base_climate_names'][language][i]\n", " if file_suffix == mb_models[1].input_filesuffix:\n", " mb_models[1].base_climate_name = climate_tab_text['base_climate_names'][language][i]\n", "\n", " set_mb_settings_tab_language()\n", "\n", " # change headings in menu\n", " set_tab_menu_tabs()\n", "\n", " set_change_selected_MB_RadioButtonGroup_language()\n", "\n", " # change headings for figures\n", " set_figures_tab_tabs()\n", "\n", " set_period_buttons_language()\n", "\n", " set_select_months_language()\n", "\n", " # update figures\n", " tab_figures_updated = [False, False, False]\n", " climographs_updated = [False, False, False]\n", " update_current_figures()\n", "\n", " toogle_figures_loading()" ] }, { "cell_type": "markdown", "id": "85283b56", "metadata": {}, "source": [ "Actual Language Selector" ] }, { "cell_type": "code", "execution_count": null, "id": "0d75c6f1", "metadata": {}, "outputs": [], "source": [ "from app_text import supported_languages\n", "\n", "language_selector = pn.widgets.RadioBoxGroup(name='select your language',\n", " options=supported_languages,\n", " inline=True,\n", " margin=(0, 0),\n", " width=70,\n", " align='center',\n", " height=15,\n", " )\n", "language_selector.param.watch(language_selector_function, 'value');" ] }, { "cell_type": "markdown", "id": "bcafd69c", "metadata": {}, "source": [ "# Define Menu" ] }, { "cell_type": "code", "execution_count": null, "id": "03fa6815", "metadata": {}, "outputs": [], "source": [ "# define background color of tab menu\n", "menu_background = '#f4f4f4'\n", "\n", "# define width for menu-tabs\n", "panel_width = 280\n", "\n", "# define width for whole menu\n", "tab_menu_width = 400\n", "\n", "# needed for some initialisations for start of app\n", "initial_run = True\n", "\n", "current_mb_i = 0" ] }, { "cell_type": "markdown", "id": "7d5fbac2", "metadata": {}, "source": [ "## Climate Tab" ] }, { "cell_type": "code", "execution_count": null, "id": "9d9faf06", "metadata": {}, "outputs": [], "source": [ "# Import Text for Climate Tab\n", "from app_text import climate_tab_text" ] }, { "cell_type": "code", "execution_count": null, "id": "d92fbef6", "metadata": {}, "outputs": [], "source": [ "# Function to change language of Climate Tab\n", "def set_climate_tab_language():\n", " base_climate_select.name = climate_tab_text['base_climate_select_name'][language]\n", "\n", " base_climate_select.options = climate_tab_text['base_climate_names'][language]\n", "\n", " y_start_slider.name = climate_tab_text['y_start_slider_name'][language]\n", "\n", " y_end_slider.name = climate_tab_text['y_end_slider_name'][language]\n", "\n", " set_climate_button.name = climate_tab_text['set_climate_button_name'][language]" ] }, { "cell_type": "code", "execution_count": null, "id": "02006bf2", "metadata": {}, "outputs": [], "source": [ "base_climate_select = pn.widgets.Select()\n", "\n", "y_end_slider = pn.widgets.IntSlider(start=1902,\n", " end=2020,\n", " step=1,\n", " value=2020)\n", "\n", "\n", "def change_y_end_slider_start(event):\n", " if y_start_slider.value > y_end_slider.value:\n", " y_end_slider.value = y_start_slider.value + 1\n", " if y_start_slider.value == 2019:\n", " y_end_slider.disabled = True\n", " else:\n", " y_end_slider.disabled = False\n", " y_end_slider.start = y_start_slider.value + 1\n", "\n", "\n", "y_start_slider = pn.widgets.IntSlider(start=1902,\n", " end=2019,\n", " step=1,\n", " value=1990)\n", "y_start_slider.param.watch(change_y_end_slider_start, ['value_throttled'])\n", "change_y_end_slider_start(None)\n", "\n", "\n", "def set_climate_button_click(event):\n", " global climate_meta_data\n", "\n", " set_default_mb_settings()\n", " # set file suffix for current selection\n", " for i, base_name in enumerate(climate_tab_text['base_climate_names'][language]):\n", " if base_name == base_climate_select.value:\n", " climate_meta_data = climate_tab_text['base_climate_meta_data'][i]\n", "\n", " set_climate_of_mb_model(current_mb_i)\n", "\n", " tab_figures_updated[current_mb_i] = False\n", " tab_figures_updated[2] = False\n", " climographs_updated[current_mb_i] = False\n", " climographs_updated[2] = False\n", " update_current_figures()\n", "\n", "\n", "set_climate_button = pn.widgets.Button(sizing_mode='stretch_width')\n", "set_climate_button.on_click(set_climate_button_click)\n", "\n", "set_climate_tab_language()\n", "\n", "climate_tab = pn.Column(base_climate_select,\n", " y_start_slider,\n", " y_end_slider,\n", " set_climate_button,\n", " background=menu_background,\n", " width=panel_width,\n", " sizing_mode='stretch_height')" ] }, { "cell_type": "markdown", "id": "f4810c32", "metadata": {}, "source": [ "## MB Settings" ] }, { "cell_type": "code", "execution_count": null, "id": "eca0386c", "metadata": {}, "outputs": [], "source": [ "from app_text import mb_settings_tab_text" ] }, { "cell_type": "code", "execution_count": null, "id": "584eeec9", "metadata": {}, "outputs": [], "source": [ "# Function to change language of MB Settings Tab\n", "def set_mb_settings_tab_language():\n", " mu_slider.name = mb_settings_tab_text['mu_slider_name'][language]\n", "\n", " temp_bias_slider.name = mb_settings_tab_text['temp_bias_slider_name'][language]\n", "\n", " temp_grad_slider.name = mb_settings_tab_text['temp_grad_slider_name'][language]\n", "\n", " prcp_fac_slider.name = mb_settings_tab_text['prcp_fac_slider_name'][language]\n", "\n", " temp_melt_slider.name = mb_settings_tab_text['temp_melt_slider_name'][language]\n", "\n", " temp_solid_slider.name = mb_settings_tab_text['temp_solid_slider_name'][language]\n", "\n", " temp_liquid_slider.name = mb_settings_tab_text['temp_liquid_slider_name'][language]\n", "\n", " set_mb_settings_button.name = mb_settings_tab_text['set_mb_settings_button_name'][language]" ] }, { "cell_type": "code", "execution_count": null, "id": "905a2188", "metadata": {}, "outputs": [], "source": [ "# MB Settings\n", "default_mu = 200\n", "min_mu = 100\n", "max_mu = 300\n", "mu_unit = 'kg m⁻² °C⁻¹ mth⁻¹'\n", "mu_slider = pn.widgets.IntSlider(start=min_mu,\n", " end=max_mu,\n", " step=10,\n", " value=default_mu)\n", "mu_slider.format = PrintfTickFormatter(format='%d ' + mu_unit)\n", "\n", "default_temp_bias = 0\n", "temp_bias_slider = pn.widgets.FloatSlider(start=-5,\n", " end=5,\n", " step=0.1,\n", " value=default_temp_bias)\n", "temp_bias_slider.format = PrintfTickFormatter(format='%.1f °C')\n", "\n", "temp_grad_slider = pn.widgets.FloatSlider(start=cfg.PARAMS['temp_local_gradient_bounds'][0] * 100,\n", " end=cfg.PARAMS['temp_local_gradient_bounds'][1] * 100,\n", " step=0.01,\n", " value=cfg.PARAMS['temp_default_gradient'] * 100)\n", "temp_grad_slider.format = PrintfTickFormatter(format='%.2f °C/100m')\n", "\n", "prcp_fac_slider = pn.widgets.FloatSlider(start=0.5,\n", " end=5,\n", " step=0.1,\n", " value=cfg.PARAMS['prcp_scaling_factor'])\n", "\n", "temp_melt_slider = pn.widgets.FloatSlider(start=-2,\n", " end=0,\n", " step=0.1,\n", " value=cfg.PARAMS['temp_melt'])\n", "temp_melt_slider.format = PrintfTickFormatter(format='%.1f °C')\n", "\n", "temp_solid_slider = pn.widgets.FloatSlider(start=-0.5,\n", " end=0.5,\n", " step=0.1,\n", " value=cfg.PARAMS['temp_all_solid'])\n", "temp_solid_slider.format = PrintfTickFormatter(format='%.1f °C')\n", "\n", "temp_liquid_slider = pn.widgets.FloatSlider(start=0.5,\n", " end=3,\n", " step=0.1,\n", " value=cfg.PARAMS['temp_all_liq'])\n", "temp_liquid_slider.format = PrintfTickFormatter(format='%.1f °C')\n", "\n", "\n", "def set_mb_settings_click(event):\n", " set_mb_settings_of_mb_model(current_mb_i)\n", " \n", " tab_figures_updated[current_mb_i] = False\n", " tab_figures_updated[2] = False\n", " update_current_figures()\n", "\n", "\n", "def set_default_mb_settings():\n", " mu_slider.value = default_mu\n", " temp_bias_slider.value = default_temp_bias\n", " temp_grad_slider.value = cfg.PARAMS['temp_default_gradient'] * 100\n", " prcp_fac_slider.value = cfg.PARAMS['prcp_scaling_factor']\n", " temp_melt_slider.value = cfg.PARAMS['temp_melt']\n", " temp_solid_slider.value = cfg.PARAMS['temp_all_solid']\n", " temp_liquid_slider.value = cfg.PARAMS['temp_all_liq']\n", "\n", "\n", "set_mb_settings_button = pn.widgets.Button(name='Set MB Settings',\n", " sizing_mode='stretch_width')\n", "set_mb_settings_button.on_click(set_mb_settings_click)\n", "\n", "set_mb_settings_tab_language()\n", "\n", "MB_settings_tab = pn.Column(mu_slider,\n", " temp_bias_slider,\n", " temp_grad_slider,\n", " prcp_fac_slider,\n", " temp_melt_slider,\n", " temp_solid_slider,\n", " temp_liquid_slider,\n", " set_mb_settings_button,\n", " width=panel_width,\n", " sizing_mode='stretch_height')" ] }, { "cell_type": "markdown", "id": "25a24e65", "metadata": {}, "source": [ "## But all Tabs together" ] }, { "cell_type": "code", "execution_count": null, "id": "1223c600", "metadata": {}, "outputs": [], "source": [ "tab_menu = pn.Tabs(('', []),\n", " height=420,\n", " width=tab_menu_width,\n", " background=menu_background,\n", " tabs_location='left')\n", "\n", "# is necassary to change the tabs title language\n", "\n", "\n", "def set_tab_menu_tabs():\n", " tab_menu.clear()\n", "\n", " tab_menu.append((climate_tab_text['heading'][language],\n", " climate_tab))\n", "\n", " tab_menu.append((mb_settings_tab_text['heading'][language],\n", " MB_settings_tab))\n", "\n", "\n", "set_tab_menu_tabs()" ] }, { "cell_type": "markdown", "id": "ac781de7", "metadata": {}, "source": [ "## functions toggle figures loading status" ] }, { "cell_type": "code", "execution_count": null, "id": "bc007b4c", "metadata": {}, "outputs": [], "source": [ "def toogle_figures_loading():\n", " figures_tab.loading = not figures_tab.loading" ] }, { "cell_type": "markdown", "id": "00482de4", "metadata": {}, "source": [ "# Logos for App" ] }, { "cell_type": "code", "execution_count": null, "id": "b57acc52", "metadata": {}, "outputs": [], "source": [ "oggm_edu_logo_link = ('

' +\n", " '' +\n", " '

')\n", "hv_logo_link = ''\n", "uni_ibk_logo = '

'\n", "uni_bremen_logo = '

'\n", "uni_bristol_logo = '

'\n", "hv_logo = pn.panel(hv_logo_link,\n", " margin=(0, 0),\n", " height=75,)\n", "uni_logos = pn.Column(pn.Pane(oggm_edu_logo_link, margin=(0, 0), align='center'),\n", " pn.Spacer(height=35),\n", " pn.Pane(uni_ibk_logo, margin=(0, 0), align='center'),\n", " pn.Spacer(height=25),\n", " pn.Pane(uni_bremen_logo, margin=(0, 0), align='center', height=40),\n", " pn.Spacer(height=5),\n", " pn.Pane(uni_bristol_logo, margin=(0, 0), align='center'),\n", " )\n", "all_logos = pn.Row(pn.Spacer(width=30),\n", " uni_logos,\n", " pn.Spacer(width=30),\n", " pn.Column(pn.Spacer(height=60,\n", " margin=(0, 0),\n", " ),\n", " pn.Pane(hv_logo_link, margin=(0, 0), align='center')\n", " ),\n", " height=150\n", " )" ] }, { "cell_type": "markdown", "id": "bd85a46b", "metadata": {}, "source": [ "# Define function for text" ] }, { "cell_type": "code", "execution_count": null, "id": "e28f9ce0", "metadata": {}, "outputs": [], "source": [ "def get_simple_text(text='', width=30, font_size='30pt'):\n", " return pn.Column(pn.layout.VSpacer(),\n", " pn.widgets.StaticText(value=text,\n", " style={'font-size': font_size}),\n", " pn.layout.VSpacer(),\n", " width=width,\n", " sizing_mode=\"stretch_height\",\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "ebf2aa6c", "metadata": {}, "outputs": [], "source": [ "def get_latex_text(text='', width=50, font_size='40pt'):\n", " return pn.Column(pn.layout.VSpacer(),\n", " pn.pane.LaTeX(text,\n", " style={'font-size': font_size}),\n", " pn.layout.VSpacer(),\n", " width=width,\n", " sizing_mode=\"stretch_height\",\n", " )" ] }, { "cell_type": "markdown", "id": "54947fd2", "metadata": {}, "source": [ "# MassBalanceClass" ] }, { "cell_type": "markdown", "id": "3eb049ae", "metadata": {}, "source": [ "## Adapted OGGM MassBalanceModels to avoid the need of gdirs" ] }, { "cell_type": "code", "execution_count": null, "id": "7551f6b2", "metadata": {}, "outputs": [], "source": [ "class PastMassBalanceAdapted(PastMassBalance):\n", " \"\"\"Mass balance during the climate data period.\"\"\"\n", "\n", " def __init__(self, min_height=0, max_height=7000,\n", " mu_star=None, bias=None,\n", " filename='climate_historical', input_filesuffix='',\n", " hemisphere='nh',\n", " fpath=climate_data_dir, t_solid=None, t_liq=None,\n", " t_melt=None, prcp_fac=None, t_grad=None,\n", " repeat=False, ys=None, ye=None):\n", " \"\"\"TODO\n", " \"\"\"\n", "\n", " super(PastMassBalance, self).__init__()\n", "\n", " self.valid_bounds = [min_height, max_height] # in m\n", " self.default_heights = np.arange(self.valid_bounds[0],\n", " self.valid_bounds[1] + 1,\n", " 100)\n", "\n", " if mu_star is None:\n", " mu_star = default_mu\n", "\n", " if bias is None:\n", " bias = 0.\n", "\n", " self.mu_star = np.array(mu_star)\n", " self.bias = np.array(bias)\n", "\n", " # Parameters\n", " if t_solid is None:\n", " self.t_solid = np.array(cfg.PARAMS['temp_all_solid'])\n", " else:\n", " self.t_solid = np.array(t_solid)\n", " if t_liq is None:\n", " self.t_liq = np.array(cfg.PARAMS['temp_all_liq'])\n", " else:\n", " self.t_liq = np.array(t_liq)\n", " if t_melt is None:\n", " self.t_melt = np.array(cfg.PARAMS['temp_melt'])\n", " else:\n", " self.t_melt = np.array(t_melt)\n", " if prcp_fac is None:\n", " prcp_fac = np.array(cfg.PARAMS['prcp_scaling_factor'])\n", " # check if valid prcp_fac is used\n", " if prcp_fac <= 0:\n", " raise InvalidParamsError('prcp_fac has to be above zero!')\n", " if t_grad is None:\n", " t_grad = cfg.PARAMS['temp_default_gradient']\n", "\n", " # Public attrs\n", " self.hemisphere = hemisphere\n", " self.repeat = repeat\n", "\n", " # Private attrs\n", " # to allow prcp_fac to be changed after instantiation\n", " # prescribe the prcp_fac as it is instantiated\n", " self._prcp_fac = prcp_fac\n", " # same for temp bias\n", " self._temp_bias = 0.\n", "\n", " # Read file\n", " with ncDataset(fpath + filename + input_filesuffix + '.nc', mode='r') as nc:\n", " # time\n", " time = nc.variables['time']\n", " try:\n", " time = netCDF4.num2date(time[:], time.units)\n", " except ValueError:\n", " # This is for longer time series\n", " time = cftime.num2date(time[:], time.units, calendar='noleap')\n", " ny, r = divmod(len(time), 12)\n", " if r != 0:\n", " raise ValueError('Climate data should be N full years')\n", " # This is where we switch to hydro float year format\n", " # Last year gives the tone of the hydro year\n", " self.years = np.repeat(np.arange(time[-1].year-ny+1,\n", " time[-1].year+1), 12)\n", " self.months = np.tile(np.arange(1, 13), ny)\n", " # save true timestamps\n", " self.years_true = np.array([t.year for t in time])\n", " self.months_true = np.array([t.month for t in time])\n", " # Read timeseries and correct it\n", " self.temp = nc.variables['temp'][:].astype(\n", " np.float64) + self._temp_bias\n", " self.prcp = nc.variables['prcp'][:].astype(\n", " np.float64) * self._prcp_fac\n", " # This is only needed if we want to use the gradient of the dataset\n", " # if 'gradient' in nc.variables:\n", " # grad = nc.variables['gradient'][:].astype(np.float64)\n", " # # Security for stuff that can happen with local gradients\n", " # g_minmax = cfg.PARAMS['temp_local_gradient_bounds']\n", " # grad = np.where(~np.isfinite(grad), t_grad, grad)\n", " # grad = clip_array(grad, g_minmax[0], g_minmax[1])\n", " # else:\n", " # grad = self.prcp * 0 + t_grad\n", "\n", " self.ref_hgt = nc.ref_hgt\n", " self.ref_lon = nc.ref_pix_lon\n", " self.ref_lat = nc.ref_pix_lat\n", " self.ref_dis = nc.ref_pix_dis\n", " self.climate_source = nc.climate_source\n", " self.ys = self.years[0] if ys is None else ys\n", " self.ye = self.years[-1] if ye is None else ye\n", "\n", " self._grad = None\n", " self.grad = t_grad\n", "\n", " @property\n", " def grad(self):\n", " return self._grad\n", "\n", " @grad.setter\n", " def grad(self, new_grad):\n", " self._grad = self.prcp * 0 + new_grad" ] }, { "cell_type": "code", "execution_count": null, "id": "d70a9cfd", "metadata": {}, "outputs": [], "source": [ "class ConstantMassBalanceAdapted(ConstantMassBalance):\n", " \"\"\"Constant mass-balance during a chosen period.\n", " This is useful for equilibrium experiments.\n", " \"\"\"\n", "\n", " def __init__(self, min_height=0, max_height=7000, mu_star=None, bias=None,\n", " y_start=1991, y_end=2020, filename='climate_historical',\n", " input_filesuffix='', hemisphere='nh', **kwargs):\n", " \"\"\"TODO\n", " \"\"\"\n", "\n", " super(ConstantMassBalance, self).__init__()\n", " self.mbmod = PastMassBalanceAdapted(min_height=min_height, max_height=max_height,\n", " mu_star=mu_star, bias=bias,\n", " filename=filename,\n", " input_filesuffix=input_filesuffix,\n", " hemisphere=hemisphere,\n", " **kwargs)\n", "\n", " self.valid_bounds = [min_height, max_height] # in m\n", " self.default_heights = self.mbmod.default_heights\n", " self.hbins = self.default_heights\n", "\n", " # Private attrs\n", " # to keep years up to date\n", " self._y_start = y_start\n", " self._y_end = y_end\n", " self.update_years()\n", "\n", " @property\n", " def y_start(self):\n", " return self._y_start\n", "\n", " @y_start.setter\n", " def y_start(self, value):\n", " self._y_start = y_start\n", " self.update_years()\n", "\n", " @property\n", " def y_end(self):\n", " return self._y_end\n", "\n", " @y_end.setter\n", " def y_end(self, value):\n", " self._y_end = value\n", " self.update_years()\n", "\n", " def update_years(self):\n", " if self._y_start == self._y_end:\n", " self.years = np.arange(self._y_start,\n", " self._y_end + 1)\n", " else:\n", " self.years = np.arange(self._y_start,\n", " self._y_end)\n", "\n", " # this two function are coppied of the original ConstantMassBalance Class without\n", " # the lazy decorator to be able to change y0 and halfsize, and also include\n", " # the heights direclty and not returning a function (interp1d)\n", " def interp_yr(self, heights):\n", " # annual MB\n", " mb_on_h = self.hbins*0.\n", " for yr in self.years:\n", " mb_on_h += self.mbmod.get_annual_mb(self.hbins, year=yr)\n", " return interp1d(self.hbins, mb_on_h / len(self.years))(heights)\n", "\n", " def interp_m(self, heights):\n", " # monthly MB\n", " months = np.arange(12)+1\n", " interp_m = []\n", " for m in months:\n", " mb_on_h = self.hbins*0.\n", " for yr in self.years:\n", " yr = date_to_floatyear(yr, m)\n", " mb_on_h += self.mbmod.get_monthly_mb(self.hbins, year=yr)\n", " interp_m.append(\n", " interp1d(self.hbins, mb_on_h / len(self.years))(heights))\n", " return interp_m\n", "\n", " def get_monthly_mb(self, heights, year=None, add_climate=False, **kwargs):\n", " yr, m = floatyear_to_date(year)\n", " if add_climate:\n", " t, tmelt, prcp, prcpsol = self.get_monthly_climate(\n", " heights, year=year)\n", " return self.interp_m(heights)[m-1], t, tmelt, prcp, prcpsol\n", " return self.interp_m(heights)[m-1]" ] }, { "cell_type": "markdown", "id": "df294361", "metadata": {}, "source": [ "## Class for extention of MB Models with visualisations" ] }, { "cell_type": "code", "execution_count": null, "id": "0c9e3339", "metadata": {}, "outputs": [], "source": [ "from app_text import climograph_plot_labels\n", "from app_text import general_plot_labels\n", "from app_text import base_climate_timeseries_plot_labels\n", "from app_text import mb_curve_plot_labels\n", "from app_text import tab_headings" ] }, { "cell_type": "code", "execution_count": null, "id": "5d3ebd73", "metadata": {}, "outputs": [], "source": [ "class MassBalanceVis(ConstantMassBalanceAdapted):\n", " \"\"\"Mass balance during the climate data period.\"\"\"\n", "\n", " def __init__(self,\n", " min_height=0,\n", " max_height=7000,\n", " input_filesuffix='',\n", " hemisphere='nh',\n", " mb_model_nr=0,\n", " t_grad=None,\n", " base_climate_name='',\n", " mu=200,\n", " y_start=1991,\n", " y_end=2020,\n", " t_solid=None,\n", " t_liq=None,\n", " t_melt=None,\n", " prcp_fac=None,\n", " repeat=False, ys=None, ye=None):\n", " \"\"\"TODO\n", " \"\"\"\n", "\n", " super(MassBalanceVis, self).__init__(min_height=min_height,\n", " max_height=max_height,\n", " input_filesuffix=input_filesuffix,\n", " hemisphere=hemisphere,\n", " t_grad=t_grad,\n", " mu_star=mu,\n", " y_start=y_start,\n", " y_end=y_end,\n", " t_solid=t_solid,\n", " t_liq=t_liq,\n", " t_melt=t_melt,\n", " prcp_fac=prcp_fac,\n", " repeat=repeat,\n", " ys=ys,\n", " ye=ye\n", " )\n", "\n", " self.base_climate_name = base_climate_name\n", " self.input_filesuffix = input_filesuffix # only needed to change language\n", " self.mb_model_nr = mb_model_nr\n", "\n", " # using months in hydro year\n", " self.months_short = {'Oct': 1,\n", " 'Nov': 2,\n", " 'Dec': 3,\n", " 'Jan': 4,\n", " 'Feb': 5,\n", " 'Mar': 6,\n", " 'Apr': 7,\n", " 'May': 8,\n", " 'Jun': 9,\n", " 'Jul': 10,\n", " 'Aug': 11,\n", " 'Sep': 12}\n", "\n", " self.default_tools = ['pan', 'wheel_zoom', 'save']\n", " self.active_tools = ['pan', 'wheel_zoom']\n", "\n", " def get_climograph(self, ref_height=None, y_lim_temp=None,\n", " y_lim_prcp_max=None, add_MB_nr_title=False,\n", " **kwargs):\n", " def prcp_hook(plot, element):\n", " p = plot.state\n", "\n", " # color yaxis of prcp axis\n", " prcp_color = 'blue'\n", " plot.handles['yaxis'].axis_label_text_color = prcp_color\n", " plot.handles['yaxis'].major_label_text_color = prcp_color\n", " plot.handles['yaxis'].axis_line_color = prcp_color\n", " plot.handles['yaxis'].major_tick_line_color = prcp_color\n", " plot.handles['yaxis'].minor_tick_line_color = prcp_color\n", "\n", " # for updating hover language\n", " plot.handles['hover'].tooltips = hover_tooltips\n", " plot.handles['hover'].formatters = hover_formatters\n", "\n", " def temp_hook(plot, element):\n", " p = plot.state\n", "\n", " temp_color = 'red'\n", "\n", " y2_label = general_plot_labels['Temperature'][language] + ' (°C)'\n", " # create secondary range and axis\n", " if 'twiny' not in [t for t in p.extra_y_ranges]:\n", " p.y_range = Range1d(start=plot.handles['y_range'].start,\n", " end=plot.handles['y_range'].end)\n", " p.y_range.name = 'default'\n", " p.extra_y_ranges = {\"twiny\": Range1d(start=-10, end=10)}\n", " p.add_layout(LinearAxis(axis_label=y2_label,\n", " y_range_name=\"twiny\",\n", " axis_label_text_color=temp_color,\n", " major_label_text_color=temp_color,\n", " axis_line_color=temp_color,\n", " major_tick_line_color=temp_color,\n", " minor_tick_line_color=temp_color), 'right')\n", "\n", " # set glyph y_range_name to the one we've just created\n", " glyph = p.renderers[-1]\n", " glyph.y_range_name = 'twiny'\n", "\n", " # set range of second y axis\n", " p.extra_y_ranges[\"twiny\"].start = y_lim_temp[0]\n", " p.extra_y_ranges[\"twiny\"].end = y_lim_temp[1]\n", "\n", " if ref_height is None:\n", " ref_height = self.mbmod.ref_hgt\n", "\n", " temp_data = []\n", " prcp_data = []\n", " for month_name, month_nr in self.months_short.items():\n", " temp, tempformelt, prcp_total, prcp_sol = \\\n", " self.get_monthly_climate(\n", " heights=[ref_height], year=month_nr/12)\n", " temp_data = np.append(temp_data, temp - self.mbmod.temp_bias)\n", " prcp_data = np.append(prcp_data, prcp_total / self.mbmod._prcp_fac)\n", "\n", " if self.mbmod.hemisphere == 'sh':\n", " temp_data = np.roll(temp_data, 6)\n", " prcp_data = np.roll(prcp_data, 6)\n", "\n", " total_prcp = np.repeat(np.sum(prcp_data), len(prcp_data))\n", " mean_temp = np.repeat(np.mean(temp_data), len(temp_data))\n", "\n", " if y_lim_prcp_max is None:\n", " y_lim_prcp_max = max(prcp_data) * 1.1\n", "\n", " if y_lim_temp is None:\n", " y_add_temp_range = (max(temp_data) - min(temp_data)) * 0.05\n", " y_lim_temp = (min(temp_data) - y_add_temp_range,\n", " max(temp_data) + y_add_temp_range)\n", "\n", " # this is needed to show Temperatuer and Precipitation in the same hover\n", " df = pd.DataFrame({'Month': np.array(general_plot_labels['Months_short'][language]),\n", " 'MonthLong': np.array(general_plot_labels['Months_long'][language]),\n", " 'Precipitation': np.array(prcp_data),\n", " 'Temperature': np.array(temp_data),\n", " 'totalPrecipitation': np.array(total_prcp),\n", " 'meanTemperature': np.array(mean_temp)})\n", "\n", " hover_tooltips = \"\"\"\n", "
\n", " \"\"\" + \\\n", " general_plot_labels['Month'][language] + \\\n", " \"\"\": @{MonthLong}\n", "
\n", " \"\"\" + \\\n", " general_plot_labels['Precipitation'][language] + \\\n", " \"\"\": @{Precipitation}{%d} mm\n", "
\n", " \"\"\" + \\\n", " general_plot_labels['totalPrecipitation'][language] + \\\n", " \"\"\": @{totalPrecipitation}{%d} mm\n", "
\n", " \"\"\" + \\\n", " general_plot_labels['Temperature'][language] + \\\n", " \"\"\": @{Temperature}{%0.1f} °C\n", "
\n", " \"\"\" + \\\n", " general_plot_labels['meanTemperature'][language] + \\\n", " \"\"\": @{meanTemperature}{%0.1f} °C\n", "
\"\"\"\n", "\n", " hover_formatters = {'@{Precipitation}': 'printf',\n", " '@{totalPrecipitation}': 'printf',\n", " '@{Temperature}': 'printf',\n", " '@{meanTemperature}': 'printf'}\n", "\n", " hover = HoverTool(mode='vline')\n", "\n", " tools = ['save', hover]\n", "\n", " if add_MB_nr_title:\n", " title_prefix = 'MB ' + str(self.mb_model_nr + 1) + ', '\n", " else:\n", " title_prefix = ''\n", "\n", " return (hv.Bars(df,\n", " kdims='Month',\n", " vdims=['Precipitation', 'Temperature', 'MonthLong',\n", " 'totalPrecipitation', 'meanTemperature'],\n", " ).opts(color='blue',\n", " responsive=True,\n", " ylim=(0, y_lim_prcp_max),\n", " ylabel=general_plot_labels['Precipitation'][language] +\n", " ' (mm)',\n", " hooks=[prcp_hook],\n", " xlabel='',\n", " default_tools=tools\n", " ) *\n", " hv.Curve(df,\n", " vdims='Temperature',\n", " kdims='Month'\n", " ).opts(color='red',\n", " hooks=[temp_hook],\n", " responsive=True,\n", " xlabel='',\n", " default_tools=['save'] # tools\n", " )\n", " ).opts(title=(title_prefix +\n", " climograph_plot_labels['Period'][language] + ': ' +\n", " str(self.years[0]) +\n", " ' ' + climograph_plot_labels['to'][language] + ' ' +\n", " str(self.years[-1] + 1) + ', ' +\n", " climograph_plot_labels['Height'][language] + ': ' +\n", " '{:d} m'.format(int(ref_height))),\n", " xrotation=45)\n", "\n", " def get_monthly_components(self, month, **kwargs):\n", " heights = self.default_heights\n", "\n", " # for conversion depending on hemisphere\n", " if self.mbmod.hemisphere == 'nh':\n", " add_to_month = 0\n", " elif self.mbmod.hemisphere == 'sh':\n", " add_to_month = 6\n", "\n", " mb, t, tmelt, prcp, prcpsol = self.get_monthly_mb(heights=heights,\n", " year=(\n", " self.months_short[month] + add_to_month)/12,\n", " add_climate=True)\n", " month_acc = prcpsol\n", " month_abl = - self.mbmod.mu_star * tmelt\n", " return month_acc, month_abl\n", "\n", " def get_annual_components(self, **kwargs):\n", " heights = self.default_heights\n", " mb, t, tmelt, prcp, prcpsol = self.get_annual_mb(\n", " heights=heights, add_climate=True)\n", " annual_acc = prcpsol\n", " annual_abl = - self.mbmod.mu_star * tmelt\n", " return annual_acc, annual_abl\n", "\n", " def get_xlim_annual(self, **kwargs):\n", " heights = self.default_heights\n", " annual_accumulation, annual_ablation = self.get_annual_components()\n", " total_range = np.max(annual_accumulation) - np.min(annual_ablation)\n", " add_lim = total_range * 0.05\n", "\n", " return (np.min(annual_ablation) - add_lim, np.max(annual_accumulation) + add_lim)\n", "\n", " def get_annual_mb_curve(self, months=[], kdims=None, vdims=None, **kwargs):\n", " heights = self.default_heights\n", " mb_annual = self.get_annual_mb(\n", " heights=heights) * SEC_IN_YEAR * self.mbmod.rho\n", "\n", " if kdims is None:\n", " kdims = 'MB annual ' + str(self.mb_model_nr)\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " annual_mb_curve = hv.Curve((mb_annual, heights),\n", " kdims=kdims,\n", " vdims=vdims,\n", " label=mb_curve_plot_labels['annual'][language],\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year'][language],\n", " ylim=(\n", " np.min(heights), np.max(heights)),\n", " xlim=self.get_xlim_annual(),\n", " )\n", "\n", " annual_mb_curve.opts(opts.Curve(framewise=True))\n", "\n", " return annual_mb_curve\n", "\n", " def get_month_mb_curve(self, month=None, vdims=None, **kwargs):\n", " heights = self.default_heights\n", "\n", " # for conversion depending on hemisphere\n", " if self.mbmod.hemisphere == 'nh':\n", " add_to_month = 0\n", " elif self.mbmod.hemisphere == 'sh':\n", " add_to_month = 6\n", "\n", " mb_month = self.get_monthly_mb(\n", " heights=heights, year=(self.months_short[month] + add_to_month)/12) \\\n", " * SEC_IN_MONTH * self.mbmod.rho\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " month_mb_curve = hv.Curve((mb_month, heights),\n", " kdims='MB ' + month + str(self.mb_model_nr),\n", " vdims=vdims,\n", " label=month\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " ylim=(np.min(heights),\n", " np.max(heights)),\n", " xlim=(np.min(mb_month) - 1,\n", " np.max(mb_month) + 1),\n", " )\n", "\n", " month_mb_curve.opts(opts.Curve(framewise=True))\n", "\n", " return month_mb_curve\n", "\n", " def get_annual_accumulation_curve(self, kdims=None, vdims=None, **kwargs):\n", " heights = self.default_heights\n", " annual_accumulation, annual_ablation = self.get_annual_components()\n", "\n", " if kdims is None:\n", " kdims = 'Acc. annual ' + str(self.mb_model_nr)\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " annual_accumulation_curve = hv.Curve((annual_accumulation, heights),\n", " kdims=kdims,\n", " vdims=vdims,\n", " label=mb_curve_plot_labels['annual'][language],\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year'][language],\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " ylim=(np.min(heights),\n", " np.max(heights)),\n", " xlim=self.get_xlim_annual()\n", " )\n", "\n", " annual_accumulation_curve.opts(opts.Curve(framewise=True))\n", " return annual_accumulation_curve\n", "\n", " def get_annual_ablation_curve(self, kdims=None, vdims=None, **kwargs):\n", " heights = self.default_heights\n", " annual_accumulation, annual_ablation = self.get_annual_components()\n", "\n", " if kdims is None:\n", " kdims = 'Abl. annual ' + str(self.mb_model_nr)\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " annual_ablation_curve = hv.Curve((annual_ablation, heights),\n", " kdims=kdims,\n", " vdims=vdims,\n", " label=mb_curve_plot_labels['annual'][language],\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year'][language],\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " ylim=(np.min(heights),\n", " np.max(heights)),\n", " xlim=self.get_xlim_annual()\n", " )\n", "\n", " annual_ablation_curve.opts(opts.Curve(framewise=True))\n", "\n", " return annual_ablation_curve\n", "\n", " def get_month_accumulation_curve(self, month=None, vdims=None, **kwargs):\n", " heights = self.default_heights\n", " month_accumulation, month_ablation = self.get_monthly_components(\n", " heights=heights, month=month)\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " month_accumulation_curve = hv.Curve((month_accumulation, heights),\n", " kdims='Acc. ' + month +\n", " str(self.mb_model_nr),\n", " vdims=vdims,\n", " label=month\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " ylim=(np.min(heights),\n", " np.max(heights)),\n", " xlim=self.get_xlim_annual()\n", " )\n", "\n", " month_accumulation_curve.opts(opts.Curve(framewise=True))\n", "\n", " return month_accumulation_curve\n", "\n", " def get_month_ablation_curve(self, month=None, vdims=None, **kwarg):\n", " heights = self.default_heights\n", " month_accumulation, month_ablation = self.get_monthly_components(\n", " heights=heights, month=month)\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " month_ablation_curve = hv.Curve((month_ablation, heights),\n", " kdims='Abl. ' + month +\n", " str(self.mb_model_nr),\n", " vdims=vdims,\n", " label=month\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " ylim=(np.min(heights),\n", " np.max(heights)),\n", " xlim=self.get_xlim_annual()\n", " )\n", "\n", " month_ablation_curve.opts(opts.Curve(framewise=True))\n", "\n", " return month_ablation_curve\n", "\n", " def get_ELA_curve(self, kdims=None, vdims=None, xlim=None, **kwarg):\n", " heights = self.default_heights\n", "\n", " ELA = self.get_ela()\n", "\n", " if xlim is None:\n", " xlim = self.get_xlim_annual()\n", "\n", " if vdims is None:\n", " vdims = 'height (m)' + str(self.mb_model_nr)\n", "\n", " ELA_curve = hv.Curve((list(xlim),\n", " [ELA, ELA]),\n", " kdims=kdims + str(self.mb_model_nr),\n", " vdims=vdims,\n", " label='ELA'\n", " ).opts(responsive=True,\n", " color='black',\n", " line_dash='dashed',\n", " default_tools=self.default_tools,\n", " active_tools=self.active_tools,\n", " ylim=(np.min(heights), np.max(heights)),\n", " xlim=xlim,\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " )\n", "\n", " ELA_curve.opts(opts.Curve(framewise=True))\n", "\n", " return ELA_curve\n", "\n", " def get_vline_with_hover(self, position=0, months=[], var='mb'):\n", " heights = self.default_heights\n", " if var == 'mb':\n", " first_var = self.get_annual_mb(\n", " heights=heights) * SEC_IN_YEAR * self.mbmod.rho\n", " else:\n", " annual_accumulation, annual_ablation = self.get_annual_components()\n", " if var == 'abl':\n", " first_var = annual_ablation\n", " elif var == 'acc':\n", " first_var = annual_accumulation\n", "\n", " data = {'height' + str(self.mb_model_nr): heights,\n", " 'annual' + str(self.mb_model_nr): first_var,\n", " 'position' + str(self.mb_model_nr): np.repeat(position, len(heights))}\n", " vdims = ['height' + str(self.mb_model_nr),\n", " 'annual' + str(self.mb_model_nr)]\n", " kdims = ['position' + str(self.mb_model_nr)]\n", " hover_tooltips = '''\n", "
\n", " ''' + \\\n", " mb_curve_plot_labels['Height'][language] + \\\n", " ''': @{height''' + str(self.mb_model_nr) + '''}{%0.0f} m\n", "
\n", " ''' + \\\n", " mb_curve_plot_labels['annual'][language] + \\\n", " ''': @{annual''' + str(self.mb_model_nr) + '''}{%0.0f} ''' + \\\n", " mb_curve_plot_labels['kg/m2_and_year'][language] + \\\n", " '''\n", " '''\n", " hover_formatters = {'@{height' + str(self.mb_model_nr) + '}': 'printf',\n", " '@{annual' + str(self.mb_model_nr) + '}': 'printf'}\n", "\n", " # for conversion depending on hemisphere\n", " if self.mbmod.hemisphere == 'nh':\n", " add_to_month = 0\n", " elif self.mbmod.hemisphere == 'sh':\n", " add_to_month = 6\n", "\n", " for month in general_plot_labels['Months_short'][language]:\n", " if var == 'mb':\n", " data[month] = self.get_monthly_mb(heights=heights,\n", " year=(self.months_short[month] + add_to_month)/12) \\\n", " * SEC_IN_MONTH * self.mbmod.rho\n", " else:\n", " month_accumulation, month_ablation = self.get_monthly_components(\n", " heights=heights, month=month)\n", " if var == 'abl':\n", " data[month] = month_ablation\n", " elif var == 'acc':\n", " data[month] = month_accumulation\n", " for month in months:\n", " vdims.append(month)\n", " hover_tooltips += ('
' +\n", " '' +\n", " month + ': @{' + month + '}{%0.0f} ' +\n", " mb_curve_plot_labels['kg/m2_and_month'][language] + '')\n", " hover_formatters['@{' + month + '}'] = 'printf'\n", "\n", " hover_tooltips += '
'\n", "\n", " hover = HoverTool(mode='hline')\n", "\n", " def hover_hook(plot, element):\n", " plot.handles['hover'].tooltips = hover_tooltips\n", " plot.handles['hover'].formatters = hover_formatters\n", "\n", " vline_curve = hv.Curve(pd.DataFrame(data),\n", " kdims=kdims,\n", " vdims=vdims,\n", " ).opts(responsive=True,\n", " default_tools=self.default_tools +\n", " [hover],\n", " color='gray',\n", " line_width=1,\n", " line_alpha=0.5,\n", " ylabel=(mb_curve_plot_labels['Height'][language] +\n", " ' (m)'),\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year_or_month'][language],\n", " ylim=(\n", " np.min(heights), np.max(heights)),\n", " xlim=self.get_xlim_annual(),\n", " hooks=[hover_hook]\n", " )\n", "\n", " vline_curve.opts(opts.Curve(framewise=True))\n", "\n", " return vline_curve\n", "\n", " def get_climate_timeseries(self):\n", " def prcp_hook(plot, element):\n", " p = plot.state\n", "\n", " # color yaxis of prcp axis\n", " prcp_color = 'blue'\n", " plot.handles['yaxis'].axis_label_text_color = prcp_color\n", " plot.handles['yaxis'].major_label_text_color = prcp_color\n", " plot.handles['yaxis'].axis_line_color = prcp_color\n", " plot.handles['yaxis'].major_tick_line_color = prcp_color\n", " plot.handles['yaxis'].minor_tick_line_color = prcp_color\n", "\n", " def temp_hook(plot, element):\n", " p = plot.state\n", "\n", " temp_color = 'red'\n", "\n", " y2_label = general_plot_labels['Temperature'][language] + ' (°C)'\n", " # create secondary range and axis\n", " if 'twiny' not in [t for t in p.extra_y_ranges]:\n", " p.y_range = Range1d(start=plot.handles['y_range'].start,\n", " end=plot.handles['y_range'].end)\n", " p.y_range.name = 'default'\n", " p.extra_y_ranges = {\"twiny\": Range1d(start=-10, end=10)}\n", " p.add_layout(LinearAxis(axis_label=y2_label,\n", " y_range_name=\"twiny\",\n", " axis_label_text_color=temp_color,\n", " major_label_text_color=temp_color,\n", " axis_line_color=temp_color,\n", " major_tick_line_color=temp_color,\n", " minor_tick_line_color=temp_color), 'right')\n", "\n", " # set glyph y_range_name to the one we've just created\n", " glyph = p.renderers[-1]\n", " glyph.y_range_name = 'twiny'\n", " if 'Temperature' in glyph.data_source.data:\n", " vals = glyph.data_source.data['Temperature']\n", "\n", " # set range of second y axis\n", " y_add_range = (vals.max() - vals.min()) * 0.05\n", " p.extra_y_ranges[\"twiny\"].start = vals.min() - y_add_range * 4\n", " p.extra_y_ranges[\"twiny\"].end = vals.max() + y_add_range\n", "\n", " # this function is needed as the names are defined with 0 = October\n", " def get_mth_name_nr(real_mth):\n", " ny, r = divmod(real_mth + 2, 12)\n", " return r\n", " # this is needed to show Temperatuer and Precipitation in the same hover\n", " df = pd.DataFrame({'Month': np.array([general_plot_labels['Months_long'][language][get_mth_name_nr(i)]\n", " for i in self.mbmod.months_true]),\n", " 'Year_real': self.mbmod.years_true,\n", " 'Year_hydro': self.mbmod.years,\n", " 'Precipitation': self.mbmod.prcp / self.mbmod._prcp_fac,\n", " 'Temperature': self.mbmod.temp - self.mbmod.temp_bias},\n", " index=pd.to_datetime(\n", " pd.DataFrame({'year': self.mbmod.years_true,\n", " 'month': self.mbmod.months_true,\n", " 'day': np.repeat(1, len(self.mbmod.years_true))}\n", " )\n", " )\n", " )\n", " df.index.name = 'Time'\n", "\n", " # calculate yearly means\n", " df_mean_yr = df.groupby('Year_hydro').mean()\n", " df['Temperature_yr_mean'] = np.repeat(\n", " df_mean_yr['Temperature'], 12).values\n", " df['Precipitation_yr_mean'] = np.repeat(\n", " df_mean_yr['Precipitation'], 12).values\n", "\n", " # calculate total means\n", " df_mean_total = df.mean(numeric_only=True)\n", " df['Temperature_total_mean'] = np.repeat(\n", " df_mean_total['Temperature'], len(df))\n", " df['Precipitation_total_mean'] = np.repeat(\n", " df_mean_total['Precipitation'], len(df))\n", "\n", " hover = HoverTool(tooltips=\"\"\"\n", "
\n", " \"\"\" +\n", " base_climate_timeseries_plot_labels['Year'][language] +\n", " \"\"\": @{Year_real}\n", "
\n", " \"\"\" +\n", " general_plot_labels['Month'][language] +\n", " \"\"\": @{Month}\n", "
\n", " \"\"\" +\n", " base_climate_timeseries_plot_labels['Hydro-Year'][language] +\n", " \"\"\": @{Year_hydro}\n", "
\n", " \"\"\" +\n", " general_plot_labels['Precipitation'][language] +\n", " \"\"\": @{Precipitation}{%d} mm\n", "
\n", " \"\"\" +\n", " base_climate_timeseries_plot_labels['Yearly Mean Prcp'][language] +\n", " \"\"\": @{Precipitation_yr_mean}{%d} mm\n", "
\n", " \"\"\" +\n", " general_plot_labels['Temperature'][language] +\n", " \"\"\": @{Temperature}{%0.1f} °C\n", "
\n", " \"\"\" +\n", " base_climate_timeseries_plot_labels['Yearly Mean Temp'][language] +\n", " \"\"\": @{Temperature_yr_mean}{%0.1f} °C\n", "
\"\"\",\n", " formatters={'@{Precipitation}': 'printf',\n", " '@{Temperature}': 'printf',\n", " '@{Temperature_yr_mean}': 'printf',\n", " '@{Precipitation_yr_mean}': 'printf'},\n", " mode='vline')\n", " tools = ['save', 'xwheel_zoom', 'xpan', 'reset']\n", " active_tools = ['xwheel_zoom', 'xpan']\n", "\n", " temp_curve = hv.Curve(df,\n", " vdims='Temperature',\n", " kdims='Time'\n", " ).opts(color='red',\n", " alpha=0.5,\n", " hooks=[temp_hook],\n", " responsive=True,\n", " xlabel='',\n", " default_tools=tools\n", " )\n", "\n", " temp_yr_mean_curve = hv.Curve(df,\n", " vdims=['Temperature_yr_mean'],\n", " kdims='Time'\n", " ).opts(color='red',\n", " hooks=[temp_hook],\n", " responsive=True,\n", " line_dash='dashed',\n", " xlabel='',\n", " default_tools=tools\n", " )\n", " temp_total_mean_curve = hv.Curve(df,\n", " vdims=['Temperature_total_mean', 'Temperature',\n", " 'Precipitation', 'Year_real', 'Month', 'Year_hydro',\n", " 'Temperature_yr_mean', 'Precipitation_yr_mean'],\n", " kdims='Time',\n", " label=('Total mean Temp (' +\n", " str(df['Temperature_total_mean'].values[0]) +\n", " ' °C')\n", " ).opts(color='red',\n", " hooks=[temp_hook],\n", " responsive=True,\n", " xlabel='',\n", " default_tools=tools + [hover],\n", " active_tools=active_tools\n", " )\n", "\n", " prcp_curve = hv.Area(df,\n", " kdims='Time',\n", " vdims='Precipitation',\n", " ).opts(color='blue',\n", " line_color=None,\n", " fill_alpha=0.5,\n", " responsive=True,\n", " ylim=(0, max(self.mbmod.prcp /\n", " self.mbmod._prcp_fac) * 1.5),\n", " ylabel=general_plot_labels['Precipitation'][language] +\n", " ' (mm)',\n", " hooks=[prcp_hook],\n", " xlabel='',\n", " default_tools=tools\n", " )\n", " prcp_yr_mean_curve = hv.Curve(df,\n", " vdims=['Precipitation_yr_mean'],\n", " kdims='Time'\n", " ).opts(color='blue',\n", " hooks=[prcp_hook],\n", " responsive=True,\n", " line_dash='dashed',\n", " ylim=(\n", " 0, max(self.mbmod.prcp / self.mbmod._prcp_fac) * 1.5),\n", " ylabel=general_plot_labels['Precipitation'][language] +\n", " ' (mm)',\n", " xlabel='',\n", " default_tools=tools\n", " )\n", " prcp_total_mean_curve = hv.Curve(df,\n", " vdims='Precipitation_total_mean',\n", " kdims='Time',\n", " label='Total mean Prcp'\n", " ).opts(color='blue',\n", " hooks=[prcp_hook],\n", " responsive=True,\n", " ylim=(\n", " 0, max(self.mbmod.prcp / self.mbmod._prcp_fac) * 1.5),\n", " ylabel=general_plot_labels['Precipitation'][language] +\n", " ' (mm)',\n", " xlabel='',\n", " default_tools=tools\n", " )\n", "\n", " timeseries_width = 1000\n", " tgt_temp = temp_curve.relabel('').opts(\n", " xlabel='',)\n", " src_temp = temp_curve.opts(\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " tgt_temp_yr_mean = temp_yr_mean_curve.relabel(\n", " base_climate_timeseries_plot_labels['Yearly Mean Temp'][language]).opts(\n", " xlabel='',)\n", " src_temp_yr_mean = temp_yr_mean_curve.opts(\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " tgt_temp_total_mean = temp_total_mean_curve.relabel(\n", " base_climate_timeseries_plot_labels['Total Mean Temp'][language] +\n", " ' ({:.1f} °C)'.format(\n", " df['Temperature_total_mean'].values[0])).opts(\n", " xlabel='',)\n", " src_temp_total_mean = temp_total_mean_curve.opts(\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " tgt_prcp = prcp_curve.relabel('').opts(\n", " labelled=['y'])\n", " src_prcp = prcp_curve.opts(\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " tgt_prcp_yr_mean = prcp_yr_mean_curve.relabel(\n", " base_climate_timeseries_plot_labels['Yearly Mean Prcp'][language]).opts(\n", " xlabel='',)\n", " src_prcp_yr_mean = prcp_yr_mean_curve.opts(\n", " # width=timeseries_width,\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " tgt_prcp_total_mean = prcp_total_mean_curve.relabel(\n", " base_climate_timeseries_plot_labels['Total Mean Prcp'][language] +\n", " ' ({:.0f} mm)'.format(\n", " df['Precipitation_total_mean'].values[0])).opts(\n", " xlabel='',)\n", " src_prcp_total_mean = prcp_total_mean_curve.opts(\n", " height=100,\n", " yaxis=None,\n", " default_tools=[],\n", " active_tools=[])\n", "\n", " # RangeToolLink(src_temp, tgt_temp)\n", " RangeToolLink(src_prcp, tgt_prcp)\n", "\n", " def source_hook(plot, element):\n", " p = plot.state\n", " p.yaxis.visible = False\n", "\n", " def tgt_hook(plot, element):\n", " self.timeseries_x_range_handle = plot.handles['x_range']\n", "\n", " # range month depend on hemisphere (start of hydrological year)\n", " if self.mbmod.hemisphere == 'nh':\n", " hydro_month_range = [10, 9]\n", " elif self.mbmod.hemisphere == 'sh':\n", " hydro_month_range = [4, 3]\n", "\n", " if len(self.years) == 1:\n", " xlim = pd.to_datetime(pd.DataFrame({'year': [self.years[0] - 1, self.years[0]],\n", " 'month': hydro_month_range,\n", " 'day': [1, 1]}\n", " ))\n", " else:\n", " xlim = pd.to_datetime(pd.DataFrame({'year': [self.years[0] - 1, self.years[-1]],\n", " 'month': hydro_month_range,\n", " 'day': [1, 1]}\n", " ))\n", " self.timeseries_xlim = xlim\n", " layout = ((tgt_prcp * tgt_prcp_yr_mean * tgt_prcp_total_mean *\n", " tgt_temp * tgt_temp_yr_mean * tgt_temp_total_mean\n", " ).opts(legend_position='left',\n", " legend_offset=(5, 10),\n", " xlim=tuple(xlim.values),\n", " hooks=[tgt_hook],\n", " ) +\n", " (src_prcp * src_prcp_yr_mean * src_prcp_total_mean *\n", " src_temp * src_temp_yr_mean * src_temp_total_mean\n", " ).opts(hooks=[source_hook],\n", " show_legend=False)\n", " ).cols(1)\n", " layout.opts(opts.Layout(shared_axes=False, merge_tools=False))\n", "\n", " return layout" ] }, { "cell_type": "markdown", "id": "3d402838", "metadata": {}, "source": [ "# Define default MassBalanceModels" ] }, { "cell_type": "code", "execution_count": null, "id": "4762d211", "metadata": {}, "outputs": [], "source": [ "mb_models = [MassBalanceVis(\n", " min_height=climate_tab_text['base_climate_meta_data'][0][1],\n", " max_height=climate_tab_text['base_climate_meta_data'][0][2],\n", " input_filesuffix=climate_tab_text['base_climate_meta_data'][0][0],\n", " hemisphere=climate_tab_text['base_climate_meta_data'][0][3],\n", " mb_model_nr=0,\n", " t_grad=temp_grad_slider.value / 100,\n", " base_climate_name=climate_tab_text['base_climate_names'][language][0],\n", " mu=mu_slider.value,\n", " y_start=y_start_slider.value,\n", " y_end=y_end_slider.value,\n", " t_solid=temp_solid_slider.value,\n", " t_liq=temp_liquid_slider.value,\n", " t_melt=temp_melt_slider.value,\n", " prcp_fac=prcp_fac_slider.value),\n", " MassBalanceVis(\n", " min_height=climate_tab_text['base_climate_meta_data'][1][1],\n", " max_height=climate_tab_text['base_climate_meta_data'][1][2],\n", " input_filesuffix=climate_tab_text['base_climate_meta_data'][1][0],\n", " hemisphere=climate_tab_text['base_climate_meta_data'][1][3],\n", " mb_model_nr=1,\n", " t_grad=temp_grad_slider.value / 100,\n", " base_climate_name=climate_tab_text['base_climate_names'][language][1],\n", " mu=mu_slider.value,\n", " y_start=y_start_slider.value,\n", " y_end=y_end_slider.value,\n", " t_solid=temp_solid_slider.value,\n", " t_liq=temp_liquid_slider.value,\n", " t_melt=temp_melt_slider.value,\n", " prcp_fac=prcp_fac_slider.value)]" ] }, { "cell_type": "markdown", "id": "0146b2e6", "metadata": {}, "source": [ "## set language of mb months" ] }, { "cell_type": "code", "execution_count": null, "id": "f7a6e98a", "metadata": {}, "outputs": [], "source": [ "def set_mb_months_language():\n", " months_dict = {month: i + 1 for i,\n", " month in enumerate(general_plot_labels['Months_short'][language])}\n", " mb_models[0].months_short = months_dict\n", " mb_models[1].months_short = months_dict" ] }, { "cell_type": "markdown", "id": "6c6cf676", "metadata": {}, "source": [ "# Connect MB Models with menu" ] }, { "cell_type": "markdown", "id": "26250b07", "metadata": {}, "source": [ "## climate" ] }, { "cell_type": "code", "execution_count": null, "id": "d1975a9c", "metadata": {}, "outputs": [], "source": [ "def set_climate_of_mb_model(mb_i):\n", " global mb_models\n", " global climate_meta_data\n", "\n", " # initialise new MB with new climate settings\n", " mb_models[mb_i] = MassBalanceVis(\n", " min_height=climate_meta_data[1],\n", " max_height=climate_meta_data[2],\n", " input_filesuffix=climate_meta_data[0],\n", " hemisphere=climate_meta_data[3],\n", " mb_model_nr=mb_i,\n", " t_grad=temp_grad_slider.value / 100,\n", " base_climate_name=base_climate_select.value,\n", " mu=mu_slider.value,\n", " y_start=y_start_slider.value,\n", " y_end=y_end_slider.value,\n", " t_solid=temp_solid_slider.value,\n", " t_liq=temp_liquid_slider.value,\n", " t_melt=temp_melt_slider.value,\n", " prcp_fac=prcp_fac_slider.value)\n", " mb_models[mb_i].temp_bias = temp_bias_slider.value" ] }, { "cell_type": "code", "execution_count": null, "id": "b776d850", "metadata": {}, "outputs": [], "source": [ "def set_climate_menu_with_selected_mb_model(mb_i):\n", " base_climate_select.value = mb_models[mb_i].base_climate_name\n", " y_start_slider.value = int(mb_models[mb_i].y_start)\n", " y_end_slider.value = int(mb_models[mb_i].y_end)\n", " change_y_end_slider_start(None)" ] }, { "cell_type": "markdown", "id": "6d329519", "metadata": {}, "source": [ "## MB settings" ] }, { "cell_type": "code", "execution_count": null, "id": "d5141424", "metadata": {}, "outputs": [], "source": [ "def set_mb_settings_of_mb_model(mb_i):\n", " mb_models[mb_i].mbmod.mu_star = np.array(mu_slider.value)\n", " mb_models[mb_i].mbmod.t_melt = np.array(temp_melt_slider.value)\n", " mb_models[mb_i].mbmod.t_solid = np.array(temp_solid_slider.value)\n", " mb_models[mb_i].mbmod.t_liq = np.array(temp_liquid_slider.value)\n", " mb_models[mb_i].prcp_fac = np.array(prcp_fac_slider.value)\n", " mb_models[mb_i].temp_bias = np.array(temp_bias_slider.value)\n", " mb_models[mb_i].mbmod.grad = np.array(temp_grad_slider.value / 100)" ] }, { "cell_type": "code", "execution_count": null, "id": "161d0d9e", "metadata": {}, "outputs": [], "source": [ "def set_mb_settings_menu_with_selected_mb_model(mb_i):\n", " mu_slider.value = int(mb_models[mb_i].mbmod.mu_star)\n", " temp_melt_slider.value = float(mb_models[mb_i].mbmod.t_melt)\n", " temp_solid_slider.value = float(mb_models[mb_i].mbmod.t_solid)\n", " temp_liquid_slider.value = float(mb_models[mb_i].mbmod.t_liq)\n", " prcp_fac_slider.value = float(mb_models[mb_i].mbmod.prcp_fac)\n", " temp_bias_slider.value = float(mb_models[mb_i].mbmod.temp_bias)\n", " temp_grad_slider.value = float(mb_models[mb_i].mbmod.grad[0]) * 100" ] }, { "cell_type": "markdown", "id": "e469f711", "metadata": {}, "source": [ "# Induvidual MassBalance plots" ] }, { "cell_type": "code", "execution_count": null, "id": "f71fbbda", "metadata": {}, "outputs": [], "source": [ "def dyn_overlay_accumulation(months, update, mb_i=0):\n", " overlay = mb_models[mb_i].get_ELA_curve(kdims='Acc.' + str(mb_i))\n", " overlay *= mb_models[mb_i].get_vline_with_hover(months=months, var='acc')\n", " overlay *= mb_models[mb_i].get_annual_accumulation_curve()\n", " for month in list(mb_models[mb_i].months_short.keys()):\n", " if month in months:\n", " overlay *= mb_models[mb_i].get_month_accumulation_curve(\n", " month=month)\n", " else:\n", " overlay *= hv.Curve((0, 0), label='').opts(responsive=True,\n", " default_tools=mb_models[mb_i].default_tools,\n", " active_tools=mb_models[mb_i].active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylim=(np.min(mb_models[mb_i].default_heights),\n", " np.max(mb_models[mb_i].default_heights))\n", " )\n", " return overlay.opts(title=mb_curve_plot_labels['Accumulation'][language],\n", " toolbar='above',\n", " show_legend=True,\n", " legend_position='top_left',\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year_or_month'][language]\n", " )\n", "\n", "\n", "def dyn_overlay_ablation(months, update, mb_i=0):\n", " overlay = mb_models[mb_i].get_ELA_curve(kdims='Abl.' + str(mb_i))\n", " overlay *= mb_models[mb_i].get_vline_with_hover(months=months, var='abl')\n", " overlay *= mb_models[mb_i].get_annual_ablation_curve()\n", " for month in list(mb_models[mb_i].months_short.keys()):\n", " if month in months:\n", " overlay *= mb_models[mb_i].get_month_ablation_curve(month=month)\n", " else:\n", " overlay *= hv.Curve((0, 0), label='').opts(responsive=True,\n", " default_tools=mb_models[mb_i].default_tools,\n", " active_tools=mb_models[mb_i].active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylim=(np.min(mb_models[mb_i].default_heights),\n", " np.max(mb_models[mb_i].default_heights))\n", " )\n", " return overlay.opts(title=mb_curve_plot_labels['Ablation'][language],\n", " ylabel='',\n", " toolbar='above',\n", " show_legend=False,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year_or_month'][language]\n", " )\n", "\n", "\n", "def dyn_overlay_total_mb(months, update, mb_i=0):\n", " overlay = mb_models[mb_i].get_ELA_curve(kdims='MB' + str(mb_i))\n", " overlay *= mb_models[mb_i].get_vline_with_hover(months=months, var='mb')\n", " overlay *= mb_models[mb_i].get_annual_mb_curve(months=months)\n", " for month in list(mb_models[mb_i].months_short.keys()):\n", " if month in months:\n", " overlay *= mb_models[mb_i].get_month_mb_curve(\n", " month=month).opts(xlim=(None, None))\n", " else:\n", " overlay *= hv.Curve((0, 0), label='').opts(responsive=True,\n", " default_tools=mb_models[mb_i].default_tools,\n", " active_tools=mb_models[mb_i].active_tools,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_month'][language],\n", " ylim=(np.min(mb_models[mb_i].default_heights),\n", " np.max(mb_models[mb_i].default_heights))\n", " )\n", " return overlay.opts(title=mb_curve_plot_labels['Mass-Balance'][language],\n", " ylabel='',\n", " toolbar='above',\n", " show_legend=False,\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year_or_month'][language]\n", " )\n", "\n", "\n", "select_months_mb_plot_0 = pn.widgets.CheckBoxGroup(\n", " name='month selection',\n", " value=[],\n", " inline=False,\n", " width=50)\n", "select_months_mb_plot_1 = pn.widgets.CheckBoxGroup(\n", " name='month selection',\n", " value=[],\n", " inline=False,\n", " width=50)\n", "select_months_mb_plot_both = [select_months_mb_plot_0,\n", " select_months_mb_plot_1]\n", "\n", "\n", "def set_select_months_language():\n", " select_months_mb_plot_both[0].options = general_plot_labels['Months_short'][language]\n", " select_months_mb_plot_both[1].options = general_plot_labels['Months_short'][language]\n", "\n", "\n", "set_select_months_language()\n", "\n", "mb_plot_updater_0 = pn.widgets.Checkbox(name='Update MB Plot 0')\n", "mb_plot_updater_1 = pn.widgets.Checkbox(name='Update MB Plot 1')\n", "mb_plot_updater_both = [mb_plot_updater_0,\n", " mb_plot_updater_1]\n", "\n", "dmap_accumulation_both = [hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_accumulation, mb_i=0),\n", " months=select_months_mb_plot_0,\n", " update=mb_plot_updater_0)),\n", " hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_accumulation, mb_i=1),\n", " months=select_months_mb_plot_1,\n", " update=mb_plot_updater_1)), ]\n", "\n", "dmap_ablation_both = [hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_ablation, mb_i=0),\n", " months=select_months_mb_plot_0,\n", " update=mb_plot_updater_0)),\n", " hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_ablation, mb_i=1),\n", " months=select_months_mb_plot_1,\n", " update=mb_plot_updater_1)), ]\n", "\n", "dmap_total_mb_both = [hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_total_mb, mb_i=0),\n", " months=select_months_mb_plot_0,\n", " update=mb_plot_updater_0)),\n", " hv.DynamicMap(\n", " pn.bind(partial(dyn_overlay_total_mb, mb_i=1),\n", " months=select_months_mb_plot_1,\n", " update=mb_plot_updater_1)), ]\n", "\n", "\n", "def get_complete_mb_figure(mb_i):\n", " return pn.Row(pn.Column(pn.layout.VSpacer(),\n", " select_months_mb_plot_both[mb_i],\n", " pn.layout.VSpacer(),\n", " width=50,\n", " sizing_mode=\"stretch_height\",\n", " ),\n", " pn.Row(dmap_accumulation_both[mb_i],\n", " get_simple_text('+'),\n", " dmap_ablation_both[mb_i],\n", " get_simple_text('='),\n", " dmap_total_mb_both[mb_i],\n", " sizing_mode='stretch_both'\n", " ),\n", " sizing_mode='stretch_both',\n", " )\n", "\n", "\n", "mb_figures = [get_complete_mb_figure(0),\n", " get_complete_mb_figure(1)]" ] }, { "cell_type": "code", "execution_count": null, "id": "c7a815a5", "metadata": {}, "outputs": [], "source": [ "def toogle_mb_plot_disabled():\n", " select_months_mb_plot_0.disabled = not select_months_mb_plot_0.disabled\n", " select_months_mb_plot_1.disabled = not select_months_mb_plot_1.disabled" ] }, { "cell_type": "markdown", "id": "5c29e66a", "metadata": {}, "source": [ "# Compare MassBalance plot" ] }, { "cell_type": "code", "execution_count": null, "id": "0d0e23f1", "metadata": {}, "outputs": [], "source": [ "color_mb_0 = 'blue'\n", "color_mb_1 = 'red'\n", "\n", "\n", "def get_xlim_comparison():\n", " xlim_0 = mb_models[0].get_xlim_annual()\n", " xlim_1 = mb_models[1].get_xlim_annual()\n", " return (min(xlim_0[0], xlim_1[0]), max(xlim_0[1], xlim_1[1]))\n", "\n", "\n", "def get_heights_comparison():\n", " heights_0 = mb_models[0].default_heights\n", " heights_1 = mb_models[1].default_heights\n", " return np.arange(min(heights_0[0], heights_1[0]),\n", " max(heights_0[-1], heights_1[-1]) + 1,\n", " 100)\n", "\n", "\n", "def get_vline_hover_comparison(position=0, var='mb'):\n", " heights = get_heights_comparison()\n", "\n", " var_0 = np.empty(len(heights))\n", " var_0[:] = np.NaN\n", " ind_0 = np.isin(heights, mb_models[0].default_heights)\n", "\n", " var_1 = np.empty(len(heights))\n", " var_1[:] = np.NaN\n", " ind_1 = np.isin(heights, mb_models[1].default_heights)\n", "\n", " if var == 'mb':\n", " var_0[ind_0] = mb_models[0].get_annual_mb(\n", " heights=mb_models[0].default_heights) * SEC_IN_YEAR * mb_models[0].mbmod.rho\n", " var_1[ind_1] = mb_models[1].get_annual_mb(\n", " heights=mb_models[1].default_heights) * SEC_IN_YEAR * mb_models[1].mbmod.rho\n", " else:\n", " annual_accumulation_0, annual_ablation_0 = mb_models[0].get_annual_components(\n", " )\n", " annual_accumulation_1, annual_ablation_1 = mb_models[1].get_annual_components(\n", " )\n", " if var == 'abl':\n", " var_0[ind_0] = annual_ablation_0\n", " var_1[ind_1] = annual_ablation_1\n", " elif var == 'acc':\n", " var_0[ind_0] = annual_accumulation_0\n", " var_1[ind_1] = annual_accumulation_1\n", "\n", " data = {'heightComp': heights,\n", " 'MB1': var_0,\n", " 'MB2': var_1,\n", " 'positionComp' + var: np.repeat(position, len(heights))}\n", " vdims = ['heightComp', 'MB1', 'MB2']\n", " kdims = ['positionComp' + var]\n", " hover_tooltips = '''\n", "
\n", " ''' + \\\n", " mb_curve_plot_labels['Height'][language] + \\\n", " ''': @{heightComp}{%0.0f} m\n", "
\n", " MB Model 1: @{MB1}{%0.0f} ''' + \\\n", " mb_curve_plot_labels['kg/m2_and_year'][language] + \\\n", " '''\n", "
\n", " MB Model 2: @{MB2}{%0.0f} ''' + \\\n", " mb_curve_plot_labels['kg/m2_and_year'][language] + \\\n", " '''\n", "
\n", " '''\n", " hover_formatters = {'@{heightComp}': 'printf',\n", " '@{MB1}': 'printf',\n", " '@{MB2}': 'printf'}\n", "\n", " hover = HoverTool(mode='hline')\n", "\n", " def hover_hook(plot, element):\n", " plot.handles['hover'].tooltips = hover_tooltips\n", " plot.handles['hover'].formatters = hover_formatters\n", "\n", " vline_curve = hv.Curve(pd.DataFrame(data),\n", " kdims=kdims,\n", " vdims=vdims,\n", " ).opts(responsive=True,\n", " default_tools=mb_models[0].default_tools +\n", " [hover],\n", " color='gray',\n", " line_width=1,\n", " line_alpha=0.5,\n", " ylabel=mb_curve_plot_labels['Height'][language] +\n", " ' (m)',\n", " xlabel=mb_curve_plot_labels['kg/m2_and_year'][language],\n", " ylim=(\n", " np.min(heights), np.max(heights)),\n", " xlim=get_xlim_comparison(),\n", " hooks=[hover_hook],\n", " )\n", "\n", " vline_curve.opts(opts.Curve(framewise=True))\n", "\n", " return vline_curve\n", "\n", "\n", "def dyn_overlay_comp_acc(update):\n", " overlay = get_vline_hover_comparison(position=0, var='acc')\n", " overlay *= mb_models[0].get_ELA_curve(kdims='Acc. Comp',\n", " vdims='h Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 1').opts(color=color_mb_0)\n", " overlay *= mb_models[0].get_annual_accumulation_curve(kdims='Acc. Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 1').opts(color=color_mb_0)\n", "\n", " overlay *= mb_models[1].get_ELA_curve(kdims='Acc. Comp',\n", " vdims='h Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 2').opts(color=color_mb_1)\n", " overlay *= mb_models[1].get_annual_accumulation_curve(kdims='Acc. Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 2').opts(color=color_mb_1)\n", "\n", " return overlay.opts(title=mb_curve_plot_labels['Accumulation'][language],\n", " toolbar='above',\n", " show_legend=True,\n", " legend_position='top_left',\n", " xlim=get_xlim_comparison()\n", " )\n", "\n", "\n", "def dyn_overlay_comp_abl(update):\n", " overlay = get_vline_hover_comparison(position=0, var='abl')\n", " overlay *= mb_models[0].get_ELA_curve(kdims='Abl. Comp',\n", " vdims='h Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 1').opts(color=color_mb_0)\n", " overlay *= mb_models[1].get_ELA_curve(kdims='Abl. Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 2').opts(color=color_mb_1)\n", "\n", " overlay *= mb_models[0].get_annual_ablation_curve(kdims='Abl. Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 1').opts(color=color_mb_0)\n", " overlay *= mb_models[1].get_annual_ablation_curve(kdims='Abl. Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 2').opts(color=color_mb_1)\n", "\n", " return overlay.opts(title=mb_curve_plot_labels['Ablation'][language],\n", " ylabel='',\n", " toolbar='above',\n", " show_legend=False,\n", " xlim=get_xlim_comparison()\n", " )\n", "\n", "\n", "def dyn_overlay_comp_total_mb(update):\n", " overlay = get_vline_hover_comparison(position=0, var='mb')\n", " overlay *= mb_models[0].get_ELA_curve(kdims='MB Comp',\n", " vdims='h Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 1').opts(color=color_mb_0)\n", " overlay *= mb_models[1].get_ELA_curve(kdims='MB Comp',\n", " vdims='h Comp',\n", " xlim=get_xlim_comparison()\n", " ).relabel('ELA 2').opts(color=color_mb_1)\n", "\n", " overlay *= mb_models[0].get_annual_mb_curve(kdims='MB Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 1').opts(color=color_mb_0)\n", " overlay *= mb_models[1].get_annual_mb_curve(kdims='MB Comp',\n", " vdims='h Comp',\n", " ).relabel('MB 2').opts(color=color_mb_1)\n", "\n", " return overlay.opts(title=mb_curve_plot_labels['Mass-Balance'][language],\n", " ylabel='',\n", " toolbar='above',\n", " show_legend=False,\n", " xlim=get_xlim_comparison()\n", " )\n", "\n", "\n", "mb_comp_plot_updater = pn.widgets.Checkbox(name='Update Comp MB Plot')\n", "\n", "dmap_comp_acc = hv.DynamicMap(\n", " pn.bind(dyn_overlay_comp_acc,\n", " update=mb_comp_plot_updater))\n", "\n", "dmap_comp_ablation = hv.DynamicMap(\n", " pn.bind(dyn_overlay_comp_abl,\n", " update=mb_comp_plot_updater))\n", "\n", "dmap_comp_total_mb_both = hv.DynamicMap(\n", " pn.bind(dyn_overlay_comp_total_mb,\n", " update=mb_comp_plot_updater))\n", "\n", "compare_mb_figure = pn.Row(dmap_comp_acc,\n", " get_simple_text('+'),\n", " dmap_comp_ablation,\n", " get_simple_text('='),\n", " dmap_comp_total_mb_both,\n", " sizing_mode='stretch_both'\n", " )" ] }, { "cell_type": "markdown", "id": "ded9f792", "metadata": {}, "source": [ "# Climographs" ] }, { "cell_type": "code", "execution_count": null, "id": "757f0eba", "metadata": {}, "outputs": [], "source": [ "def get_climograph(change, mb_i=0):\n", " return mb_models[mb_i].get_climograph().opts(toolbar='above')\n", "\n", "\n", "climograph_updater_0 = pn.widgets.Checkbox(name='Update Climograph 0')\n", "climograph_updater_1 = pn.widgets.Checkbox(name='Update Climograph 1')\n", "climograph_updater_both = [climograph_updater_0,\n", " climograph_updater_1]\n", "\n", "climographs = [hv.DynamicMap(\n", " pn.bind(partial(get_climograph, mb_i=0),\n", " change=climograph_updater_0)),\n", " hv.DynamicMap(\n", " pn.bind(partial(get_climograph, mb_i=1),\n", " change=climograph_updater_1)), ]" ] }, { "cell_type": "markdown", "id": "f7b33100", "metadata": {}, "source": [ "# Climographs Compare" ] }, { "cell_type": "code", "execution_count": null, "id": "3d793335", "metadata": {}, "outputs": [], "source": [ "def get_y_lims_climograph(ref_height):\n", " temp_0_data = []\n", " temp_1_data = []\n", " prcp_0_data = []\n", " prcp_1_data = []\n", " for month_name, month_nr in mb_models[0].months_short.items():\n", " mb_model = mb_models[0]\n", " temp, tempformelt, prcp_total, prcp_sol = \\\n", " mb_model.get_monthly_climate(\n", " heights=[ref_height], year=month_nr/12)\n", " temp_0_data = np.append(temp_0_data, temp)\n", " prcp_0_data = np.append(\n", " prcp_0_data, prcp_total / mb_model.mbmod._prcp_fac)\n", "\n", " mb_model = mb_models[1]\n", " temp, tempformelt, prcp_total, prcp_sol = \\\n", " mb_model.get_monthly_climate(\n", " heights=[ref_height], year=month_nr/12)\n", " temp_1_data = np.append(temp_1_data, temp)\n", " prcp_1_data = np.append(\n", " prcp_1_data, prcp_total / mb_model.mbmod._prcp_fac)\n", "\n", " y_lim_prcp_max = max(np.append(prcp_0_data, prcp_1_data)) * 1.1\n", "\n", " y_add_temp_0_range = (max(temp_0_data) - min(temp_0_data)) * 0.05\n", " y_lim_temp_0 = (min(temp_0_data) - y_add_temp_0_range,\n", " max(temp_0_data) + y_add_temp_0_range)\n", " y_add_temp_1_range = (max(temp_1_data) - min(temp_1_data)) * 0.05\n", " y_lim_temp_1 = (min(temp_1_data) - y_add_temp_1_range,\n", " max(temp_1_data) + y_add_temp_1_range)\n", "\n", " y_lim_temp = (min([y_lim_temp_0[0], y_lim_temp_1[0]]),\n", " max([y_lim_temp_0[1], y_lim_temp_1[1]]))\n", "\n", " return y_lim_temp, y_lim_prcp_max\n", "\n", "\n", "def get_climographs_comp(change):\n", " ref_height = min(mb_models[0].mbmod.ref_hgt, mb_models[1].mbmod.ref_hgt)\n", " y_lim_temp, y_lim_prcp_max = get_y_lims_climograph(ref_height)\n", "\n", " return (mb_models[0].get_climograph(ref_height=ref_height,\n", " y_lim_temp=y_lim_temp,\n", " y_lim_prcp_max=y_lim_prcp_max,\n", " add_MB_nr_title=True,\n", " ).opts(toolbar='above',\n", " ) +\n", " mb_models[1].get_climograph(ref_height=ref_height,\n", " y_lim_temp=y_lim_temp,\n", " y_lim_prcp_max=y_lim_prcp_max,\n", " add_MB_nr_title=True,\n", " ).opts(toolbar='above',\n", " )\n", " )\n", "\n", "\n", "climograph_comp_updater = pn.widgets.Checkbox(name='Update Climograph comp')\n", "\n", "\n", "climographs_comp = hv.DynamicMap(\n", " pn.bind(get_climographs_comp,\n", " change=climograph_comp_updater))" ] }, { "cell_type": "markdown", "id": "e8451aab", "metadata": {}, "source": [ "# Help Function to get table values" ] }, { "cell_type": "code", "execution_count": null, "id": "a5438982", "metadata": {}, "outputs": [], "source": [ "def get_table_values(mb_i, include_base_name=False):\n", " if include_base_name:\n", " values = [mb_models[mb_i].base_climate_name]\n", " else:\n", " values = []\n", " values.append(np.round(mb_models[mb_i].temp_bias, 1))\n", " values.append(np.round(mb_models[mb_i].mbmod.grad[0] * 100, 2))\n", " values.append(np.round(mb_models[mb_i].mbmod.prcp_fac, 1))\n", " values.append(mb_models[mb_i].mbmod.mu_star)\n", " values.append(np.round(mb_models[mb_i].mbmod.t_melt, 1))\n", " values.append(np.round(mb_models[mb_i].mbmod.t_solid, 1))\n", " values.append(np.round(mb_models[mb_i].mbmod.t_liq, 1))\n", "\n", " return values" ] }, { "cell_type": "markdown", "id": "956e2da4", "metadata": {}, "source": [ "# Table for current settings" ] }, { "cell_type": "code", "execution_count": null, "id": "9ca7badd", "metadata": {}, "outputs": [], "source": [ "def get_info_table(mb_i=0):\n", " variables = ['T_bias', 'T_grad', 'Prcp_fac',\n", " 'µ', 'T_melt', 'T_solid', 'T_liquid']\n", " units = ['°C', '°C/100m', ' ',\n", " mu_unit, '°C', '°C', '°C']\n", " values = get_table_values(mb_i, include_base_name=False)\n", "\n", " def table_hook(plot, element):\n", " plot.handles['table'].autosize_mode = \"none\"\n", " plot.handles['table'].columns[0].width = 50\n", " plot.handles['table'].columns[1].width = 40\n", " plot.handles['table'].columns[2].width = 100\n", "\n", " return hv.Table({'Variable': variables, 'Value': values, 'Unit': units},\n", " ['Variable'], ['Value', 'Unit'],\n", " ).opts(index_position=None,\n", " width=190,\n", " height=210,\n", " hooks=[table_hook]\n", " )\n", "\n", "\n", "# hook for hv.Table do not work correctly when used with DynamicMap (see https://github.com/holoviz/holoviews/issues/4343)\n", "# therefore make a hard refresh in update function ()\n", "info_tables = [pn.Column(pn.layout.VSpacer(),\n", " get_info_table(0),\n", " pn.layout.VSpacer(),\n", " width=190,\n", " sizing_mode='stretch_height'),\n", " pn.Column(pn.layout.VSpacer(),\n", " get_info_table(1),\n", " pn.layout.VSpacer(),\n", " width=190,\n", " sizing_mode='stretch_height')]" ] }, { "cell_type": "markdown", "id": "f5607e1b", "metadata": {}, "source": [ "# Table for comparision of current settings" ] }, { "cell_type": "code", "execution_count": null, "id": "fc2d4bde", "metadata": {}, "outputs": [], "source": [ "def get_compare_table(change):\n", " variables = ['Base Climate', 'T_bias', 'T_grad', 'Prcp_fac',\n", " 'µ', 'T_melt', 'T_solid', 'T_liquid']\n", " units = ['', '°C', '°C/100m', ' ',\n", " mu_unit, '°C', '°C', '°C']\n", " values_0 = get_table_values(mb_i=0, include_base_name=True)\n", "\n", " values_1 = get_table_values(mb_i=1, include_base_name=True)\n", "\n", " def table_hook(plot, element):\n", " plot.handles['table'].sizing_mode = 'stretch_width'\n", "\n", " return hv.Table({'Variable': variables,\n", " 'Values MB 1': values_0,\n", " 'Values MB 2': values_1,\n", " 'Unit': units},\n", " ['Variable'], ['Values MB 1', 'Values MB 2', 'Unit'],\n", " ).opts(index_position=None,\n", " height=230,\n", " hooks=[table_hook])\n", "\n", "\n", "compare_table_updater = pn.widgets.Checkbox(name='Update Compare table')\n", "\n", "compare_mb_table = hv.DynamicMap(\n", " pn.bind(get_compare_table,\n", " change=compare_table_updater))" ] }, { "cell_type": "markdown", "id": "cead5f03", "metadata": {}, "source": [ "# Climate Timeseries" ] }, { "cell_type": "markdown", "id": "78c4b8b6", "metadata": {}, "source": [ "## buttons to set period" ] }, { "cell_type": "code", "execution_count": null, "id": "4caddac1", "metadata": {}, "outputs": [], "source": [ "def set_period_buttons_language():\n", " button_name = base_climate_timeseries_plot_labels['set_period_buttons_name'][language]\n", " set_period_buttons[0].name = button_name\n", " set_period_buttons[1].name = button_name\n", "\n", "\n", "set_period_buttons = [pn.widgets.Button(width=106,\n", " height=83),\n", " pn.widgets.Button(width=106,\n", " height=83)]\n", "\n", "set_period_buttons_language()\n", "\n", "\n", "def set_new_period(event):\n", " global current_mb_i\n", "\n", " if type(mb_models[current_mb_i].timeseries_x_range_handle.start) == np.datetime64:\n", " period_start = pd.to_datetime(\n", " mb_models[current_mb_i].timeseries_x_range_handle.start)\n", " else:\n", " period_start = (pd.to_datetime(pd.DataFrame({'year': [1970],\n", " 'month': [1],\n", " 'day': [1]})) +\n", " pd.Timedelta(mb_models[current_mb_i].timeseries_x_range_handle.start,\n", " 'milliseconds'))[0]\n", "\n", " if type(mb_models[current_mb_i].timeseries_x_range_handle.end) == np.datetime64:\n", " period_end = pd.to_datetime(\n", " mb_models[current_mb_i].timeseries_x_range_handle.end)\n", " else:\n", " period_end = (pd.to_datetime(pd.DataFrame({'year': [1970],\n", " 'month': [1],\n", " 'day': [1]})) +\n", " pd.Timedelta(mb_models[current_mb_i].timeseries_x_range_handle.end,\n", " 'milliseconds'))[0]\n", "\n", " # depending on hemisphere different start_mth\n", " if mb_models[current_mb_i].mbmod.hemisphere == 'nh':\n", " start_mth = 10\n", " elif mb_models[current_mb_i].mbmod.hemisphere == 'sh':\n", " start_mth = 4\n", "\n", " if period_start.month >= start_mth:\n", " y_start_slider.value = period_start.year + 1\n", " else:\n", " y_start_slider.value = period_start.year\n", "\n", " change_y_end_slider_start(None)\n", "\n", " if period_end.month >= start_mth:\n", " y_end_slider.value = period_end.year + 1\n", " else:\n", " y_end_slider.value = period_end.year\n", "\n", " set_climate_button_click(None)\n", "\n", "\n", "set_period_buttons[0].on_click(set_new_period)\n", "set_period_buttons[1].on_click(set_new_period)" ] }, { "cell_type": "markdown", "id": "f027505f", "metadata": {}, "source": [ "## actual timeseries" ] }, { "cell_type": "code", "execution_count": null, "id": "3d2a259b", "metadata": {}, "outputs": [], "source": [ "def get_timeseries(mb_i=0):\n", " return mb_models[mb_i].get_climate_timeseries()\n", "\n", "\n", "timeseries = [pn.Row(get_timeseries(mb_i=0),\n", " sizing_mode='stretch_both'),\n", " pn.Row(get_timeseries(mb_i=1),\n", " sizing_mode='stretch_both')]" ] }, { "cell_type": "markdown", "id": "ff6aecbf", "metadata": {}, "source": [ "# Function to update figures" ] }, { "cell_type": "code", "execution_count": null, "id": "a29ac000", "metadata": {}, "outputs": [], "source": [ "def update_current_figures():\n", " if active_tab in [0, 1]:\n", " if not tab_figures_updated[active_tab]:\n", " toogle_figures_loading()\n", " mb_plot_updater_both[active_tab].value = not mb_plot_updater_both[active_tab].value\n", " info_tables[active_tab].objects = [\n", " pn.layout.VSpacer(), get_info_table(mb_i=active_tab), pn.layout.VSpacer()]\n", " tab_figures_updated[active_tab] = True\n", " if not climographs_updated[active_tab]:\n", " climograph_updater_both[active_tab].value = not climograph_updater_both[active_tab].value\n", " timeseries[active_tab].objects = [get_timeseries(mb_i=active_tab)]\n", " climographs_updated[active_tab] = True\n", " toogle_figures_loading()\n", " \n", " elif active_tab == 2:\n", " if not tab_figures_updated[active_tab]:\n", " toogle_figures_loading()\n", " compare_table_updater.value = not compare_table_updater.value\n", " mb_comp_plot_updater.value = not mb_comp_plot_updater.value\n", " tab_figures_updated[active_tab] = True\n", " if not climographs_updated[active_tab]:\n", " climograph_comp_updater.value = not climograph_comp_updater.value\n", " climographs_updated[active_tab] = True\n", " toogle_figures_loading()" ] }, { "cell_type": "markdown", "id": "0f19c1bc", "metadata": {}, "source": [ "# Put figures together" ] }, { "cell_type": "markdown", "id": "97063715", "metadata": {}, "source": [ "## Individual Mass-Balance Figures" ] }, { "cell_type": "code", "execution_count": null, "id": "94b8fc49", "metadata": {}, "outputs": [], "source": [ "def get_mb_tab(i):\n", " global mb_models\n", "\n", " return pn.Column(pn.Tabs((tab_headings['Current Settings and Climograph'][language],\n", " pn.Row(info_tables[i],\n", " climographs[i],\n", " sizing_mode='stretch_both')),\n", " (tab_headings['Base Climate Timeseries'][language],\n", " pn.Row(timeseries[i],\n", " pn.Column(pn.layout.VSpacer(),\n", " set_period_buttons[i]),\n", " sizing_mode='stretch_both')),\n", " sizing_mode='stretch_both',\n", " tabs_location='above',\n", " dynamic=False\n", " ),\n", " pn.layout.Divider(margin=(0, 0, 0, 0)),\n", " pn.Row(mb_figures[i],\n", " sizing_mode='stretch_both'),\n", " sizing_mode='stretch_both')" ] }, { "cell_type": "markdown", "id": "bdd7b77b", "metadata": {}, "source": [ "## Compare Mass-Balance Figure" ] }, { "cell_type": "markdown", "id": "104036dd", "metadata": {}, "source": [ "Buttons to change MBs on compariosion plot" ] }, { "cell_type": "code", "execution_count": null, "id": "fdc6f2ac", "metadata": {}, "outputs": [], "source": [ "from app_text import compare_tab_text" ] }, { "cell_type": "code", "execution_count": null, "id": "9bf9e44c", "metadata": {}, "outputs": [], "source": [ "change_selected_MB_options = []\n", "\n", "\n", "def change_selected_MB_click(event):\n", " global current_mb_i\n", "\n", " if event.new == change_selected_MB_options[0]:\n", " current_mb_i = 0\n", " set_climate_menu_with_selected_mb_model(0)\n", " set_mb_settings_menu_with_selected_mb_model(0)\n", " elif event.new == change_selected_MB_options[1]:\n", " current_mb_i = 1\n", " set_climate_menu_with_selected_mb_model(1)\n", " set_mb_settings_menu_with_selected_mb_model(1)\n", "\n", "\n", "change_selected_MB = pn.widgets.RadioButtonGroup(name='choose MB to change',\n", " button_type='default')\n", "change_selected_MB.param.watch(change_selected_MB_click, ['value'])\n", "\n", "\n", "def set_change_selected_MB_RadioButtonGroup_language():\n", " global change_selected_MB_options\n", "\n", " change_selected_MB_options = [\n", " compare_tab_text['Activate to change MB-Model'][language] + ' 1',\n", " compare_tab_text['Activate to change MB-Model'][language] + ' 2']\n", "\n", " change_selected_MB.options = change_selected_MB_options\n", "\n", "\n", "set_change_selected_MB_RadioButtonGroup_language()\n", "\n", "change_selected_MB.value = compare_tab_text['Activate to change MB-Model'][language] + ' 1'" ] }, { "cell_type": "code", "execution_count": null, "id": "7a0b676d", "metadata": {}, "outputs": [], "source": [ "def get_compare_tab():\n", " return pn.Column(pn.Tabs((tab_headings['Compare Climographs'][language],\n", " pn.Row(climographs_comp,\n", " sizing_mode='stretch_both')),\n", " (tab_headings['Compare MB Settings'][language],\n", " pn.Column(pn.layout.VSpacer(),\n", " compare_mb_table,\n", " pn.layout.VSpacer(),\n", " sizing_mode='stretch_both')),\n", " tabs_location='above'),\n", " change_selected_MB,\n", " pn.layout.Divider(margin=(0, 0, 0, 0)),\n", " pn.Row(compare_mb_figure,\n", " sizing_mode='stretch_both'),\n", " sizing_mode='stretch_both')" ] }, { "cell_type": "markdown", "id": "d9ac6ee3", "metadata": {}, "source": [ "## create figures tab for all " ] }, { "cell_type": "code", "execution_count": null, "id": "a7434059", "metadata": {}, "outputs": [], "source": [ "def change_figures_tab(event):\n", " global current_mb_i\n", " global active_tab\n", "\n", " if event.new == 0:\n", " current_mb_i = 0\n", " active_tab = 0\n", " change_selected_MB.value = change_selected_MB_options[0]\n", " set_climate_menu_with_selected_mb_model(0)\n", " set_mb_settings_menu_with_selected_mb_model(0)\n", " update_current_figures()\n", "\n", " elif event.new == 1:\n", " current_mb_i = 1\n", " active_tab = 1\n", " change_selected_MB.value = change_selected_MB_options[1]\n", " set_climate_menu_with_selected_mb_model(1)\n", " set_mb_settings_menu_with_selected_mb_model(1)\n", " update_current_figures()\n", "\n", " elif event.new == 2:\n", " active_tab = 2\n", " update_current_figures()\n", "\n", "\n", "figures_tab = pn.Tabs(('', []),\n", " dynamic=False)\n", "figures_tab.param.watch(change_figures_tab, ['active'])\n", "\n", "\n", "def set_figures_tab_tabs():\n", " figures_tab.clear()\n", "\n", " figures_tab.append((tab_headings['Mass Balance Model'][language] + ' 1',\n", " get_mb_tab(0)))\n", "\n", " figures_tab.append((tab_headings['Mass Balance Model'][language] + ' 2',\n", " get_mb_tab(1)))\n", "\n", " figures_tab.append((tab_headings['Compare Mass Balance Models'][language],\n", " get_compare_tab()))\n", "\n", "\n", "set_figures_tab_tabs()" ] }, { "cell_type": "markdown", "id": "de8a35e4", "metadata": {}, "source": [ "# Put App together" ] }, { "cell_type": "code", "execution_count": null, "id": "031db01a", "metadata": {}, "outputs": [], "source": [ "initial_run = False" ] }, { "cell_type": "code", "execution_count": null, "id": "2144f4d2", "metadata": {}, "outputs": [], "source": [ "app = pn.Template(template)\n", "\n", "app.add_panel('header', pn.Row(analytics,\n", " pn.layout.HSpacer(),\n", " language_selector,\n", " pn.Spacer(width=10),\n", " pn.pane.Markdown(object='

' + __version__ + '

',\n", " height=20,\n", " margin=(0, 0),\n", " align='end',),\n", " sizing_mode='stretch_width'))\n", "app.add_panel('menu_and_figures', pn.Row(pn.Column(tab_menu,\n", " all_logos,\n", " ),\n", " figures_tab,\n", " sizing_mode='stretch_both'))\n", "app.servable(title='Mass Balance Simulator ' + __version__)" ] }, { "cell_type": "markdown", "id": "d97d9c47", "metadata": {}, "source": [ "As long as you are running this notebook \"live\" (in Jupyter, not viewing a website or a static copy), the above notebook cell should contain the fully operational dashboard here in the notebook. You can also launch the dashboard at a separate port that shows up in a new browser tab, either by changing .servable() to .show() above and re-executing that cell, or by leaving the cell as it is and running bokeh serve --show simulator.ipynb." ] } ], "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.16" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "296.467px" }, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }