From dbf286238ad05e55f2ded5d455ec9690484295fc Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Wed, 9 Aug 2023 17:21:55 -0400 Subject: [PATCH 1/9] Indicator search prototype --- docs/_static/style.css | 25 ++++++ docs/conf.py | 36 +++++---- docs/indicators.rst | 167 +++++++++++------------------------------ 3 files changed, 89 insertions(+), 139 deletions(-) diff --git a/docs/_static/style.css b/docs/_static/style.css index 0f2390dae..e76a2e218 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -65,3 +65,28 @@ ul.simple li { #contents .toctree-wrapper:first-of-type ul { margin-bottom: 0; } + +#queryInput { + width: 100%; + padding: 10px; + margin: 5px; +} + +.indElem { + margin: 10px; + padding: 10px; + background-color: #ddd; + border-radius: 10px; +} + +.indName { + float: right; +} + +code > .indName { + background-color: #ccc; +} + +.indVarname { + border-radius: 10px; +} diff --git a/docs/conf.py b/docs/conf.py index 607c07d0b..418ea73eb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,20 +64,28 @@ def _indicator_table(module): # name: p.default if p.default != inspect._empty else f"<{name}>" # for (name, p) in ind._sig.parameters.items() # } - try: - table[ind_name] = ind.json() # args? - except KeyError as err: - warnings.warn( - f"{ind.identifier} could not be documented.({err})", UserWarning - ) - else: - table[ind_name]["doc"] = ind.__doc__ - if ind.compute.__module__.endswith("generic"): - table[ind_name][ - "function" - ] = f"xclim.indices.generic.{ind.compute.__name__}" - else: - table[ind_name]["function"] = f"xclim.indices.{ind.compute.__name__}" + table[ind_name] = { + "title": ind.title, + "vars": [ + param_name + for param_name, param in ind._all_parameters.items() + if param.kind < 2 and not param.injected + ], + } + # try: + # table[ind_name] = ind.json() # args? + # except KeyError as err: + # warnings.warn( + # f"{ind.identifier} could not be documented.({err})", UserWarning + # ) + # else: + # table[ind_name]["doc"] = ind.__doc__ + # if ind.compute.__module__.endswith("generic"): + # table[ind_name][ + # "function" + # ] = f"xclim.indices.generic.{ind.compute.__name__}" + # else: + # table[ind_name]["function"] = f"xclim.indices.{ind.compute.__name__}" return table diff --git a/docs/indicators.rst b/docs/indicators.rst index e6481f79f..038533da5 100644 --- a/docs/indicators.rst +++ b/docs/indicators.rst @@ -12,135 +12,52 @@ that conform as much as possible with the `CF-Convention`_. Indicators are split into realms (atmos, land, seaIce), according to the variables they operate on. See :ref:`notebooks/extendxclim:Defining new indicators` for instruction on how to create your own indicators. This page -lists all indicators with a summary description, click on the names to get to the complete docstring of each indicator. +allows a simple free text search of all indicators. Click on the python names to get to the complete docstring of each indicator. -atmos: Atmosphere -================= .. raw:: html -
- {% for indname, ind in indicators['atmos'].items() %} -
atmos.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
- - -land: Land surface -================== - -.. raw:: html - -
- {% for indname, ind in indicators['land'].items() %} -
land.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
- - -seaIce: Sea ice -=============== - -.. raw:: html - -
- {% for indname, ind in indicators['seaIce'].items() %} -
seaIce.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
- - -generic: Generic indicators -=========================== - -Indicators in this "realm" do not have units assigned to their inputs. They provide useful functions that might apply to many different types of data. They are most useful for building custom "indicator modules", see :ref:`indicators:Virtual submodules`. - -.. raw:: html - -
- {% for indname, ind in indicators['generic'].items() %} -
generic.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
+ + +
+ {% for realm, indlist in indicators.items() %} + {% for indname, ind in indlist.items() %} +
+ +
Uses: {% for var in ind.vars %}{{ var }} {% endfor %}
+
+ {% endfor %} + {% endfor %} +
+ + .. _CF-Convention: http://cfconventions.org/ - - -Virtual submodules -================== - -.. automodule:: xclim.indicators.cf - :noindex: - -.. raw:: html - -
- {% for indname, ind in indicators['cf'].items() %} -
cf.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
- -.. automodule:: xclim.indicators.icclim - :noindex: - -.. raw:: html - -
- {% for indname, ind in indicators['icclim'].items() %} -
icclim.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
- -.. automodule:: xclim.indicators.anuclim - :noindex: - -.. raw:: html - -
- {% for indname, ind in indicators['anuclim'].items() %} -
anuclim.{{ indname | safe}} : {{ ind.title }}
-
- {% if ind.identifier != indname %}Id: {{ ind.identifier }}
{% endif %} - Description: {{ ind.abstract }}
- Based on {{ ind.function }} 
- Produces: {% for var in ind['outputs'] %} {{ var['var_name'] }}: {{ var['long_name'] }} [{{ var['units'] }}] {% endfor %} -
- {% endfor %} -
From 32a5f6ef3ae1966c7e27a3dc08df97bd388a52e1 Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Wed, 27 Sep 2023 15:41:17 -0400 Subject: [PATCH 2/9] More powerful search - fix some indicator titles - upd chngs --- CHANGES.rst | 1 + docs/_static/indsearch.js | 59 +++++++++++++++++++ docs/_templates/layout.html | 13 +++++ docs/conf.py | 82 +++++++++------------------ docs/indicators.rst | 41 +------------- xclim/core/indicator.py | 1 + xclim/indicators/atmos/_conversion.py | 2 +- 7 files changed, 105 insertions(+), 94 deletions(-) create mode 100644 docs/_static/indsearch.js diff --git a/CHANGES.rst b/CHANGES.rst index 933c7377b..6e0c14627 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,7 @@ New features and enhancements * `xclim` now has a dedicated console command for prefetching testing data from `xclim-testdata` with branch options (e.g.: `$ xclim prefetch_testing_data --branch some_development_branch`). This command can be used to download the testing data to a local cache, which can then be used to run the testing suite without internet access or in "offline" mode. For more information, see the contributing documentation section for `Updating Testing Data`. (:issue:`1468`, :pull:`1473`). * The testing suite now offers a means of running tests in "offline" mode (using `pytest-socket `_ to block external connections). This requires a local copy of `xclim-testdata` to be present in the user's home cache directory and for certain `pytest` options and markers to be set when invoked. For more information, see the contributing documentation section for `Running Tests in Offline Mode`. (:issue:`1468`, :pull:`1473`). * The `SKIP_NOTEBOOKS` flag to speed up docs builds is now documented. See the contributing documentation section `Get Started!` for details. (:issue:`1470`, :pull:`1476`). +* Refactored the indicators page with the addition of a search bar. Bug fixes ^^^^^^^^^ diff --git a/docs/_static/indsearch.js b/docs/_static/indsearch.js new file mode 100644 index 000000000..d6a18ac79 --- /dev/null +++ b/docs/_static/indsearch.js @@ -0,0 +1,59 @@ +let indicators = []; +let miniSearch = new MiniSearch({ + fields: ['title', 'abstract', 'variables'], // fields to index for full-text search + storeFields: ['title', 'abstract', 'vars', 'realm', 'name'], // fields to return with search results + searchOptions: { + boost: {'title': 3, 'variables': 2}, + fuzzy: 0.1, + prefix: true, + }, + extractField: (doc, field) => { + if (field === 'variables') { + return Object.keys(doc['vars']).join(' '); + } + return MiniSearch.getDefault('extractField')(doc, field); + } +}); + +// populate list +fetch('indicators.json') + .then(data => data.json()) + .then(data => { + indicators = Object.entries(data).map(([k, v]) => { + return {id: k.toLowerCase(), ...v} + }); + miniSearch.addAll(indicators); + indFilter(); + }); + +function indTemplate(ind) { + const varlist = Object.entries(ind.vars).map((kv) => `${kv[0]}`).join(''); + return ` +
+ +
Uses: ${varlist}
+

${ind.abstract}

+
Yaml ID: ${ind.id}
+
+ `; +} + +function indFilter() { + const input = document.getElementById("queryInput").value; + let inds = []; + if (input === "") { + inds = indicators; + } else { + inds = miniSearch.search(input); + } + + const newTable = inds.map(indTemplate).join(''); + const tableElem = document.getElementById("indTable"); + tableElem.innerHTML = newTable; + return newTable; +} diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 4c57ba830..a56f391b3 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -1,2 +1,15 @@ {% extends "!layout.html" %} {% set css_files = css_files + ["_static/style.css"] %} + + +{% block scripts %} +{% if "indicators" in sourcename %} + + +{% endif %} +{{ super() }} +{% endblock %} diff --git a/docs/conf.py b/docs/conf.py index 159cb82b1..80694b907 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,10 +14,10 @@ from __future__ import annotations import datetime +import json import os import sys import warnings -from collections import OrderedDict import xarray from pybtex.plugin import register_plugin # noqa @@ -29,6 +29,7 @@ xarray.CFTimeIndex.__module__ = "xarray" import xclim # noqa +from xclim.core.indicator import registry # noqa # If extensions (or modules to document with autodoc) are in another # directory, add these directories to sys.path here. If the directory is @@ -38,59 +39,29 @@ sys.path.insert(0, os.path.abspath("..")) sys.path.insert(0, os.path.abspath(".")) - -def _get_indicators(module): - """For all modules or classes listed, return the children that are instances of registered Indicator classes. - - module : A xclim module. - """ - from xclim.core.indicator import registry - - out = {} - for key, val in module.__dict__.items(): - if hasattr(val, "_registry_id") and val._registry_id in registry: # noqa - out[key] = val - - return OrderedDict(sorted(out.items())) - - -def _indicator_table(module): - """Return a sequence of dicts storing metadata about all available indices in xclim.""" - inds = _get_indicators(getattr(xclim.indicators, module)) - table = {} - for ind_name, ind in inds.items(): - # Apply default values - # args = { - # name: p.default if p.default != inspect._empty else f"<{name}>" - # for (name, p) in ind._sig.parameters.items() - # } - table[ind_name] = { - "title": ind.title, - "vars": [ - param_name - for param_name, param in ind._all_parameters.items() - if param.kind < 2 and not param.injected - ], - } - # try: - # table[ind_name] = ind.json() # args? - # except KeyError as err: - # warnings.warn( - # f"{ind.identifier} could not be documented.({err})", UserWarning - # ) - # else: - # table[ind_name]["doc"] = ind.__doc__ - # if ind.compute.__module__.endswith("generic"): - # table[ind_name][ - # "function" - # ] = f"xclim.indices.generic.{ind.compute.__name__}" - # else: - # table[ind_name]["function"] = f"xclim.indices.{ind.compute.__name__}" - return table - - -modules = ("atmos", "generic", "land", "seaIce", "cf", "icclim", "anuclim") -indicators = {module: _indicator_table(module) for module in modules} +# Indicator data for populating the searchable indicators page +# Get all indicators and some information about them +indicators = {} +for module in ("atmos", "generic", "land", "seaIce", "cf", "icclim", "anuclim"): + for key, ind in getattr(xclim.indicators, module).__dict__.items(): + if hasattr(ind, "_registry_id") and ind._registry_id in registry: # noqa + indicators[ind._registry_id] = { + "realm": ind.realm, + "title": ind.title, + "name": key, + "abstract": ind.abstract, + "vars": { + param_name: f"{param.description} [{param.units}]" + for param_name, param in ind._all_parameters.items() + if param.kind < 2 and not param.injected + }, + } +# Sort by title +indicators = dict(sorted(indicators.items(), key=lambda kv: kv[1]["title"])) +# Dump to json. The json is added to the html output (html_extra_path) +# It is read by _static/indsearch.js to populate the table in indicators.rst +with open("indicators.json", "w") as f: + json.dump(indicators, f) # -- General configuration --------------------------------------------- @@ -241,6 +212,7 @@ class XCStyle(AlphaStyle): """ nbsphinx_timeout = 300 nbsphinx_allow_errors = False +# nbsphinx_requirejs_path = "" # To make MiniSearch work in the indicators page # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -302,7 +274,7 @@ class XCStyle(AlphaStyle): html_theme = "sphinx_rtd_theme" -html_context = {"indicators": indicators} +html_extra_path = ["indicators.json"] # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the diff --git a/docs/indicators.rst b/docs/indicators.rst index 038533da5..eda659af7 100644 --- a/docs/indicators.rst +++ b/docs/indicators.rst @@ -14,50 +14,15 @@ Indicators are split into realms (atmos, land, seaIce), according to the variabl See :ref:`notebooks/extendxclim:Defining new indicators` for instruction on how to create your own indicators. This page allows a simple free text search of all indicators. Click on the python names to get to the complete docstring of each indicator. - .. raw:: html
- {% for realm, indlist in indicators.items() %} - {% for indname, ind in indlist.items() %} -
- -
Uses: {% for var in ind.vars %}{{ var }} {% endfor %}
-
- {% endfor %} - {% endfor %}
- - +.. + Filling of the table and search is done by scripts in _static/indsearch.js which are added through _templates/layout.html + the data comes from indicators.json which is created by conf.py. .. _CF-Convention: http://cfconventions.org/ diff --git a/xclim/core/indicator.py b/xclim/core/indicator.py index eba93350f..4aeb7bb2a 100644 --- a/xclim/core/indicator.py +++ b/xclim/core/indicator.py @@ -1140,6 +1140,7 @@ def _translate(cf_attrs, names, var_id=None): ) return attrs + @classmethod def json(self, args=None): """Return a serializable dictionary representation of the class. diff --git a/xclim/indicators/atmos/_conversion.py b/xclim/indicators/atmos/_conversion.py index d1771e88f..ee319c42d 100644 --- a/xclim/indicators/atmos/_conversion.py +++ b/xclim/indicators/atmos/_conversion.py @@ -344,7 +344,7 @@ def cfcheck(self, **das): corn_heat_units = Converter( - title=" Corn heat units", + title="Corn heat units", identifier="corn_heat_units", units="", long_name="Corn heat units (Tmin > {thresh_tasmin} and Tmax > {thresh_tasmax})", From c0f48ea9905c3e076529816ea013ed540b497045 Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Wed, 27 Sep 2023 15:50:45 -0400 Subject: [PATCH 3/9] Fix title --- xclim/indicators/atmos/_precip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xclim/indicators/atmos/_precip.py b/xclim/indicators/atmos/_precip.py index 1d0e98ac1..988a09476 100644 --- a/xclim/indicators/atmos/_precip.py +++ b/xclim/indicators/atmos/_precip.py @@ -563,7 +563,7 @@ class HrPrecip(Hourly): # FIXME: Are fraction_over_precip_thresh and fraction_over_precip_doy_thresh the same thing? # FIXME: Clarity needed in both French and English metadata fields fraction_over_precip_doy_thresh = PrecipWithIndexing( - title="", + title="Fraction of precipitation due to wet days with daily precipitation over a given daily percentile.", identifier="fraction_over_precip_doy_thresh", long_name="Fraction of precipitation due to days with daily precipitation above {pr_per_thresh}th daily percentile", description="{freq} fraction of total precipitation due to days with precipitation above {pr_per_thresh}th daily " From bee5b4556bf5a7315afc7028ccb2eb24e7fb96f1 Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Thu, 28 Sep 2023 12:05:28 -0400 Subject: [PATCH 4/9] Remove weakly document CF indicators - fix internal name --- docs/_static/indsearch.js | 4 ++-- docs/conf.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/_static/indsearch.js b/docs/_static/indsearch.js index d6a18ac79..9d1846a27 100644 --- a/docs/_static/indsearch.js +++ b/docs/_static/indsearch.js @@ -32,8 +32,8 @@ function indTemplate(ind) {
Uses: ${varlist}
diff --git a/docs/conf.py b/docs/conf.py index 80694b907..35b112714 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,13 +42,15 @@ # Indicator data for populating the searchable indicators page # Get all indicators and some information about them indicators = {} -for module in ("atmos", "generic", "land", "seaIce", "cf", "icclim", "anuclim"): +# FIXME: Include cf module when its indicators documentation is improved. +for module in ("atmos", "generic", "land", "seaIce", "icclim", "anuclim"): for key, ind in getattr(xclim.indicators, module).__dict__.items(): if hasattr(ind, "_registry_id") and ind._registry_id in registry: # noqa indicators[ind._registry_id] = { "realm": ind.realm, "title": ind.title, "name": key, + "module": module, "abstract": ind.abstract, "vars": { param_name: f"{param.description} [{param.units}]" From 5b50f12f29575abc9cad9d5bc48e0dcc6366531a Mon Sep 17 00:00:00 2001 From: David Huard Date: Thu, 28 Sep 2023 20:14:56 -0400 Subject: [PATCH 5/9] Added keyword search. Show keywords if there is at least one. --- docs/_static/indsearch.js | 18 ++++++++++++++++-- docs/_static/style.css | 8 ++++++++ docs/_templates/layout.html | 1 + docs/conf.py | 1 + xclim/indicators/atmos/_conversion.py | 1 + 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/_static/indsearch.js b/docs/_static/indsearch.js index d6a18ac79..02044a61f 100644 --- a/docs/_static/indsearch.js +++ b/docs/_static/indsearch.js @@ -1,7 +1,7 @@ let indicators = []; let miniSearch = new MiniSearch({ - fields: ['title', 'abstract', 'variables'], // fields to index for full-text search - storeFields: ['title', 'abstract', 'vars', 'realm', 'name'], // fields to return with search results + fields: ['title', 'abstract', 'variables', 'keywords'], // fields to index for full-text search + storeFields: ['title', 'abstract', 'vars', 'realm', 'name', 'keywords'], // fields to return with search results searchOptions: { boost: {'title': 3, 'variables': 2}, fuzzy: 0.1, @@ -26,6 +26,19 @@ fetch('indicators.json') indFilter(); }); + +function makeKeywordLabel(ind) { + /* Print list of keywords only if there is at least one. */ + if (ind.keywords[0].length > 0) { + const keywords = ind.keywords.map(v => `${v.trim()}`).join(''); + return `
Keywords: ${keywords}
`; + } + else { + return ""; + } +} + + function indTemplate(ind) { const varlist = Object.entries(ind.vars).map((kv) => `${kv[0]}`).join(''); return ` @@ -38,6 +51,7 @@ function indTemplate(ind) {
Uses: ${varlist}

${ind.abstract}

+ ${makeKeywordLabel(ind)}
Yaml ID: ${ind.id}
`; diff --git a/docs/_static/style.css b/docs/_static/style.css index e76a2e218..5babe9e93 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -90,3 +90,11 @@ code > .indName { .indVarname { border-radius: 10px; } + +/* Rounded corners for keyword labels: */ +.keywordlabel { + border-radius: 10px; + padding: 5px; + margin: 5px; + background-color: #ddd; +} diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index a56f391b3..f00ef0ad7 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -6,6 +6,7 @@ loaded before all other scripts. nbsphinx adds a line to load require.js which breaks MiniSearch if loaded first. --> + {% block scripts %} {% if "indicators" in sourcename %} diff --git a/docs/conf.py b/docs/conf.py index 80694b907..bc1d8c6e7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,6 +55,7 @@ for param_name, param in ind._all_parameters.items() if param.kind < 2 and not param.injected }, + "keywords": ind.keywords.split(","), } # Sort by title indicators = dict(sorted(indicators.items(), key=lambda kv: kv[1]["title"])) diff --git a/xclim/indicators/atmos/_conversion.py b/xclim/indicators/atmos/_conversion.py index ee319c42d..03e5e6d7f 100644 --- a/xclim/indicators/atmos/_conversion.py +++ b/xclim/indicators/atmos/_conversion.py @@ -54,6 +54,7 @@ def cfcheck(self, **das): long_name="Humidex index", description="Humidex index describing the temperature felt by the average person in response to relative humidity.", cell_methods="", + keywords="heatwave", abstract="The humidex describes the temperature felt by a person when relative humidity is taken into account. " "It can be interpreted as the equivalent temperature felt when the air is dry.", compute=indices.humidex, From da40c5cab61dd3e622a5153874c42739054565d5 Mon Sep 17 00:00:00 2001 From: David Huard Date: Fri, 29 Sep 2023 10:34:47 -0400 Subject: [PATCH 6/9] Add tooltip for variables --- docs/_static/indsearch.js | 26 ++++++++++++++++++++++++-- docs/conf.py | 15 ++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/_static/indsearch.js b/docs/_static/indsearch.js index e558a65ef..5c1451e69 100644 --- a/docs/_static/indsearch.js +++ b/docs/_static/indsearch.js @@ -1,4 +1,7 @@ +/* Array of indicator objects */ let indicators = []; + +/* MiniSearch object defining search mechanism */ let miniSearch = new MiniSearch({ fields: ['title', 'abstract', 'variables', 'keywords'], // fields to index for full-text search storeFields: ['title', 'abstract', 'vars', 'realm', 'name', 'keywords'], // fields to return with search results @@ -15,7 +18,7 @@ let miniSearch = new MiniSearch({ } }); -// populate list +// Populate search object with complete list of indicators fetch('indicators.json') .then(data => data.json()) .then(data => { @@ -27,6 +30,16 @@ fetch('indicators.json') }); +// Populate list of variables +//function getVariables() { +// fetch('variables.json') +// .then((res) => { +// return res.json(); +// }) +//} +//const variables = getVariables(); + + function makeKeywordLabel(ind) { /* Print list of keywords only if there is at least one. */ if (ind.keywords[0].length > 0) { @@ -39,8 +52,17 @@ function makeKeywordLabel(ind) { } +function makeVariableList(ind) { + /* Print list of variables and include mouse-hover tooltip with variable description. */ + return Object.entries(ind.vars).map((kv) => { + const tooltip = ``; + return tooltip + }).join(''); +} + function indTemplate(ind) { - const varlist = Object.entries(ind.vars).map((kv) => `${kv[0]}`).join(''); + // const varlist = Object.entries(ind.vars).map((kv) => `${kv[0]}`).join(''); + const varlist = makeVariableList(ind); return `
diff --git a/docs/conf.py b/docs/conf.py index d77b75379..22ef76a68 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,6 +20,7 @@ import warnings import xarray +import yaml from pybtex.plugin import register_plugin # noqa from pybtex.style.formatting.alpha import Style as AlphaStyle # noqa from pybtex.style.labels import BaseLabelStyle # noqa @@ -53,7 +54,7 @@ "module": module, "abstract": ind.abstract, "vars": { - param_name: f"{param.description} [{param.units}]" + param_name: f"{param.description}" for param_name, param in ind._all_parameters.items() if param.kind < 2 and not param.injected }, @@ -61,11 +62,19 @@ } # Sort by title indicators = dict(sorted(indicators.items(), key=lambda kv: kv[1]["title"])) -# Dump to json. The json is added to the html output (html_extra_path) + +# Dump indicators to json. The json is added to the html output (html_extra_path) # It is read by _static/indsearch.js to populate the table in indicators.rst with open("indicators.json", "w") as f: json.dump(indicators, f) + +# Dump variables information +with open("variables.json", "w") as fout: + with open("../xclim/data/variables.yml") as fin: + data = yaml.safe_load(fin) + json.dump(data, fout) + # -- General configuration --------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. @@ -277,7 +286,7 @@ class XCStyle(AlphaStyle): html_theme = "sphinx_rtd_theme" -html_extra_path = ["indicators.json"] +html_extra_path = ["indicators.json", "variables.json"] # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the From 72f6ee2dcdbee7b3a67386b4ea81e52ec2ce8d98 Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Fri, 29 Sep 2023 11:03:57 -0400 Subject: [PATCH 7/9] Update indicators.rst --- docs/indicators.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/indicators.rst b/docs/indicators.rst index eda659af7..be46e0007 100644 --- a/docs/indicators.rst +++ b/docs/indicators.rst @@ -16,7 +16,7 @@ allows a simple free text search of all indicators. Click on the python names to .. raw:: html - +
From ae86295a1313a809ca452495255037d9998fc90d Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Fri, 29 Sep 2023 11:25:32 -0400 Subject: [PATCH 8/9] Keep module in available fields --- docs/_static/indsearch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_static/indsearch.js b/docs/_static/indsearch.js index 5c1451e69..cbaacbac5 100644 --- a/docs/_static/indsearch.js +++ b/docs/_static/indsearch.js @@ -4,7 +4,7 @@ let indicators = []; /* MiniSearch object defining search mechanism */ let miniSearch = new MiniSearch({ fields: ['title', 'abstract', 'variables', 'keywords'], // fields to index for full-text search - storeFields: ['title', 'abstract', 'vars', 'realm', 'name', 'keywords'], // fields to return with search results + storeFields: ['title', 'abstract', 'vars', 'realm', 'module', 'name', 'keywords'], // fields to return with search results searchOptions: { boost: {'title': 3, 'variables': 2}, fuzzy: 0.1, From 049a5db2041df6c95dc4589060ab7802ef9d7f70 Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Fri, 29 Sep 2023 14:39:38 -0400 Subject: [PATCH 9/9] Adjust make docs for server requirement --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a691fd060..066a85af5 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ define BROWSER_PYSCRIPT import os, webbrowser, sys from urllib.request import pathname2url -webbrowser.open(f"file://{pathname2url(os.path.abspath(sys.argv[1]))}") +webbrowser.open(sys.argv[1]) endef export BROWSER_PYSCRIPT @@ -93,7 +93,11 @@ linkcheck: autodoc-custom-index ## run checks over all external links found thro docs: autodoc-custom-index ## generate Sphinx HTML documentation, including API docs, but without indexes for for indices and indicators $(MAKE) -C docs html ifndef READTHEDOCS - $(BROWSER) docs/_build/html/index.html + ## Start http server and show in browser. + ## We want to have the cli command run in the foreground, so it's easy to kill. + ## And we wait 2 sec for the server to start before opening the browser. + \{ sleep 2; $(BROWSER) http://localhost:54345 \} & + python -m http.server 54345 --directory docs/_build/html/ endif servedocs: docs ## compile the docs watching for changes